Re: [julia-users] scoping wat
I wrote: > Consider for example embedding a for loop in a macro, and the risk for > variable capture. Forget that. Macros seem to be hygienic. -- ELS'16 registration open! http://www.european-lisp-symposium.org Lisp, Jazz, Aïkido: http://www.didierverna.info
Re: [julia-users] scoping wat
Jeff Bezansonwrote: > Yes, one could argue that a `for` loop variable should always be a new > variable, but that does make the constructs less orthogonal. It's funny that you see this as less orthogonal, considering that, as Stefan pointed out, your "for" index will leak its final value. Consider for example embedding a for loop in a macro, and the risk for variable capture. Sounds pretty anti-orthogonal to me... > In any case I don't see how this is "do or don't, it depends". Depends > on what? Is the i in for(i=1:3) local to the loop? It depends (on whether there is an outer i or not). Does assignment create a binding? It depends (on the construct you're in). E.g. julia> if true; k = 10 end # -> 10 julia> k # -> 10 julia> let; l = 10 end # -> 10 julia> l # -> ERROR: UndefVarError: l not defined Does assignment in a function create a local binding? It depends (on whether the function is nested). etc. -- ELS'16 registration open! http://www.european-lisp-symposium.org Lisp, Jazz, Aïkido: http://www.didierverna.info
Re: [julia-users] scoping wat
Jeff Bezansonwrote: > It works this way because we didn't want to require all variables to > be explicitly introduced with a construct like `var x = 0`. This adds > a lot of noise to a program and is annoying to those used to python or > matlab. I see your point and I understand the concern for Python or Matlab users. You see local declarations as noise whereas as I see it as explicit intent. I still have a hard time digesting the fact that assignment creates new local bindings, but not always though ;-) -- ELS'16 registration open! http://www.european-lisp-symposium.org Lisp, Jazz, Aïkido: http://www.didierverna.info
Re: [julia-users] scoping wat
Cedric St-Jeanwrote: > Your let is broken, it's a no-op. let always creates local bindings :-D I know, it was just for the sake of the example. The let was just to introduce a block, I couldn't do that with begin since begin doesn't introduce a block! > I agree that the hard/soft scoping rules are messy. In practice, it > doesn't seem to cause a lot of issues Granted (although this doesn't really justify doing a mess in the first place; the same argument applies to Emacs Lisp's dynamic scoping by default for instance). -- ELS'16 registration open! http://www.european-lisp-symposium.org Lisp, Jazz, Aïkido: http://www.didierverna.info
Re: [julia-users] scoping wat
It looks to me like everything in the `for` loop behaves like variables inside a `let` block. Yes, one could argue that a `for` loop variable should always be a new variable, making it equivalent to let i for i = itr ... end end but that does make the constructs less orthogonal. In any case I don't see how this is "do or don't, it depends". Depends on what? On Tue, Apr 12, 2016 at 12:48 PM, Stefan Karpinskiwrote: > On Tue, Apr 12, 2016 at 12:33 PM, Jeff Bezanson > wrote: >> >> > And then, some like "for" do or don't, it depends. >> >> Is that really true? I don't believe there is a case where `for` >> behaves differently than `let`. > > > julia> i = 1 > 1 > > julia> for i = 2:10 >println(i) >end > 2 > 3 > 4 > 5 > 6 > 7 > 8 > 9 > 10 > > julia> i > 10
Re: [julia-users] scoping wat
On Tue, Apr 12, 2016 at 12:33 PM, Jeff Bezansonwrote: > > And then, some like "for" do or don't, it depends. > > Is that really true? I don't believe there is a case where `for` > behaves differently than `let`. > julia> i = 1 1 julia> for i = 2:10 println(i) end 2 3 4 5 6 7 8 9 10 julia> i 10
Re: [julia-users] scoping wat
As for how assignments introduce local variables: it was quite deliberate (and the right decision IMO) that the *presence* of an assignment to a variable creates a local variable, and not whether the assignment has actually executed yet. I'm talking about this example: x = 10 function foo() println(x) x = 5 println(x) end The new binding for x is the one used throughout the block. The *binding* is indeed visible to the first println, but the value it points to is a non-first-class "undefined" value that raises an error. I don't think you would want a variable to switch from global to local in the middle of a block based on control flow. It works this way because we didn't want to require all variables to be explicitly introduced with a construct like `var x = 0`. This adds a lot of noise to a program and is annoying to those used to python or matlab. > And then, some like "for" do or don't, it depends. Is that really true? I don't believe there is a case where `for` behaves differently than `let`. This approach to scope is not as foreign to Scheme as one might think. You can think of constructs like `for` or `let` as scheme macros, where some introduce implicit letrecs and others don't. Scheme `begin` doesn't have an implicit letrec, but lambda does, etc. On Tue, Apr 12, 2016 at 10:37 AM, Erik Schnetterwrote: > On Tue, Apr 12, 2016 at 9:05 AM, Cedric St-Jean > wrote: >> >> On Tuesday, April 12, 2016 at 8:52:23 AM UTC-4, Didier Verna wrote: >>> >>> Mauro wrote: >>> >>> > Maybe you can be a bit more explicit in what you mean, examples would >>> > help too. >>> >>> Sorry for the fuzziness. This is an example of what I mean: >>> >>> let >>> x = 10 >>> end >> >> >> Your let is broken, it's a no-op. let always creates local bindings >> >> xx = 20 >> let xx = 30 >> @show xx >> end >> @show xx >> >>> xx=30 >>> xx=20 > > The manual is unclear where it introduces let bindings. It says e.g. > at one point that let uses soft scope > (http://docs.julialang.org/en/release-0.4/manual/variables-and-scoping/), > and at another point that "let statements allocate new variable > bindings". It doesn't make a distinction between the bindings > introduced on the same line as the `let` (or in lines terminated by a > colon), and other lines (or after the first semicolon). Compare > > let a=4 end > > let; a=4 end > > let a=4, b=4 end > > let a=4; b=4 end > > let a=4, > b=4 > end > > let a=4; > b=4 > end > > let > a=4 > b=4 > end > > The manual could be more explicit about this. > > -erik > > >> I agree that the hard/soft scoping rules are messy. In practice, it doesn't >> seem to cause a lot of issues >> >> >>> >>> >>> here, the same expression "x = 10" will either assign a new value to x >>> if such a /global/ exists, or create a new /local/ binding. This is >>> already bad enough[1]. Then, begin/end behaves differently. Then, "if" >>> doesn't introduce a new block, but some others constructs do, and some >>> don't. And then, some like "for" do or don't, it depends. >>> >>> Now even worse: >>> x = 10 >>> function foo() >>> println(x) >>> x = 5 >>> println(x) >>> end >>> >>> will break on the first println (one could expect to get 10, the global >>> value for x) because since there is an assignment /later on/, a new >>> /local/ binding will be created for x (which BTW is the exact opposite >>> of what let does!), but this binding isn't available to the first >>> println. And also, since a variable cannot switch from global to local >>> (or vice-versa) in the same block, the intuition (well, mine anyway ;-)) >>> that after the assignment, the scoping changes, is wrong. >>> >>> And then, as you mention, nested functions will behave yet >>> differently. All of this looks really bad. >>> >>> So IMHO, the real problem is that there are two distinct concepts: >>> assigning a new value to an existing binding, and creating a new >>> binding, possibly with an initial assignment. These are separate things >>> and mixing the two in such ways is wrong, and also quite surprising, >>> knowing the lispy side of this language. >>> >>> >>> >>> Footnotes: >>> [1] consider that a simple typo in your code may lead to silently >>> creating a new variable, which will never be used. >>> >>> -- >>> ELS'16 registration open! http://www.european-lisp-symposium.org >>> >>> Lisp, Jazz, Aïkido: http://www.didierverna.info > > > > -- > Erik Schnetter > http://www.perimeterinstitute.ca/personal/eschnetter/
Re: [julia-users] scoping wat
On Tue, Apr 12, 2016 at 9:05 AM, Cedric St-Jeanwrote: > > On Tuesday, April 12, 2016 at 8:52:23 AM UTC-4, Didier Verna wrote: >> >> Mauro wrote: >> >> > Maybe you can be a bit more explicit in what you mean, examples would >> > help too. >> >> Sorry for the fuzziness. This is an example of what I mean: >> >> let >> x = 10 >> end > > > Your let is broken, it's a no-op. let always creates local bindings > > xx = 20 > let xx = 30 > @show xx > end > @show xx > >> xx=30 >> xx=20 The manual is unclear where it introduces let bindings. It says e.g. at one point that let uses soft scope (http://docs.julialang.org/en/release-0.4/manual/variables-and-scoping/), and at another point that "let statements allocate new variable bindings". It doesn't make a distinction between the bindings introduced on the same line as the `let` (or in lines terminated by a colon), and other lines (or after the first semicolon). Compare let a=4 end let; a=4 end let a=4, b=4 end let a=4; b=4 end let a=4, b=4 end let a=4; b=4 end let a=4 b=4 end The manual could be more explicit about this. -erik > I agree that the hard/soft scoping rules are messy. In practice, it doesn't > seem to cause a lot of issues > > >> >> >> here, the same expression "x = 10" will either assign a new value to x >> if such a /global/ exists, or create a new /local/ binding. This is >> already bad enough[1]. Then, begin/end behaves differently. Then, "if" >> doesn't introduce a new block, but some others constructs do, and some >> don't. And then, some like "for" do or don't, it depends. >> >> Now even worse: >> x = 10 >> function foo() >> println(x) >> x = 5 >> println(x) >> end >> >> will break on the first println (one could expect to get 10, the global >> value for x) because since there is an assignment /later on/, a new >> /local/ binding will be created for x (which BTW is the exact opposite >> of what let does!), but this binding isn't available to the first >> println. And also, since a variable cannot switch from global to local >> (or vice-versa) in the same block, the intuition (well, mine anyway ;-)) >> that after the assignment, the scoping changes, is wrong. >> >> And then, as you mention, nested functions will behave yet >> differently. All of this looks really bad. >> >> So IMHO, the real problem is that there are two distinct concepts: >> assigning a new value to an existing binding, and creating a new >> binding, possibly with an initial assignment. These are separate things >> and mixing the two in such ways is wrong, and also quite surprising, >> knowing the lispy side of this language. >> >> >> >> Footnotes: >> [1] consider that a simple typo in your code may lead to silently >> creating a new variable, which will never be used. >> >> -- >> ELS'16 registration open! http://www.european-lisp-symposium.org >> >> Lisp, Jazz, Aïkido: http://www.didierverna.info -- Erik Schnetter http://www.perimeterinstitute.ca/personal/eschnetter/
Re: [julia-users] scoping wat
On Tuesday, April 12, 2016 at 8:52:23 AM UTC-4, Didier Verna wrote: > > Maurowrote: > > > Maybe you can be a bit more explicit in what you mean, examples would > > help too. > > Sorry for the fuzziness. This is an example of what I mean: > > let > x = 10 > end > Your let is broken, it's a no-op. let always creates local bindings xx = 20 let xx = 30 @show xx end @show xx > xx=30 > xx=20 I agree that the hard/soft scoping rules are messy. In practice, it doesn't seem to cause a lot of issues > > here, the same expression "x = 10" will either assign a new value to x > if such a /global/ exists, or create a new /local/ binding. This is > already bad enough[1]. Then, begin/end behaves differently. Then, "if" > doesn't introduce a new block, but some others constructs do, and some > don't. And then, some like "for" do or don't, it depends. > > Now even worse: > x = 10 > function foo() > println(x) > x = 5 > println(x) > end > > will break on the first println (one could expect to get 10, the global > value for x) because since there is an assignment /later on/, a new > /local/ binding will be created for x (which BTW is the exact opposite > of what let does!), but this binding isn't available to the first > println. And also, since a variable cannot switch from global to local > (or vice-versa) in the same block, the intuition (well, mine anyway ;-)) > that after the assignment, the scoping changes, is wrong. > > And then, as you mention, nested functions will behave yet > differently. All of this looks really bad. > > So IMHO, the real problem is that there are two distinct concepts: > assigning a new value to an existing binding, and creating a new > binding, possibly with an initial assignment. These are separate things > and mixing the two in such ways is wrong, and also quite surprising, > knowing the lispy side of this language. > > > > Footnotes: > [1] consider that a simple typo in your code may lead to silently > creating a new variable, which will never be used. > > -- > ELS'16 registration open! http://www.european-lisp-symposium.org > > Lisp, Jazz, Aïkido: http://www.didierverna.info >
Re: [julia-users] scoping wat
Python has similar rules. x = 10 def foo(): print x x = 5 print x foo() UnboundLocalError: local variable 'x' referenced before assignment On Tuesday, April 12, 2016 at 1:52:23 PM UTC+1, Didier Verna wrote: > > Maurowrote: > > > Maybe you can be a bit more explicit in what you mean, examples would > > help too. > > Sorry for the fuzziness. This is an example of what I mean: > > let > x = 10 > end > > here, the same expression "x = 10" will either assign a new value to x > if such a /global/ exists, or create a new /local/ binding. This is > already bad enough[1]. Then, begin/end behaves differently. Then, "if" > doesn't introduce a new block, but some others constructs do, and some > don't. And then, some like "for" do or don't, it depends. > > Now even worse: > x = 10 > function foo() > println(x) > x = 5 > println(x) > end > > will break on the first println (one could expect to get 10, the global > value for x) because since there is an assignment /later on/, a new > /local/ binding will be created for x (which BTW is the exact opposite > of what let does!), but this binding isn't available to the first > println. And also, since a variable cannot switch from global to local > (or vice-versa) in the same block, the intuition (well, mine anyway ;-)) > that after the assignment, the scoping changes, is wrong. > > And then, as you mention, nested functions will behave yet > differently. All of this looks really bad. > > So IMHO, the real problem is that there are two distinct concepts: > assigning a new value to an existing binding, and creating a new > binding, possibly with an initial assignment. These are separate things > and mixing the two in such ways is wrong, and also quite surprising, > knowing the lispy side of this language. > > > > Footnotes: > [1] consider that a simple typo in your code may lead to silently > creating a new variable, which will never be used. > > -- > ELS'16 registration open! http://www.european-lisp-symposium.org > > Lisp, Jazz, Aïkido: http://www.didierverna.info >
Re: [julia-users] scoping wat
Maurowrote: > Maybe you can be a bit more explicit in what you mean, examples would > help too. Sorry for the fuzziness. This is an example of what I mean: let x = 10 end here, the same expression "x = 10" will either assign a new value to x if such a /global/ exists, or create a new /local/ binding. This is already bad enough[1]. Then, begin/end behaves differently. Then, "if" doesn't introduce a new block, but some others constructs do, and some don't. And then, some like "for" do or don't, it depends. Now even worse: x = 10 function foo() println(x) x = 5 println(x) end will break on the first println (one could expect to get 10, the global value for x) because since there is an assignment /later on/, a new /local/ binding will be created for x (which BTW is the exact opposite of what let does!), but this binding isn't available to the first println. And also, since a variable cannot switch from global to local (or vice-versa) in the same block, the intuition (well, mine anyway ;-)) that after the assignment, the scoping changes, is wrong. And then, as you mention, nested functions will behave yet differently. All of this looks really bad. So IMHO, the real problem is that there are two distinct concepts: assigning a new value to an existing binding, and creating a new binding, possibly with an initial assignment. These are separate things and mixing the two in such ways is wrong, and also quite surprising, knowing the lispy side of this language. Footnotes: [1] consider that a simple typo in your code may lead to silently creating a new variable, which will never be used. -- ELS'16 registration open! http://www.european-lisp-symposium.org Lisp, Jazz, Aïkido: http://www.didierverna.info
Re: [julia-users] scoping wat
Maybe you can be a bit more explicit in what you mean, examples would help too. The only bit of the scoping rules which I find a bit questionable is that functions in a local scope have soft-scope (otherwise they have hard-scope). This has been discussed on github, search for "nonlocal". On Tue, 2016-04-12 at 11:16, Didier Vernawrote: > Hi, > > I'm quite puzzled by the complication of Julia's scoping rules, and in > particular this way of constantly and implicitly mixing binding and > assignment, with varying semantics according to the context. > > The manual is not convincing (at least to me) in justifying what's > happening. Most of the scoping behavior looks like a big DWIM machinery > which is evil. > > What's the history behind all this? Technical debt? Inspiration from > other languages (certainly not Scheme!)? Actual, arbitrary design > decisions? > > Thank you!
[julia-users] scoping wat
Hi, I'm quite puzzled by the complication of Julia's scoping rules, and in particular this way of constantly and implicitly mixing binding and assignment, with varying semantics according to the context. The manual is not convincing (at least to me) in justifying what's happening. Most of the scoping behavior looks like a big DWIM machinery which is evil. What's the history behind all this? Technical debt? Inspiration from other languages (certainly not Scheme!)? Actual, arbitrary design decisions? Thank you! -- ELS'16 registration open! http://www.european-lisp-symposium.org Lisp, Jazz, Aïkido: http://www.didierverna.info