thanks !
Old post, but could not find a more recent example.
In oo-lingo, closures getx and setx are made to âpublic methodsâ.
() â (getx;setx)
I understand something like âtupleâ, âmapâ, âtuple of functionsâ, but not the syntax.
Could someone please translate the working of this line into plain English?
Which part of the doc to consult for such an expression?
Thx
This defines an anonymous function with zero arguments. Calling it returns a named tuple containing the functions getx
and setx
.
I.e. youâd use it like this:
julia> f = Foo()
julia> f().getx()
-1
julia> f().setx(1)
1
julia> f().getx()
1
https://docs.julialang.org/en/v1/manual/functions/#man-anonymous-functions
Thanks @Sukera.
This defines an anonymous function with zero arguments.
Right
Calling it returns a named tuple containing the functions
getx
andsetx
.
Canât follow here.
While the dot notation is also available for named tuples, I only know their definition as (name1 = val1, ).
How get the nested functions attached to the outer function?
Donât want to be too fussy, if itâs just the way it works, ok. Maybe there is something basic to learn.
Theyâre not attached at all! Theyâre defined in Foo
and capture the variable x
, i.e. they keep a reference to x
. Finally, the last anonymous function captures (keeps a reference) to both getx
and setx
, which can be retrieved due to the trick of having them saved in a named tuple. Finally, Foo()().getx
is the same as f = Foo(); vars = f(); getx_func = vars.getx; getx_func()
. Internally, itâs a little more complicated because anonymous functions are basically callable structs, which are defined before Foo
during lowering - but thatâs just an implementation detail.
I think itâs fine to find this confusing. (getx;setx)
does not create a named tuple, it just returns setx
. With a recent enough Julia (;getx, setx)
does create a named tuple though. Compare these implementations:
julia> function Foo1()
x::Int = -1
setx(x_) = (x = x_)
getx() = x
() -> (getx;setx)
end
Foo1 (generic function with 1 method)
julia> function Foo2()
x::Int = -1
setx(x_) = (x = x_)
getx() = x
() -> (;getx, setx)
end
Foo2 (generic function with 1 method)
julia> f1=Foo1()
#27 (generic function with 1 method)
julia> f2=Foo2()
#31 (generic function with 1 method)
julia> f2().getx()
-1
julia> f1().getx()
ERROR: type #setx#28 has no field getx
Stacktrace:
[1] getproperty(x::Function, f::Symbol)
@ Base ./Base.jl:33
[2] top-level scope
@ REPL[58]:1
However, the magic of the original example is that you in both cases can do
julia> f2.getx()
-1
julia> f1.getx()
-1
Related: How to understand this code that seemingly creates an anonymous type on the fly? - #2 by rdeits
I like the explicit syntax using named tuples!
function Foo()
x = -1 # should make it Int
setx(xnew) = (x = Int(xnew))
getx() = x
(; getx, setx)
end
julia> f = Foo()
(getx = var"#getx#18"(Core.Box(-1)), setx = var"#setx#17"(Core.Box(-1)))
Is the Box(ing) above a bad sign for performance?
The compiler should be informed enough about types. Why does it appear?
The absolute horror of that.