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.

1 Like

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.

8 Likes

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

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

1 Like

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.

1 Like

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:

5 Likes

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.

1 Like

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

2 Likes