# Defining a function inside if...else..end NOT as expected?

**URL:** https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815
**Category:** New to Julia
**Tags:** scope
**Created:** [August 21, 2018, 9:12am UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815 "2018-08-21T09:12:22Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 9:12am UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/1 "2018-08-21T09:12:22Z")

</div>

hello, I have difficulties in defining a closure within a if-else-end block.

I expect `closure(1)` would give a function that prints 1, while `closure(2)` would give a function that prints “not 1”.

But the results are very strange as below. I’m using JuliaPro 0.6.3.1

```julia
function closure(choice)
    if choice == 1
        function fun()
            println(1)
        end
    else
        function fun()
            println("not 1")
        end
    end

    return fun
end

julia> fff = closure(1)
(::fun) (generic function with 1 method)

julia> fff()
not 1

julia> ggg = closure(2)
ERROR: UndefVarError: fun not defined
Stacktrace:
 [1] closure(::Int64) at ./none:12
 [2] macro expansion at /Applications/JuliaPro-0.6.3.1.app/Contents/Resources/pkgs-0.6.3.1/v0.6/Atom/src/repl.jl:118 [inlined]
 [3] anonymous at ./<missing>:?

```

---

<div class="post-metadata">

### Author: ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)
#### Post date: [August 21, 2018, 9:48am UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/2 "2018-08-21T09:48:05Z")

</div>

It is a known failure and intentional, I think. You should use anonymous function for conditional function generation. It should look like

```julia
if ...
 fun = () -> ....
...
else
 fun = () -> .....
end

```

or

```julia
if ....
 fun = function (args)

 end
else
 fun =function (args)
 end
end

```

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 9:57am UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/3 "2018-08-21T09:57:47Z")

</div>

sadly …

two problems with this approach:

1. multiple dispatch not work !!! e.g.

```julia

ff = function(a::Vector{Float64})
    sum(a)
end

ff = function(a::Vector{Int64})
    prod(a)
end

julia> ff([1.0, 2.0])
ERROR: MethodError: no method matching (::##135#136)(::Array{Float64,1})
Closest candidates are:
  #135(::Array{Int64,1}) at none:2

julia> ff([1, 2])
2

```

the first float version is **_overwritten_** by the integer version !!! actually it each method should be kept ???

1. return type can **_not_** be specified??? e.g. function like below gives error 😫

```julia

ff = function(a::Vector{Float64})::Float64
    sum(a)
end

ERROR: ParseError("expected \"(\" in function definition")
Stacktrace:
 [1] #parse#236(::Bool, ::Bool, ::Function, ::String, ::Int64) at ./parse.jl:222
 [2] (::Base.#kw##parse)(::Array{Any,1}, ::Base.#parse, ::String, ::Int64) at ./<missing>:0
 [3] #parse#237(::Bool, ::Function, ::String) at ./parse.jl:232
 [4] macro expansion at /Applications/JuliaPro-0.6.3.1.app/Contents/Resources/pkgs-0.6.3.1/v0.6/Atom/src/repl.jl:118 [inlined]
 [5] anonymous at ./<missing>:?

```

---

<div class="post-metadata">

### Author: ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)
#### Post date: [August 21, 2018, 10:06am UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/4 "2018-08-21T10:06:16Z")

</div>

I don’t know what you want to achieve but I have an idea that you can make your own custom `Function` type like

```julia
struct FF{choice} <: Function
end

```

Now, you can overload `(::FF{1})(args)`, `(::FF{2})(args)`, etc and conditionally assign `ff`.

---

<div class="post-metadata">

### Author: ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)
#### Post date: [August 21, 2018, 10:15am UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/5 "2018-08-21T10:15:11Z")

</div>

> [@tomtom](#):
>
> sadly …
> 
> two problems with this approach:

If you applied the anonymous function suggestion to your original code it works just fine:

```julia
julia> function closure(choice)
           fun = if choice == 1
               function(a::Vector{Float64})
                   sum(a)
               end
           else
               function(a::Vector{Int})
                   prod(a)
               end
           end
           return fun
       end
closure (generic function with 1 method)

julia> f = closure(1); g = closure(2);

julia> f([1., 2.])
3.0

julia> g([1, 2])
2

```

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 10:16am UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/6 "2018-08-21T10:16:06Z")

</div>

thanks.

I just think that closure is very essential to functional programming. And, defining (mulitplely dispatched) functions according to different conditions is very natural …

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 1:27pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/7 "2018-08-21T13:27:45Z")

</div>

> If you applied the anonymous function suggestion to your original code it works just fine:

No. This way does _not_ support multiple dispatch …

let me give a better example:

```julia
function closure(choice)
    # using closure for "static local variables"
    staticlocalvar = 0

    # ok: multiple dispatch for set()
    function set(var::Float64)
        staticlocalvar = var
    end

    function set(var::Vector{Float64})
        staticlocalvar = var
    end

    # NOT ok: function definitions within if-elseif-else-end
    if choice == :sum
        function f(x::Float64)
            return x + staticlocalvar
        end
    
        function f(x::Vector{Float64})
            return x .+ staticlocalvar
        end

    elseif choice == :prod
        function f(x::Float64)
            return x * staticlocalvar
        end
    
        function f(x::Vector{Float64})
            return dot(x, staticlocalvar)
        end
    else
        error("choice should be :sum or :prod !")
    end

    return (set, f)
end

```

_ideally_, calling `closure(:sum)` or `closure(:prod)` would give me a Tuple of functions `set()` and ` f()`, and each of them has multiple dispatch …

unfortunately, it does not work because defining function inside `if-end` is “a known failure and intentional”, why???

using anonymous functions does _not_ support multiple dispatch, as each identifier (e.g. `fun`) is assigned to one and only one anonymous function. Or, any way out such that we can have multiple dispatch on anonymous function?

using struct as suggested by @tomaklutfu … it’s kind of “artificial”, and most importantly, it loses the possibility of “static local variable” provided by closure, which is essential as Julia does not natively support it in other way …

---

<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: [August 21, 2018, 2:02pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/8 "2018-08-21T14:02:43Z")

</div>

> [@tomtom](#):
>
> why???

Optimization so that the method table can be constructed in advance.

---

<div class="post-metadata">

### Author: ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)
#### Post date: [August 21, 2018, 2:40pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/9 "2018-08-21T14:40:14Z")

</div>

You can have “local variables” as struct fields as closures do the same I think but the thing with conditional named functions is that the name of functions clash as constant variables. It can be more efficient defining this way rather than unpredictable `staticlocalvar` in the example.

```julia
struct FF{Choice, T} <: Function
staticlocalvar::T 
end

```

If you want it to work that way you can use different names within branches and assign `f` to that function name.

```julia
if choice==:sum
function g(args)
end
f=g
else
function h(args)
end
f=h
end

```

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 3:16pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/10 "2018-08-21T15:16:21Z")

</div>

> Optimization so that the method table can be constructed in advance.

Sorry …I’m not convinced … as long as a human could “parse” some code without much difficulty, it should be easy for the optimizer to do the job.

I just don’t see why multiply-dispatched-functions can not be defined in a if-end block within a closure …

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [August 21, 2018, 3:18pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/11 "2018-08-21T15:18:51Z")

</div>

Read the code provided by @fredrikekre carefully, especially this part:

```julia
fun = if choice == 1
    function(a::Vector{Float64})
        sum(a)
    end
else
    function(a::Vector{Int})
        prod(a)
    end
end
return fun

```

This is NOT what you’re doing - here, the result of the if (in this case the function definition!) is saved into `fun` and returned. What you’re doing is defining functions without returning them to the caller of the closure.

EDIT: Your code, fixed:

```julia
function closure(choice)
    staticlocalvar = 0

    function set(var::Float64)
        staticlocalvar = var
    end

    function set(var::Vector{Float64})
        staticlocalvar = var
    end

    # totally fine actually
    ret = if choice == :sum
        function f(x::Float64)
            return x + staticlocalvar
        end
    
        function f(x::Vector{Float64})
            return x .+ staticlocalvar
        end
        f
    elseif choice == :prod
        function f(x::Float64)
            return x * staticlocalvar
        end
    
        function f(x::Vector{Float64})
            return dot(x, staticlocalvar)
        end
        f
    else
        error("choice should be :sum or :prod !")
    end

    return (set, ret)
end

```

---

<div class="post-metadata">

### Author: ![Evizero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evizero/32/10118_2.png) [@Evizero](https://discourse.julialang.org/u/Evizero)
#### Post date: [August 21, 2018, 4:26pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/12 "2018-08-21T16:26:19Z")

</div>

This seems to work:

```julia
julia> function closure(choice)
           fun = if choice == 1
               function tf1(x::Number)
                   println("hello")
               end
               function tf1(x::AbstractVector)
                   println("is it me")
               end
               tf1
           else
               function tf2(x::Number)
                   println("you are looking for")
               end
               tf2
           end
           return fun
       end
closure (generic function with 1 method)

julia> f = closure(1)
(::getfield(Main, Symbol("#tf1#25"))) (generic function with 2 methods)

julia> f(1)
hello

julia> f([1,2])
is it me

julia> f = closure(2)
(::getfield(Main, Symbol("#tf2#26"))) (generic function with 1 method)

julia> f(1)
you are looking for

```

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 4:38pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/13 "2018-08-21T16:38:45Z")

</div>

> totally fine actually

not really. It compiles, but if you try to run:

```julia
julia> (setfun, sumfun) = closure(:sum)
(set, f)

julia> setfun(1.1)
1.1
julia> sumfun(2.2)
2.4200000000000004
julia> (setfun, prodfun) = closure(:prod)
ERROR: UndefVarError: f not defined
Stacktrace:
 [1] closure(::Symbol) at ./none:31
 [2] macro expansion at /Applications/JuliaPro-0.6.3.1.app/Contents/Resources/pkgs-0.6.3.1/v0.6/Atom/src/repl.jl:118 [inlined]
 [3] anonymous at ./<missing>:?

```

finally, as @Evizero suggested, **the trick is to use different function names** inside `if-else-end` block. Fixed like this:

```julia

 
function closure(choice)
    staticlocalvar = 0

    function set(var::Float64)
        staticlocalvar = var
    end

    function set(var::Vector{Float64})
        staticlocalvar = var
    end

    # totally fine actually
    ret = if choice == :sum
        function f(x::Float64)
            return x + staticlocalvar
        end

        function f(x::Vector{Float64})
            return x .+ staticlocalvar
        end

        f

    elseif choice == :prod
        function g(x::Float64) # !!! g, not f !!! #
            return x * staticlocalvar
        end

        function g(x::Vector{Float64}) # !!! g, not f !!! #
            return dot(x, staticlocalvar)
        end

        g # !!! g, not f !!! #

    else
        error("choice should be :sum or :prod !")
    end

    return (set, ret)
end

julia> (setfun, sumfun) = closure(:sum)
(set, f)
julia> setfun(1.1)
1.1
julia> sumfun(2.2)
3.3000000000000003
julia> (setfun, prodfun) = closure(:prod)
(set, g)
julia> setfun(1.1)
1.1
julia> prodfun(2.2)
2.4200000000000004

```

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [August 21, 2018, 5:39pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/14 "2018-08-21T17:39:43Z")

</div>

Interesting - maybe that’s because you used both right after one another? I only tested them individually.

I guess it’s because you can’t redefine an existing symbol, which is what would happen if you call them twice. What’s even more interesting is that the error message about redefining an existing symbol gets swallowed and only after the return when you try to call it do you get an error about a function not being defined.

---

<div class="post-metadata">

### Author: ![danielmatz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielmatz/32/2285_2.png) [@danielmatz](https://discourse.julialang.org/u/danielmatz)
#### Post date: [August 21, 2018, 5:51pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/15 "2018-08-21T17:51:57Z")

</div>

I think the issue is that named functions in a given scope block are combined, with no regard to the logic of the code. So if we use let blocks to introduce additional scope blocks, I think it works:

```julia
function closure(option)
    if option == 1
        let
            f(x::Int) = 1
            f(x::Float64) = 1.0
            f
        end
    else
       let
           f(x::Int) = 2
           f(x::Float64) = 2.0
           f
       end
    end
end

```

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [August 21, 2018, 6:41pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/16 "2018-08-21T18:41:03Z")

</div>

> [@tomtom](#):
>
> Sorry …I’m not convinced … as long as a human could “parse” some code without much difficulty, it should be easy for the optimizer to do the job.

Claims that something should be easy to implement that are unaccompanied by correct, efficient implementations are unfortunately both common and not terribly useful. We would, however, be be very happy to accept a PR implementing this. You may want to keep in mind that Jeff, who designed and implemented the way functions work in Julia today, was not and has not yet been able to figure out a way to address this limitation efficiently and generally. That doesn’t mean it’s not possible, but it does suggest that there may be some difficulties and subtleties that may not be immediately apparent to someone who has only just encountered the problem for the first time.

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 10:44pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/17 "2018-08-21T22:44:29Z")

</div>

> Claims that something should be easy to implement that are unaccompanied by correct, efficient implementations are unfortunately both common and not terribly useful.

I’m sorry. You’re right.

> accept a PR implementing this

by the way, what does “PR” mean?

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [August 21, 2018, 10:47pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/18 "2018-08-21T22:47:26Z")

</div>

PR = “[pull request](https://help.github.com/articles/about-pull-requests/)”

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 10:48pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/19 "2018-08-21T22:48:45Z")

</div>

yes, it works.😀

---

<div class="post-metadata">

### Author: ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)
#### Post date: [August 21, 2018, 10:51pm UTC](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815/20 "2018-08-21T22:51:49Z")

</div>

> PR = “[pull request](https://help.github.com/articles/about-pull-requests/)”

I see. thanks.

[Next page](https://discourse.julialang.org/t/defining-a-function-inside-if-else-end-not-as-expected/13815.md?page=2)
