On Thu, Jul 21, 2016 at 11:37 PM, Cedric St-Jean <[email protected]> wrote:
> Neat macro. > > >> For this though, my macro needs to somehow figure out that "inc" was also >> defined with @self (since it shouldn't blindly add self as a first arg so >> other non-@self'ed function calls). Is this possible in Julia? >> > > You could have a global Set that would contain the names of the functions > that were defined with @self. But IMO this is going to bite you at one > point or another. > Yea certainly a possibility, although even this doesn't seem that robust since you're only doing this based on function name, and you don't know if its referring to a different function in any given call environment. I'm starting to doubt its truly possible at compile time, although still thinking.... > > FYI Mauro's package has something similar > <http://parametersjl.readthedocs.io/en/latest/manual/>. > Some interesting stuff in there, thanks! > > I would suggest using a global variable, if you want to avoid explicitly > passing `self` all over the place. It would look like this: > > const self = Array{mytype}() # trick to avoid the globals' poor > performance > > @self function foo() > x = x + 1 # expands into self[].x = self[].x + 1 > end > > @with_self(mytype(200)) do > # expands into > # try > # ... save the current value of self > # global self[] = mytype(200) > # ... code > # finally > # global self[] = ...restore previous value > # end > ... > end > > I used this idiom in Common Lisp all the time. It's strictly equivalent to > passing the object around to every function, and doesn't break the > "functionalness" of the code. > > Cédric > > > On Thursday, July 21, 2016 at 4:01:20 PM UTC-4, Marius Millea wrote: >> >> In an attempt to make some numerical code (ie something thats basically >> just a bunch of equations) more readable, I am trying to write a macro that >> lets me write the code more succinctly. The code uses parameters from some >> data structure, call it "mytype", so its littered with "t.a", "t.b", etc.. >> where t::mytype. My macro basically splices in the the "t." part for me. >> Its kind of like how C++ member functions automatically access the class's >> fields, as an example. To my amazement / growing love of Julia, I actually >> managed to hack it together without too much difficulty, it looks like this, >> >> >> macro self(func) >> @assert func.head == :function >> >> # add "self" as a first function argument >> insert!(func.args[1].args,2,:(self::mytype)) >> >> >> # recurse through AST and rename X to self.X if >> # its a fieldname of mytype >> function visit(ex) >> if typeof(ex) == Expr >> ex.args = map(visit,ex.args) >> elseif (typeof(ex) == Symbol) & (ex in fieldnames(mytype)) >> return :(self.$ex) >> end >> ex >> end >> func.args[2] = visit(func.args[2]) >> >> show(func) # print the edited function so we can see it in action >> >> :($(esc(func))) >> end >> >> >> >> >> Here it is in action: >> >> > @self function inc() >> x = x + 1 >> end >> >> >> :(function inc(self::mytype) >> self.x = self.x + 1 >> end) >> >> >> inc (generic function with 1 method) >> >> >> >> >> > inc(mytype(0)) >> 1 >> >> >> >> where I'm assuming I've defined mytype as >> >> type mytype >> x >> end >> >> >> >> As you can see, all it did was add self::mytype as an arg and replace x >> with self.x everywhere it found it. This is also super nice because there >> is zero run-time overhead vs. having written the "self." myself, everything >> happens compile time. >> >> Now for the question. I'd like to also to be able automatically pass the >> "self" argument to functions, so that I could write something like, >> >> @self function inc2() >> inc() >> inc() >> end >> >> >> >> and it would produce >> >> function inc2(self::mytype) >> inc(self) >> inc(self) >> end >> >> >> >> For this though, my macro needs to somehow figure out that "inc" was also >> defined with @self (since it shouldn't blindly add self as a first arg so >> other non-@self'ed function calls). Is this possible in Julia? I suppose >> somehow the macro must access the global scope where the expression is >> being evaluated? I'm not entirely sure that's doable. I'm happy to take any >> tips how to achieve this though, especially ones incurring minimal overhead >> for the rewritten function. Thanks! >> >>
