Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit capture of variables in a closure. #14959

Open
KristofferC opened this issue Feb 6, 2016 · 10 comments
Open

Explicit capture of variables in a closure. #14959

KristofferC opened this issue Feb 6, 2016 · 10 comments

Comments

@KristofferC
Copy link
Member

Right now when you create a closure you capture all the variables in the scope the closure is defined. This can lead to subtle bugs where you accidentally introduce a variable with the same name as one of the captured variables.

Would it be possible to introduce a syntax where the user explicitly lists what variables should be captured? A possible syntax of this (in spirit of lambda capture lists in c++) could be

function foo[a,b,...](x)
   ...
end

(x)[a,b,...] -> ...

which would capture a and b. These both seem to be syntax error so should be available to use.

An example of this in use:

function foo()
    a = 1
    b = 1
    c = 1
    # Only a and b is captured
    function g[a, b](x)
        a = x
        b = x
        c = x
    end
    g(5)
    println(a)
    println(b)
    println(c)
end

foo()
# Prints
JuliaLang/julia#5
JuliaLang/julia#5
JuliaLang/julia#1

function bar()
    a = 1
    b = 2
    c = 3
    function f[a, b](x)
        return a + b + x
    end
    function g[a](x)
        return a + b + x
    end
    f(5) # Ok!
    g(5) # UndefVarError since b is not captured
end

Issues like #14948 seem to indicate that some sort of explicit capturing functionality could be useful to have.

@amitmurthy
Copy link
Contributor

Related issue : JuliaLang/Distributed.jl#30

@mauro3
Copy link
Contributor

mauro3 commented Feb 8, 2016

@amitmurthy: yes that issue is closely related: it is this very issue ;-) Which one did you mean?

@amitmurthy
Copy link
Contributor

Edited above.

@mauro3
Copy link
Contributor

mauro3 commented Jun 23, 2016

@KristofferC: your examples suggest that you are concerned about functions in inner scopes. If so, making hard-scopes also hard for non-global variables could go some way. See #10559

When only "reading" variables, this could get quite verbose, would you need to write: f[pi,sin](x) = sin(pi*x)?

@KristofferC
Copy link
Member Author

I was concerned about accidentally modifying (rebinding) a variable local to the outer function from a closure so I wanted a syntax to only bring a set of chosen variables in scope for the closure. By default things can work exactly like now.

@mauro3
Copy link
Contributor

mauro3 commented Jun 23, 2016

I don't quite follow your comment, but maybe I can be clearer. If Julia had functions with hard scope also for non-global variables and had the nonlocal keyword, your first example would read:

function foo()
    a = 1
    b = 1
    c = 1
    # Only a and b is captured
    function g(x)
        nonlocal a = x
        nonlocal b = x
        c = x
    end
    g(5)
    println(a)
    println(b)
    println(c)
end

foo()
# Prints
# 5
# 5
# 1

@martinholters
Copy link
Member

@mauro3 That would be a breaking change unless some ugly rule like "assume implicit nonlocal everywhere unless there is at least one explicit one" is added.

Coming back to the bar example, ones needs to know that + is a function, not a variable bound to a function, otherwise it would have to be added to the list of captures. Certainly not a problem here, and probably rarely an issue, but worth keeping in mind.

Another option (whatever the syntax) would be to have all variables captured read-only (const-like) and naming those explicitly that should be writable.

@KristofferC
Copy link
Member Author

I did not think about functions being first class objects so you would also need to capture those, would be annoying... An implicit const on all captured objects is in my view a good idea but I have no feeling of how often a captured variable is modified in Base / user code so I don't know the level of breakage it would do.

@mauro3
Copy link
Contributor

mauro3 commented Jun 23, 2016

Yes, that would be a breaking change. However, I think I would prefer it to the proposal here as function signatures are tricky enough already in Julia. Anyway, I just wanted to relate #10559 (closed) to this issue.

Also, @JeffBezanson recently hinted that this hard-scope-only-affects-global-bindings could change: #16727 (comment)

@colinfang
Copy link
Contributor

The current semi-hard scope rule for nested function is so dangerous and annoying. I really want @mauro3 's nonlocal which is also the Python 3's approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants