On Thu, Jul 21, 2016 at 7:02 PM, Marius Millea <[email protected]> wrote:
>
>
> 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....
No it's not.
>
>
>
>>
>>
>> FYI Mauro's package has something similar.
>
>
> 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!
>>>
>