Absolutely – I didn't want to get into correct/incorrect when I implemented @with but I definitely think the
@with Foo::(a, b) syntax is preferable. I think I'll disable the type syntax, add support for indexing and then send a PR to see if there's any chance of having it in Base. (Personally I think the type syntax could be acceptable if used very sparingly and only where it has significant benefit – e.g. for a very large config object that's used in many places. But I do agree that such a construct wouldn't be best placed in Base.) On 13 June 2014 15:25, Stefan Karpinski <[email protected]> wrote: > 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. >>>>>> >>>>> >> >
