Not by default, but it should be simple enough (and correct, I think) to just call macroexpand on macro calls.
macro test(expr) (expr,) end (@test @foo x) == (:(@foo x),) All I meant about the let binding is that the mutating version expands to: let a = Foo.a # code Foo.a = a end AFAIK let bindings have a small overhead (compared to a normal declaration), so if a redundant assignment is a significant overhead in your code then using the let binding will be prohibitive anyway. I haven't particularly tested that, though, so the situation could have changed recently. On 13 June 2014 14:59, David Moon <dave_m...@alum.mit.edu> wrote: > [I can't get this damned thing not to include a quote of all previous > messages. I guess it only works in Google Chrome; what a pain. So sorry > about the unnecessarily long post.] > > In the argument to a macro all nested macro calls are already expanded, I > think. It's certainly true that for complete correctness you would need to > handle shadowing of the bindings introduced by atsign-with by local > bindings of the same name. It's even more true that Julia does not provide > any assistance in processing Expr's and other AST objects, nor even much > documentation, so far as I know. > > I don't understand your comment about the overhead of the let binding used > by the mutating version of the macro. What extra overhead is that? > > On Friday, June 13, 2014 3:57:07 AM UTC-4, Mike Innes wrote: >> >> That was my first thought, too – and it's fine in principle, but remember >> for that macro to be correct you'd have to handle let bindings, quoting, >> local variable declarations and expanding any macros that might result in >> these, then test all of those things carefully to make sure it's working >> correctly. >> >> Plus, if the overhead of unnecessary writes is an issue, so will be that >> of the let binding used by the mutating version of the macro. This again is >> probably solvable, but for all that effort you could just use the faster >> non-mutating version and store a couple of changes by hand. >> >> That's not meant to put off anyone who wants to have a go at this, just >> warning that it wouldn't be as trivial as it sounds. >> >> On Friday, 13 June 2014 02:01:28 UTC+1, David Moon wrote: >>> >>> Mike Innes' atsign with macro is good, but it would be better if it >>> would iterate over the AST for its last argument and replace each >>> occurrence of "field" with "obj.field". That way there wouldn't be any >>> unexpected assignments to fields which were not actually changed, and in >>> general no wasted motion at run time. The macro would be a little more >>> complex to write but it should not be very difficult. >>> >>> On Thursday, June 12, 2014 6:14:15 AM UTC-4, Mike Innes 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. >>>>>>> >>>>>> >>> On Thursday, June 12, 2014 6:14:15 AM UTC-4, Mike Innes 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. >>>>>>> >>>>>>