# Nested functions pros and cons

**URL:** https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417
**Category:** General Usage
**Created:** [January 9, 2019, 10:31am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417 "2019-01-09T10:31:21Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 9, 2019, 10:31am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/1 "2019-01-09T10:31:21Z")

</div>

I’ve learned that nested functions are useful in Matlab to avoid passing tons of arguments to external functions when optimizing/fitting some data.

Is this still true in Julia? Since lambda functions are very cheap, is there any point in nesting a function? What if I’m nesting 2 or 3 layers deep? Then repeatedly calling a top nested function will re-“build” all the deeper nested functions many times over…

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [January 9, 2019, 10:51am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/2 "2019-01-09T10:51:51Z")

</div>

> [@yakir12](#):
>
> Then repeatedly calling a top nested function will re-“build” all the deeper nested functions many times over…

This is not how it works. The function is “pulled out” and defined when the code is getting lowered.

Some code examples of what you mean would help clarify your point. To me, it just seems like you are talking about a closure which indeed is a way to avoid passing arguments to functions getting passed into other routines, like optimization algorithms.

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 9, 2019, 12:22pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/3 "2019-01-09T12:22:23Z")

</div>

I think you got me right. I was about to create a contrived but clear example, but then I figured I might as well just put the actual code here, and test it!

## Code

Nested:

```julia-auto
function nested(retina, distance, aperture, morphz)
    layers, rc, ous, nodalz, focallengths = createobj(morphz)
    r = Ray()
    function θ2signal(θ)
        l = Light(distance, aperture, rc, θ, nodalz)
        function getsignal(b)
            ous[retina].medium.signal.photoreceptor = 0.0
            try
                l(r, b[1], b[2])
                raytrace!(r, ous)
            catch ex
                ex isa RayTraceEllipsoids.DeadRay || throw(ex)
            end
            ous[retina].medium.signal.photoreceptor
        end
        s, _ = hcubature(getsignal, [0, 0], [1, 0.5], initdiv=10, maxevals=10^4)
        s
    end
    s0 = θ2signal(0)
    fun(θ) = (θ2signal(θ) - s0/2)^2
    res = optimize(fun, 1e-4, 0.45)
    Optim.minimizer(res)
end

```

Not Nested:

```julia-auto
function getsignal(b, ous, retina, l, r)
    ous[retina].medium.signal.photoreceptor = 0.0
    try
        l(r, b[1], b[2])
        raytrace!(r, ous)
    catch ex
        ex isa RayTraceEllipsoids.DeadRay || throw(ex)
    end
    ous[retina].medium.signal.photoreceptor
end
function θ2signal(θ, distance, aperture, rc, nodalz, ous, retina, r)
    l = Light(distance, aperture, rc, θ, nodalz)
    s, _ = hcubature(b -> getsignal(b, ous, retina, l, r), [0, 0], [1, 0.5], initdiv=10, maxevals=10^4)
    s
end
function notnested(retina, distance, aperture, morphz)
    layers, rc, ous, nodalz, focallengths = createobj(morphz)
    r = Ray()
    s0 = θ2signal(0, distance, aperture, rc, nodalz, ous, retina, r)
    res = optimize(θ -> θ2signal(θ, distance, aperture, rc, nodalz, ous, retina, r), 1e-4, 0.45)
    Optim.minimizer(res)
end

```

## Benchmarks

Nested:

```julia-auto
BenchmarkTools.Trial: 
  memory estimate: 105.94 MiB
  allocs estimate: 4444955
  --------------
  minimum time: 2.583 s (0.59% GC)
  median time: 2.584 s (0.54% GC)
  mean time: 2.584 s (0.54% GC)
  maximum time: 2.584 s (0.48% GC)
  --------------
  samples: 2
  evals/sample: 1

```

Not nested:

```julia-auto
BenchmarkTools.Trial: 
  memory estimate: 16.72 MiB
  allocs estimate: 752272
  --------------
  minimum time: 2.836 s (0.10% GC)
  median time: 2.837 s (0.05% GC)
  mean time: 2.837 s (0.05% GC)
  maximum time: 2.839 s (0.00% GC)
  --------------
  samples: 2
  evals/sample: 1

```

## Conclusions

So, not nested is ~10% slower but takes ~5 times less memory.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [January 9, 2019, 1:03pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/4 "2019-01-09T13:03:20Z")

</div>

Note that you’re only actually running two samples in your benchmark, so a 10% difference in timing may not be all that statistically significant.

In general there should be no performance penalty for nested functions (which behave exactly like any other anonymous function), but you do run the risk of running into [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276) The way to check for this is to run `@code_warntype`. Have you tried that, and does the result look OK?

Also, I’m pretty sure `try...catch` blocks are pretty slow in Julia, particularly if the `catch` path is taken. Are you sure that’s not slowing down your code?

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 9, 2019, 1:05pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/5 "2019-01-09T13:05:54Z")

</div>

> [@rdeits](#):
>
> run `@code_warntype` . Have you tried that, and does the result look OK?

I have not. I’ll look into that.

> [@rdeits](#):
>
> Also, I’m pretty sure `try...catch` blocks are pretty slow in Julia, particularly if the `catch` path is taken. Are you sure that’s not slowing down your code?

Waaaat…? Didn’t know that. I’ve been using it as a means to terminate a iteration that is fruitless. Since the mechanics of such an event is nested well down the code I can’t elicit a `break` or some such. But I can most certainly propagate some failure in another way. Hmm!!!

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [January 9, 2019, 1:09pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/6 "2019-01-09T13:09:15Z")

</div>

> [@yakir12](#):
>
> Waaaat…? Didn’t know that. I’ve been using it as a means to terminate a iteration that is fruitless.

Using try catch for control flow is not great. It has performance implications and makes the code pretty confusing to read. Using a return value from `raytrace!` might work just as well here.

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 9, 2019, 1:48pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/7 "2019-01-09T13:48:40Z")

</div>

> [@rdeits](#):
>
> you do run the risk of running into [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276)

Wow, I did run into that. Thanks for the flag. OK, not nested it is.

---

<div class="post-metadata">

### Author: ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)
#### Post date: [January 9, 2019, 2:35pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/8 "2019-01-09T14:35:00Z")

</div>

Previously, I used a nested function definition also, but later I realized that I can get much better performance if I define the other function outside the main function, and use parametric typed to pass the extra information instead, so that lowered code is simplified for pre-compilation. This would probably be faster.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [January 9, 2019, 2:40pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/9 "2019-01-09T14:40:23Z")

</div>

Don’t take this to mean “closures are slow” or that you shouldn’t use them if they suit your particular problem. It’s nearly always possible (if somewhat annoying) to avoid issue 15276 using a `let` block, as long as your closure (i.e. your nested function) doesn’t need to affect any bindings in the parent scope. But if you are running into that issue and you don’t need a closure, then yes, defining your methods externally is another easy way to fix it.

---

<div class="post-metadata">

### Author: ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)
#### Post date: [January 10, 2019, 1:44am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/10 "2019-01-10T01:44:03Z")

</div>

If you need variables from the parent scope, the nested function is relatively short, and specific to where it’s used (can’t be reused elsewhere), I think nesting is a good idea.

Disadvantages of nesting: If the nested function grows, readability of the parent function can be compromised (compare your `notnested` with `nested` above). Also, it’s harder to unit test a nested function in isolation.

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [January 10, 2019, 3:57am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/11 "2019-01-10T03:57:19Z")

</div>

> [@yakir12](#):
>
> I’ve been using it [try/catch] as a means to terminate a iteration that is fruitless. Since the mechanics of such an event is nested well down the code I can’t elicit a `break` or some such. But I can most certainly propagate some failure in another way. Hmm!!!

`@goto` is your friend. Just write `@label error_foo` at the position where you want to break to, and then write `error_condition && @goto error_foo`. In that case you need to also remember scoping: If you need some loop-local variable in the error handler, then don’t make it loop-local (initialize it to some dummy value of the correct type outside of the loop; if you need to transfer a for-loop counter, then write it to something that is visible at the `@label` before triggering the `@goto`).

This is typically significantly more readable than “iterated `break`” where each loop checks errors of the inner loop and possibly breaks again.

In julia, `@goto` is not a necessarily a code smell, but instead is more fundamental than `while` and `for` (as evidenced by `@code_lowered` that rewrites control flow in terms of `@goto`).

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [January 10, 2019, 4:13am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/12 "2019-01-10T04:13:46Z")

</div>

> [@foobar\_lv2](#):
>
> In julia, `@goto` is not a necessarily a code smell, but instead is more fundamental than `while` and `for` (as evidenced by `@code_lowered` that rewrites control flow in terms of `@goto` ).

This is not more or less true in any other languages that I’m aware of. Loops are also lowered into conditional and unconditional branches in C compilers which isn’t any different from what you get in julia. They just may not have a easy way to inspect it or in the case of LLVM (and probably most other optimizing compilers) use a completely language. FWIW, the lowered AST isn’t strictly the same language as the surface julia syntax and/so `while` and `for` in julia are not implemented as `@goto`.

In any case, the usual advice against `goto` has nothing to do with what they do (unconditional branch, which is always going to be needed in these languages) but the way they are/can be used. It’s just too general and flexible that can be used to confuse both the compiler and the reader. So the advice is always to use them in a clear and predictable way/pattern.

The use of `@goto` to break out deeply nested loop is certainly fine and it’s one of the few patterns that I know that are widely accepted. But this should definitely not be generalized to using `@goto` being more encourage in julia than anywhere else.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [January 10, 2019, 4:18am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/13 "2019-01-10T04:18:39Z")

</div>

> [@kristoffer.carlsson](#):
>
> Using try catch for control flow is not great.

This is generally true in other languages as well\*\*. Pretty much all optimization specifically around exceptions are based on the assumption that they don’t happen often so they can be slow. (Of course on top of that our try-catch are even more expensive for C interop that is only needed in very few cases…)

\*\* At least in compilied/optimized languages. Probably doesn’t make much difference with an interpreter and I’ve certainly seen cases where throwing an exception as control flow is faster than a normal branch in python…

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 10, 2019, 9:18am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/14 "2019-01-10T09:18:36Z")

</div>

> [@foobar\_lv2](#):
>
> `@goto` is your friend

Cool, I tried it now, but it seems that it won’t work across functions, right? I can’t @goto from one function to a @label in another function, right? If correct then this won’t work for me – breaking events occur inside functions other than the functions I want to exit from. Kind of like this:

```julia
function fun(x) 
    x < 2 && @goto kaka
    x = 1
end
function fun2(x)
    g = fun(x)
    g+1
end
function fun3(x)
    return fun2(x)
    @label kaka
    false
end

```

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [January 10, 2019, 11:12am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/15 "2019-01-10T11:12:50Z")

</div>

Even if you could (you cannot) – you would not want to do that. That is how “spaghetti code” is cooked.

---

<div class="post-metadata">

### Author: ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)
#### Post date: [January 10, 2019, 11:14am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/16 "2019-01-10T11:14:26Z")

</div>

I don’t have anything against `goto`s per se, but I’ve met a lot of programmers, even experienced ones, who have a very strong aversion to them, and will consider any usage of `goto` a sign of poor quality code and a lazy/inexperienced developer. Even if you don’t agree with that, if your code is being judged (e.g. in a pull request or job interview), it’s something worth paying attention to.

In your example, `goto` doesn’t sound like the right approach. Neither does an exception. Hard to tell with such an artificial example, but if the breaking event is a dead ray, perhaps you should have a special return value indicating that, which you can test/propagate up the call hierarchy. You could either simply use a constant value for that (e.g. if you’re using floats, you could use `NaN`), or more elegantly you could have a small `RayStatus` struct and a method like `dead(rs::RayStatus)` which indicates status.

There will be a few extra lines propagating the status, but on the other hand, since the `DeadRay` exception is just caught and ignored in your example above, it seems like that whole try/catch block can go away with this approach.

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 10, 2019, 11:27am UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/17 "2019-01-10T11:27:53Z")

</div>

> [@bennedich](#):
>
> you should have a special return value indicating that

Indeed that’s how I solved it. Some of the relevant functions now return `failure, result` instead of just `result`. I then propagate the `failure` accordingly. It works very nicely now.

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [January 10, 2019, 12:42pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/18 "2019-01-10T12:42:46Z")

</div>

The point of try/catch is that they are capable of unwinding a call stack that is not known at compile time. This is expensive (especially with respect to what the compiler can optimize).

If your special condition is triggered and handled in the same stack frame, then you should not pay this price, and `@goto` is strictly preferable to `try`/`catch`. A well-placed `@goto` is really no different than `continue` or `break`, and is imo the right way of “break twice”.

There is one theoretical performance advantage of exceptions: If the special condition applies rarely and can be raised by a CPU trap, then you don’t need to compile the branch, i.e. checking for the special condition is almost free (it forbids some optimizations but incurs not a single instruction).

Afaik julia currently doesn’t really exploit that hardware mechanism in user code.

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 10, 2019, 12:48pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/19 "2019-01-10T12:48:15Z")

</div>

Very cool. Yea, in my specific case it happens about 5% of the “time”. I think. So it’s not ultra rare.

The alternative way of handling this is to use ‘Missing’, ‘Union’, ‘nothing’, etc…

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [January 10, 2019, 2:44pm UTC](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417/20 "2019-01-10T14:44:03Z")

</div>

(maybe admins should split this into a new topic - “try catch versus return break” or some such)

Hmm, I tried adding @simd in some loops and realized I can’t have `break` or `continue` in such loops. So one solution is not to break the loop but write versions of the functions in the loop that short-circuit on specific values (values that indicate a failure).

So for instance, if something deeply nested returned a failure then it should return something like a `Val(true)` (true for failure), and I can add a method for one of the top functions that does nothing when the `failure` argument is true:

```julia
fun(arguments..., ::Val{false}) = <calculations...>
fun(arguments..., ::Val{true}) = nothing

```

What do you think about that?

[Next page](https://discourse.julialang.org/t/nested-functions-pros-and-cons/19417.md?page=2)
