Accessing data in a closure?

Learning to work with closures. This is a construct to find out what is possible.

foo(d, x, y) = d[x] = y

struct Test
       f::Function
       Test(d::Dict, f::Function = (x, y) -> foo(d, x, y)) = new(f)
end

t = Test(Dict())

Whenever I call t.f(x, y) a key, value pair is added to the dict I passed with the Test constructor. So far, so good.

My question is: having t, can I access that dict somehow?

Thanks,
Stef

Found it!

t.f.d

I love this language!

I’m just leaving it here in case anyone else is interested.

I took me a while understanding what you did there. Interesting. I would have written it like this:

foo(d, x, y) = d[x] = y

struct Test
       f::Function
end

Test(d::Dict) = Test( (x,y) -> foo(d,x,y) )

t = Test(Dict())

@show t

@show t.f(1,2)

@show t.f 

@show t.f.d


I am not completely sure why you can access the dictionary as if it was a field of the closure. I guess that is because closures are implemented functors, meaning that it is something implicitly like

struct F
  d :: Dict
end

foo(d,x,y) = d[x] = y

(f::F)(x,y) = foo(f.d,x,y)

f = F(Dict())

@show f
@show f(1,2)
@show f.d 

Where clearly f has a d field. But I am not sure. That is not a common pattern to be seen (or is it?)

It is an implementation detail that variables captured by a closure can be accessed as fields of the closure object. Ideally, you should not rely on it.

What would be the minimal working example of that? This does not work, for example:

a = 2
f = x -> a*x
@show f(1).a

Maybe that is a good opportunity to understand how closures work a little further.

Edit:

This works:

f(a,x) = x -> a*x
@show f(1,2).a 

Yet the analogy with the OP example does not seem exact in this case.

julia> adder(x) = y -> x + y
adder (generic function with 1 method)

julia> adder(10).x
10

You probably should not be taking that second argument. It is immediately shadowed by the inner closure parameter name.

Yes, thanks. I added that trying to build a “standalone” working closure. But that makes no sense.

You may find the function dump useful in understanding new structures, the closure in this case.

I don’t think

I don’t think that’s true. The docs say: “A closure is simply a callable object with field names corresponding to captured variables”, though there’s no code example of accessing it that way. (Julia Functions · The Julia Language).
This easy access to closed-over variable is one of the things I was happy to find in Julia, since I always felt was missing in Python. I use it quite a lot.

You are looking at the Developer’s Documentation, not the User’s Manual.

Accessing captured variables as fields in a closure object is an implementation detail, we have word of god on this:

Yeah, you’re right. I was searching the docs for “closure” and didn’t notice the result was in the Developer section.
That’s pretty disappointing, cause I think it’s an awesome feature.

Feel free to use it as long as you’re willing to possibly have your code break with new Julia versions.