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
>>>>>>>
>>>>>>>  
>>>>>>
>>>>>  
>

Reply via email to