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
7 Likes

Mind blowing!!!

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

2 Likes

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?

2 Likes

The simplest one: function foo end

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

1 Like

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.

1 Like

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

julia> (()() = ())()
()
1 Like

This recalls:

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

:sweat_smile:

7 Likes
julia> where where where
Any

why does this work?

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

9 Likes

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?

1 Like

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.

9 Likes

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
1 Like

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
2 Likes

this thread is getting better and better

5 Likes