All ways to define functions in Julia?

There’s another way:

julia> name4 = (a + b for a in 1:2, b in 3:4).f
#1 (generic function with 1 method)

julia> name4((1, 2))
3

Mind blowing!!!

Agreed. But I hope that no one will ever use this :smiley:

I don’t think so. In my example,

function fn_generator()
    if true
        f() = 0
    else
        f(x, y) = x+y
    end
end

both method definitions are returned:

julia> fn_generator()
(::var"#f#1") (generic function with 2 methods)

However, if instead I say

function fn_generator2()
    if false
        f(x, y) = x+y
    else
        f() = 0
    end
end

then I get an error:

julia> fn_generator2()
ERROR: UndefVarError: f not defined

Is that intended?

The simplest one: function foo end

More brackets:
(Δ = ((((((((()))))((((((())))))) = ())))))
Δ(2)

Does that work for you? I get an error.

julia> (Δ = ((((((((()))))((((((())))))) = ())))))
ERROR: syntax: invalid function name "()" around REPL[3]:100: 
julia> (Δ = ((((((((()))))((((((())))))) = ())))))
#s1 (generic function with 1 method)

julia> Δ(2)
()

This is what I got.

Looks like it’s new in 1.6. A smaller version is

julia> (()() = ())()
()

This recalls:

julia> where where where where where where where where where
Any

:sweat_smile:

julia> where where where
Any

why does this work?

Same as T where T, with a variable called where.

Huh, interesting. I would have expected where to be a reserved word in Julia, or at least throw some kind of warning. On the other hand, one would have to go deliberately out of their way to make that construct, so forbidding it may arguably not be warranted.

wow! Why can I do this:

julia> a*b=a+b
* (generic function with 1 method)

julia> 2*3
5

but not this

julia> 2*3
6

julia> a*b=a+b
ERROR: error in method definition: function Base.* must be explicitly imported to be extended
Stacktrace:
 [1] top-level scope
   @ none:0
 [2] top-level scope
   @ REPL[1]:1

after starting a new REPL each time? Shouldn’t the first one give the same warning?

I agree that that in particular could show a warning or an error. But note that this is the behaviour for every function exported by any module:

julia> module A
         export f
         f(x) = 1
       end
Main.A

julia> using .A

julia> f(x) = 2
f (generic function with 1 method)

julia> f(1)
2

while:

julia> module A
         export f
         f(x) = 1
       end
Main.A

julia> using .A

julia> f(1)
1

julia> f(x) = 2
ERROR: error in method definition: function A.f must be explicitly imported to be extended

It would be really annoying if we could not define the function if the name we wanted because some package exported that name. The behaviour is that if you define your own function first, then you take that name, if you use the package’s function first, then if you try to redefine it, you must explicitly extend it.

Thanks for clarifying, up until now I assumed that your first example would also give an error! That might have caused some confusion in the past :sweat_smile:

Another one, I have not seen yet

julia> name1 = begin
           x
           y=2
       end -> x + y
#1 (generic function with 1 method)

julia> name1(1)
3

julia> name1(2;y=2)
4

julia> name2 = begin
           x
           y
       end -> x + y
#4 (generic function with 1 method)

julia> name2(2; y=2)
4

Why is begin; x; y; end equivalent to (x;y) in this context?

I am not too sure but I would say that multiple unrelated expressions are parsed as a block so (x;y) is a valid block. You can then replace (x;y) by begin; x; y; end in the function declaration.

julia> :((x;y)) |> dump
Expr
  head: Symbol block
  args: Array{Any}((3,))
    1: Symbol x
    2: LineNumberNode
      line: Int64 1
      file: Symbol REPL[1]
    3: Symbol y

this thread is getting better and better