No, that's the main annoyance admittedly, even though I find that most of the time I need to just read the values (or get a pointer to a mutable container which gets updated anyway). For that, one would either need to enclose everything in a block as in the @with macro and do some more magic (but this has problems of its own, and I'm particularly wary of unnecessary performance losses) or more simply have a mirror/sister macro to add at the end, I suppose. Up to now, I haven't really felt the need for that and therefore haven't implemented it.
On Saturday, June 14, 2014 12:50:10 AM UTC+2, Stefan Karpinski wrote: > > Does your @extract macro somehow assign values back to fields at the end > of the scope? > > > On Fri, Jun 13, 2014 at 5:29 PM, Carlo Baldassi <carlob...@gmail.com > <javascript:>> wrote: > >> The point would be that it's not different, just more concise, so you're >> still in control of what you're doing and don't risk braking code when >> changing a type etc.; e.g. this is one typical function from some code I'm >> using: >> >> function foo(network::Network, i::Int) >> @extract network N H0 lambda state=current_state Ji=unsafe(J[i]) >> @extract state S s=unsafe(s) >> return dot(Ji, s) - H0 - lambda * (S - 0.5 * N) >> end >> >> which would be: >> >> function foo(network::Network, i::Int) >> N = network.N >> H0 = network.H0 >> lambda = network.lambda >> state = network.current_state >> Ji = unsafe(network.J[i]) >> S = state.S >> s = unsafe(state.s) >> >> return dot(Ji, s) - H0 - lambda * (S - 0.5 * N) >> end >> >> I just think the @extract version is clearer and more maintainable. >> Repeated across lots and lots of small functions, it means a consistent >> reduction in lines of code, and I think it allows to visually focus on the >> actual functionality rather than on the boring stuff. Also, adding more >> fields at the end of an @extract line is nicer when you change the fields >> of a type a lot (another typical situation I found myself into a lot is >> having a composite type which is just used to pass around tons of >> parameters, and having to extract them all whenever I use them). >> >> Anyway, so far I never actually thought of proposing inclusion into Base >> or even registering a package, but in the span of two days this thread came >> up and a coworker asked me for exactly this kind of thing (since he also >> was becoming annoyed by the long lists of assignments at the beginning of >> each function), so if someone likes the syntactic sugar the functionality >> is basically there. >> >> >> >> On Friday, June 13, 2014 10:45:44 PM UTC+2, Stefan Karpinski wrote: >> >>> How is this different than just assigning fields to local variables? >>> >>> On Friday, June 13, 2014, Carlo Baldassi <carlob...@gmail.com> wrote: >>> >>>> Sorry for spamming, but after reading the discussion it seems like a >>>> (slightly polished) version of the @extract macro I mentioned above (I >>>> know >>>> the name is not great) already basically does that and a bit more, IIUC >>>> the >>>> discussion here. Some more examples and documentation are in the code at >>>> https://github.com/carlobaldassi/MacroUtils.jl/ >>>> blob/master/src/Extract.jl >>>> >>>> The nice thing (I think) about it is that if you have two objects of >>>> the same kind you can assign different names to the variables you use to >>>> refer to their fields, and even apply functions, e.g. say you have >>>> >>>> type Foo >>>> a::Int >>>> b::Vector{Float64} >>>> end >>>> >>>> you can do things like: >>>> >>>> function bar(f1::Foo, f2::Foo) >>>> @extract f1 a1=a b1=b >>>> @extract f2 a2=a b2=b >>>> >>>> # do stuff with a1,b1,a2,b2 instead of f1.a,f1.b,f2.a,f2.b >>>> end >>>> >>>> or even: >>>> >>>> function baz(f::Foo, i::Int) >>>> @extract f a bi=b[i] >>>> >>>> # do stuff with a and bi instead of f.a and f.b[i] >>>> >>>> @extract f b=unsafe(b) >>>> >>>> # do risky stuff with b >>>> end >>>> >>>> etc. (It may be even somewhat too fancy). >>>> >>>> Anyway, I happen to use that macro a lot in my code. >>>> >>>> >>>> >>>> On Friday, June 13, 2014 4:53:33 PM UTC+2, Mike Innes wrote: >>>>> >>>>> 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 <ste...@karpinski.org> 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 <vtj...@gmail.com> >>>>>> 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 <mike.j...@gmail.com> >>>>>>> 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 implie >>>>>>> >>>>>>> >>>>>> >>>>> >