Functions: Multiple Return Values

This is a technique that you’d fall back on, when you are really looking to get things more speedy. Arguably its not the prettiest coding technique, and fairly esoteric and I am not advocating to use it as the main interfacing technique. But it is useful, sometimes.

local is not like your other programming language local variables

In bash a local variable starts a scope at runtime for the function it “lives” in and every function getting called from this function. This is in stark contrast to compiled languages, where a local variable is only visible inside the function itself.

Here is an experiment that shows this:

foo()
{
   printf "%s\n" "${_bar}"
}


call_foo()
{
   local _bar

   _bar="hello"
   foo
}

call_foo
printf "_bar is \"%s\"\n" "${_bar}"

_bar is a local variable, not a global variable. The scope is limited to the functions runtime scope, not what would be the compile scope. So the result will be:

hello
_bar is ""

As a more compiler language oriented guy, I had to get over the hang-up, what a local variable is. It’s different the way a shell does it. There is no point in fighting the tool, instead make good use of it.

Multiple return values

I would never, ever (well just very rarely) use this feature to pass values into another function. There are named parameters for that. But for getting multiple return values out of a function, this can come in handy.

First of all its important to distinguish such multiple return values from regular variables. I prefix them with an underscore _. Second a function should declare, what return values it will set. This is done with a comment in front of the function detailing the local declarations to be set by the caller.

Taking it all together this is how a multiple value function looks like in the called function:

#
# This function sets values of variables that should be declared
# in the caller!
#
#   local _branch
#   local _address
#
m_set_branch_address()
{
   local mode="$1"

   case "${mode}" in
      whatever)
         _branch="important"
         _address=""
      ;;

      *)
         _branch=""
         _address="unimportant"
      ;;
   esac
}

and this is how the calling function does it:

print_branch_address_for_mode()
{
   local mode="$1"

   local _branch
   local _address

   m_set_branch_address "${mode}"

   printf "address : %s\n" "${_address}"
   printf "branch  : %s\n" "${_branch}"
}

Again, it’s not beautiful, but it’s not too bad.

Note

I am toying with the idea of prefixing my multiple return value functions with m_ but I haven’t done it yet.