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