Keno's example showed how a simple error like forgetting that you had assigned to `a` would cause problems, but it's even worse – that's just a matter of making an error about the current state of the program. It's worse than that though: if someone adds a field to a type that is used *anywhere* with such a `using` construct, that code becomes incorrect. The fundamental problem with this construct is that it makes it locally impossible to reason about what it means when you access or assign a binding. Let's say I have this code:
function foo(x::Bar) using x a = b + 1 end What does this mean? b could be a global variable or a field of x; a could be a local variable or a field of x. Without knowing the structure of Bar, we can't know. In Julia, we never does this: you can always tell the meaning of code from purely local syntactic analysis. The code may be wrong – you might try to access or assign a field that doesn't exist, but there is only one thing your code could mean. For the same exact reasons, I wouldn't accept a macro that simulates this into base – it has the exact same problems. The only way to make this acceptable is if can be locally disambiguated what the code means. You could, for example, do something like this: function foo(x::Bar) using x: a, b a = b + 1 end Now you can immediately tell that `a` and `b` are both fields of `x` and not global or local variables (not by accident, this is independent of the definition of Bar). On Thu, Jun 12, 2014 at 7:40 AM, Jameson Nash <[email protected]> wrote: > > Having the local keyword like it is makes most sense to me, but I > suppose it isn't a big deal to me that if you don't explicitly specify > local you could be referring to something outside the current scope, which > is the case with for loops. > > Javascript does this. It also has the "using" block that you describe (see > "with"). They are probably the worst (mis)features in the entire language. > In the latest version of javascript, it has finally been removed, to the > relief of javascript programmers everywhere: > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode > . > > I would be interested in having a language feature akin to visual basic's > with block, since it is only a trivial source transform to annotate each > `.` with the result of the expression in the nearest `with` block. > function f(A) > with A > .c = .a + .b > end > end > However, since this only saves a one character, it really isn't worthwhile. > function f(A) > Z = A > Z.c = Z.a + Z.b > end > > > On Thu, Jun 12, 2014 at 6:14 AM, Mike Innes <[email protected]> > wrote: > >> Ok, managed to have a quick go at this – source with some examples: >> >> https://gist.github.com/one-more-minute/668c5c7cdd8fd8b81d35 >> >> Currently it does nothing to avoid the issue Keno pointed out, but in >> principle you could throw an error when the mutating version is used >> without explicit types. >> >> If there's any interest in having this in Base you're welcome to it, >> otherwise I'll probably just clean it up and store it in Lazy.jl. >> >> >> On Thursday, 12 June 2014 09:44:30 UTC+1, Andrew Simper wrote: >>> >>> Brilliant Mike! This is exactly what I was after, I just want a way to >>> write shorthand names for things within a scope, and the @with macro does >>> just that :) In the example I posted I split the coefficients away from the >>> state so that only the state needs to be returned, I think this is good for >>> efficiency. I'll have a play with @with and see how I go. Passing in names >>> (Typename), isn't a problem, since when a new name is added there is no >>> duplication in doing this. >>> >>> Keno, sorry for not understanding that this is probably what you meant >>> when you said this would be best off done by using macros, I didn't think >>> of enclosing the entire algorithm in a macro. >>> >>> On Thursday, June 12, 2014 4:21:58 PM UTC+8, Mike Innes wrote: >>>> >>>> FWIW – putting to one side the question of whether or not this is a >>>> good idea – it would be possible to do this without new language syntax. >>>> However, you'd have to either pass a type hint or be explicit about the >>>> variables you want: >>>> >>>> e.g. >>>> >>>> function tick(state::SvfSinOsc, coef::SvfSinOscCoef) >>>> @with state::SvfSinOsc, coef::SvfSinOsc >>>> # or >>>> @with state (ic1eq, ic2eq) coef (g0, g1) >>>> >>>> lv1 = g0*ic1eq - g1*ic2eq >>>> lv2 = g1*ic1eq + g0*ic2eq >>>> SvfSinOsc(2*v1 - ic1eq, 2*v2 - ic2eq) >>>> end >>>> >>>> This would work in the non-mutating case by calling names() on the type >>>> and making appropriate variable declarations. >>>> >>>> You could then go further and implement >>>> >>>> function tick(state::SvfSinOsc, coef::SvfSinOscCoef) >>>> @with state (ic1eq, ic2eq) coef (g0, g1) begin >>>> >>>> lv1 = g0*ic1eq - g1*ic2eq >>>> lv2 = g1*ic1eq + g0*ic2eq >>>> SvfSinOsc(2*v1 - ic1eq, 2*v2 - ic2eq) >>>> end >>>> end >>>> >>>> Which would walk over the expression, replacing `a` with `Foo.a`. >>>> However, it would be tricky to implement this correctly since you'd have to >>>> be aware of variable scoping within the expression. >>>> >>>> I may implement the non-mutating version of this at some point – it >>>> seems like it could be useful. >>>> >>>> >>>> On Thursday, 12 June 2014 08:21:42 UTC+1, Andrew Simper wrote: >>>>> >>>>> On Thursday, June 12, 2014 2:16:30 PM UTC+8, Andrew Simper wrote: >>>>>> >>>>>> It seems that the local keyword is a bit of a language kludge to me, >>>>>> since it is implied in most cases, apart from stating the new scope in >>>>>> the >>>>>> form of a for loop etc. It would seem more natural and consistent to me >>>>>> to >>>>>> add the local keyword in front of all variables you want to be local in >>>>>> scope, and everyting else is global. This line of reasoning I'm sure has >>>>>> already been argued to death, and obviously having an implicit local was >>>>>> decided to be best. >>>>>> >>>>> >>>>> Having the local keyword like it is makes most sense to me, but I >>>>> suppose it isn't a big deal to me that if you don't explicitly specify >>>>> local you could be referring to something outside the current scope, which >>>>> is the case with for loops. >>>>> >>>> >
