Subroutine-like functions in Julia

I’m trying to convert some Fortran code to Julia (I know it’s possible to call Fortran from Julia but I prefer not to do that for the time being).
What’s the best way to write a function in Julia that is similar to a Fortran subroutine? It seems like all functions in Julia need to return something. Is that correct?

Not really. It will work like you expect from fortran if you do:

function foo(a, b, out)
    out[1] = sin(a) * cos(b)
    return
end

(note as far as I understand out needs to be a mutable type, so an array for example). You can see that the function returning nothing and you get the subroutine like behavior of changing one of the arguments.

2 Likes

Note that there is a convention in Julia that functions which mutate one of their array arguments like this have names ending in ! so it would be more idiomatic to call this function foo!.

7 Likes

Julia is smart enough to note care about the return value, but if you want to explicitly set it to return nothing, you can use the implicit returns (Julia returns the answer to the last expression) to give back nothing.

function foo!(A)
  A[1] = 2
  nothing
end

As @StefanKarpinski says, as a convention you should use ! in a mutating function.

1 Like

Or also explicitly:

return nothing

which is my preferred style.

4 Likes

Thanks a lot for all the replies! I’ll keep in mind to use ! for the mutating functions.

Or just return with no return expression (nothing is the default return value).

1 Like

Wouldn’t it be nice if Julia had a subroutine keyword so that

subroutine foo!(A)
  A[1] = 2
end

would be syntactic sugar for

function foo!(A)::Void
  A[1] = 2
  nothing
end

(A @subroutine macro wouldn’t be too hard to write, I guess.)

Why do we need that? What’s wrong with just ignoring the return value?

2 Likes

Do also note, that it’s convention to have the mutated argument in first position.
With this in mind @gabrielgellner’s code would become

function foo!(out, a, b)
    out[1] = sin(a) * cos(b)
    return
end

I still prefer to return something. It is easy to ignore - just don’t assign the output to anything. On the other hand, it’s easier to test and debug functions with return values.

2 Likes

In addition to the great specific answers you got, you should consider porting code to a more idiomatic form in Julia. The performance tips section of the manual would be a good starting point, especially with the following in mind:

Preallocation has other advantages, for example by allowing the caller to control the “output” type from an algorithm. In the example above, we could have passed a SubArray rather than an Array, had we so desired.
Taken to its extreme, pre-allocation can make your code uglier, so performance measurements and some judgment may be required. However, for “vectorized” (element-wise) functions, the convenient syntax x .= f.(y) can be used for in-place operations with fused loops and no temporary arrays (see the dot syntax for vectorizing functions).

If all programmers always read and write good documentation, then, of course, ignoring the return value is equivalent to not returning any value.

However, if some users start relying on the “undocumented feature” that foo! returns 2, then a change that the developer considers “minor” might break their code. (This is particularly likely to happen if foo! has no documentation at all.)

So this would be purely syntactic sugar. A way of saying “please don’t use the return value of this function” without actually having to put those words into the docstring or adding an empty return statement.

I think it is very rare for this to actually be the case. For example, A would be a much better return value than nothing.

Also if you are going to change how a function is written, I don’t see why you can’t just document it. Also, just write return is shorter and much easier to understand.

1 Like

I am not sure I entirely understand the issue (which can be common in these discussions!), but wouldn’t the user have to see the code to know it is a subroutine, and therefore the “contract” of not using the return type is meant, given no documentation? Or do you mean the language would have something different than the generic methods currently? If so I am not sure that seeing a naked return at the end would be any more or less “documented” than having the method defined with a “subroutine” keyword, both require inspection of the source code.

Something I know I had to deal with in Julia coming from Fortran is that how methods work (multiple dispatch etc) is very different, and just because something can be made to look similar doesn’t always mean it is good to do the emulation :slight_smile:

What I meant was for subroutines to be lowered into functions that return nothing, exactly equivalent to writing the function with a ::Void return type assertion and an empty return at the end. If the user doesn’t read the documentation or the source code, he can still find out what the subroutine/function returns simply by trying it.

But I agree with @yuyichao that it is fairly rare for a function not to have anything at all that is reasonable to return. So it’s probably not worth it to introduce an extra keyword for this special case.