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] 
> <javascript:>> 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