{"id":727,"date":"2025-08-13T09:00:00","date_gmt":"2025-08-12T23:00:00","guid":{"rendered":"https:\/\/jm.armijo.au\/dev\/?p=727"},"modified":"2025-08-12T22:39:06","modified_gmt":"2025-08-12T12:39:06","slug":"output-variables","status":"publish","type":"post","link":"https:\/\/jm.armijo.au\/dev\/blog\/2025\/08\/13\/output-variables\/","title":{"rendered":"Why Output Variables Are (Usually) a Bad Idea"},"content":{"rendered":"\n<p>One of the many things I&#8217;ve learnt from the Clean Code book is about the evils of output variables.<\/p>\n\n\n\n<p>Functions can take arguments and can return values. An output variable is one of those arguments that the function uses to give a result by changing its value instead of, or in addition to, the function\u2019s normal return value. Although this sounds really handy, it comes with some issues.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Devil is in the Details<\/h3>\n\n\n\n<p>As mentioned before, output variables may seem innocent, and even good, but there are a number of reasons why they should be avoided. Here&#8217;s why.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Hide details that should be visible<\/h5>\n\n\n\n<p>In some of my previous articles I&#8217;ve mentioned something that is not always recognised: software developers spend most of our time reading rather than writing code.<\/p>\n\n\n\n<p>When we use output variables, we are hiding information from whoever needs to read our code. Following the code becomes harder, as we force people to see how functions are implemented in order to understand the code (or check the documentation if this is a library) to find out that we&#8217;re using the argument to return data. And, on top of that, we have to remember all that while we read the rest of the code.<\/p>\n\n\n\n<p>Attempts at addressing this issue by using clear variable names (for example, <code>outValue<\/code>) are welcome, but are not really a solution. When reading the code, we may easily miss this if we&#8217;re not expecting an output variable, even if the name is clear. And it&#8217;s not unheard of to have changed a function and forgotten to change some variable names that are no longer used as output variables.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Can introduce bugs that are hard to detect<\/h5>\n\n\n\n<p>Another problem is when two or more variables point to the same object. And, in fact, I find that this is one of the worst types of bugs to have to deal with, as the code seems perfectly fine even though it&#8217;s not. Changing a value this way can lead to unexpected results. Take this code, for example:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: ruby; gutter: false; title: ; notranslate\" title=\"\">\ndef apply_discount(out_cart)\n  out_cart&#x5B;:total] *= 0.9   # changes the argument\n  out_cart&#x5B;:total]          # also returns a value\nend\n\ndef apply_tax(out_cart)\n  out_cart&#x5B;:total] *= 1.1   # changes the argument\n  out_cart&#x5B;:total]          # also returns a value\nend\n\ncart = { total: 100 }\n\n# returns 110, cart&#x5B;:total] now 110\ntotal_after_tax = apply_tax(cart)\n\n# returns 99, cart&#x5B;:total] now 99\ntotal_after_discount = apply_discount(cart)\n<\/pre><\/div>\n\n\n<p>Here, both functions do their job correctly, but the interaction produces an invalid value. Taxes should be applied to the original price, before the discount, and the discount should be applied to the original price, without taxes. However, these functions update the value that the other uses to make their calculation, so the final result is incorrect.<\/p>\n\n\n\n<p>If you are still wondering what the customer should be really charged, I&#8217;ll show the answer at the end of this article \ud83d\ude42<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Make Testing Harder<\/h5>\n\n\n\n<p>Testing a function that returns a value is simple: we call it, compare the return value to what we expect, and voil\u00e0:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: ruby; gutter: false; title: ; notranslate\" title=\"\">\ndef double(x)\n  x * 2\nend\n\nputs double(4) == 8  # test in one line\n<\/pre><\/div>\n\n\n<p>To be fair, tests tend to be more complex in real life. But that said, testing a function&#8217;s output variable response adds even more work, as we need to set up the argument, then call the function, to finally check if it changed the way we wanted:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: ruby; gutter: false; title: ; notranslate\" title=\"\">\ndef double!(out_var)\n  out_var&#x5B;:value] *= 2\nend\n\nvar = { value: 4 }\ndouble!(var)\nputs var&#x5B;:value] == 8  # need to check the updated state\n<\/pre><\/div>\n\n\n<p>That\u2019s more steps and more chances to mess up, and it becomes worse if the function also returns data in the standard way.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Prevents Chain Calls<\/h5>\n\n\n\n<p>Another issue is that functions with output variables don\u2019t work well together. Consider the functions in the example below. If these functions used output variables, we\u2019d have to break the code into multiple steps and keep track of extra variables:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: ruby; gutter: false; title: ; notranslate\" title=\"\">\ndata = nil\nread_data(data) # sets 'data'\n\ncleaned = nil\nclean(cleaned, data) # sets 'cleaned' from data\n\nresult = nil\ntransform(result, cleaned) # sets 'result' from cleaned\n<\/pre><\/div>\n\n\n<p>Here, we have several lines and temporary variables to be aware of when working with this code. We also have to remember which arguments are being read, which are being written, and in what order.<\/p>\n\n\n\n<p>However, if we had a bunch of functions that just return values, we could chain them easily:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: ruby; gutter: false; title: ; notranslate\" title=\"\">\nresult = transform(clean(read_data))\n<\/pre><\/div>\n\n\n<p>Here, each function returns its result, and we simply pass it to the next function. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Dancing With the Devil<\/h3>\n\n\n\n<p>Even though output variables can cause problems, they can be very useful sometimes, for example, when performance is critical, and creating new objects or passing pointers is the difference between success and failure.<\/p>\n\n\n\n<p>Many programming languages use output variables in their built-in functions\/libraries, like encoding and I\/O operations. This is not by chance, but to allow building performance-critical applications if a system requires it. Sometimes, these built-in features are so idiomatic that we could even argue that using them is not particularly problematic.<\/p>\n\n\n\n<p>A word of caution though: I&#8217;ve witnessed over and over how most developers try to prematurely optimise their code at the expense of readability and maintainability, without even knowing if that was even needed.<\/p>\n\n\n\n<p>Please, if you &#8220;think&#8221; your code needs to be optimised, do yourself a favour and make sure before making any changes. I recommend reading this other article for further thoughts on this topic:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-practical-software-development wp-block-embed-practical-software-development\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"40MuoZfGpV\"><a href=\"https:\/\/jm.armijo.au\/dev\/blog\/2025\/04\/16\/premature-code-optimisation\/\">Premature Code Optimisation<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;Premature Code Optimisation&#8221; &#8212; Practical Software Development\" src=\"https:\/\/jm.armijo.au\/dev\/blog\/2025\/04\/16\/premature-code-optimisation\/embed\/#?secret=ew2Y10pe3D#?secret=40MuoZfGpV\" data-secret=\"40MuoZfGpV\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Beating the Devil<\/h3>\n\n\n\n<p>When we use standard returns instead of output variables, we make our functions easier to read, easier to chain, and easier to test. And if we need to return more than one thing, many languages let us return multiple values or a small object with named fields.<\/p>\n\n\n\n<p>I would suggest wrapping code that uses output variables whenever possible with equivalent code that does not, or at least reducing the places where output variables are used. That way, only a small part of the code will deal with output variables, protecting the rest of the system from the risks I mentioned before. And if we really have to use output variables, at least let&#8217;s make it obvious in our code.<\/p>\n\n\n\n<p>Finally, and as promised, I&#8217;ll share the expected price to pay for the customer after applying the discount and the taxes. In that example, we charged ten dollars in taxes (ten per cent of one hundred dollars), and we deducted ten per cent from the original price, which reduced the price from one hundred to ninety dollars. So, ninety dollars (the price with discount) plus ten dollars (taxes) equals one hundred dollars, which is the price the customer should really be charged.<\/p>\n\n\n\n<p>Cheers,<br>Jos\u00e9 Miguel<\/p>\n\n\n\n<p><em>Share if you find this content useful, and Follow me on&nbsp;<a href=\"http:\/\/www.linkedin.com\/comm\/mynetwork\/discovery-see-all?usecase=PEOPLE_FOLLOWS&amp;followMember=jmarmijo\">LinkedIn<\/a>&nbsp;to be notified of new articles.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the many things I&#8217;ve learnt from the Clean Code book is about the evils of output variables. Functions can take arguments and can return values. An output variable is one of those arguments that the function uses to give a result by changing its value instead of, or in addition to, the function\u2019s [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":741,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-727","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts\/727","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/comments?post=727"}],"version-history":[{"count":21,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts\/727\/revisions"}],"predecessor-version":[{"id":749,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts\/727\/revisions\/749"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/media\/741"}],"wp:attachment":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/media?parent=727"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/categories?post=727"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/tags?post=727"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}