Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the Julia Do Syntax for functions work?

I've seen here that do syntax can be used as a more convenient way to write map() functions, but I don't understand how e.g. in the example shown in the linked julia docs :

open("outfile", "w") do io
    write(io, data)
end

Which works on the following function definition of 'open'

function open(f::Function, args...)
    io = open(args...)
    try
        f(io)
    finally
        close(io)
    end
end

How in the world does the do pass the io and write(io,data) to the actual function of open and f(io)? Does the function with the do block have to have the same name/be multi-dispatched for the do block to work?

like image 838
Spcogg the second Avatar asked May 13 '21 12:05

Spcogg the second


People also ask

How do functions work in Julia?

Functions in Julia can be combined by composing or piping (chaining) them together. Function composition is when you combine functions together and apply the resulting composition to arguments. You use the function composition operator ( ∘ ) to compose the functions, so (f ∘ g)(args...) is the same as f(g(args...)) .

What is the type of a function in Julia?

Function is an abstract type. So for example Vector{Function} is like a Vector{Any} , or Vector{Integer} : Julia just can't infer the results.

How do you return a function in Julia?

'return' keyword in Julia is used to return the last computed value to the caller function. This keyword will cause the enclosing function to exit once the value is returned. return keyword will make the function to exit immediately and the expressions after the return statement will not be executed.

What is a generic function Julia?

Method Tables Every function in Julia is a generic function. A generic function is conceptually a single function, but consists of many definitions, or methods. The methods of a generic function are stored in a method table. Method tables (type MethodTable ) are associated with TypeName s.


2 Answers

It is a purely syntactical transformation.

func(x) do y
    body
end

is equivalent to

func(y -> body, x)

or

tmp = y -> body
func(tmp, x)

if you will, i.e. the do block defines an anonymous function that is passed as the first argument. For this to work it is, of course, required that there exist a method of func that has a matching signature, for example func(f::Function, ...) = ... (or simplyfunc(f, ...) = ...).


You can inspect what is really happening by using Meta.@lower:

julia> Meta.@lower func(x) do y
           print(y)
       end
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─      $(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─      global var"#1#2"
│        const var"#1#2"
│   %3 = Core._structtype(Main, Symbol("#1#2"), Core.svec(), Core.svec(), false, 0)
│        var"#1#2" = %3
│        Core._setsuper!(var"#1#2", Core.Function)
│        Core._typebody!(var"#1#2", Core.svec())
└──      return nothing
)))
│   %2 = Core.svec(var"#1#2", Core.Any)
│   %3 = Core.svec()
│   %4 = Core.svec(%2, %3, $(QuoteNode(:(#= REPL[1]:2 =#))))
│        $(Expr(:method, false, :(%4), CodeInfo(
    @ REPL[1]:2 within `none'
1 ─ %1 = print(y)
└──      return %1
)))
│        #1 = %new(var"#1#2")
│   %7 = #1
│   %8 = func(%7, x)
└──      return %8
))))

The output is, unfortunately, garbled with implementation details of anonymous functions: The code defines a new struct (%3), makes it callable (%4) using the body of the do block, creates an instance of it (%7), and in the end calls func(%7, x).

like image 67
fredrikekre Avatar answered Nov 15 '22 07:11

fredrikekre


If it helps anybody, I have also discovered through fiddling what @fredrikekre has written generally, via this example:

function func(blah::Function,baz,foo)
   blah([baz,foo])
End

and you can call it as either of the following

func("a", "b") do zzz
   vcat(uppercase.(zzz),"C")
end

func(zzz->vcat(uppercase.(zzz),"C"),"a", "b")

both produce the same output

3-element Vector{String}:
 "A"
 "B"
 "C"
like image 20
Spcogg the second Avatar answered Nov 15 '22 07:11

Spcogg the second