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!

Reply via email to