But wait – if you don't assign things back at the end, how is this
different than just assigning to a local variable?


On Fri, Jun 13, 2014 at 7:07 PM, Stefan Karpinski <[email protected]>
wrote:

> Using a block seems like the right way to handle that.
>
>
> On Fri, Jun 13, 2014 at 7:04 PM, Carlo Baldassi <[email protected]>
> wrote:
>
>> 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 <[email protected]>
>>> 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 <[email protected]> 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 <[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 implie
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>
>

Reply via email to