I’m coming from Python, attempting to build a Julia equivalent of huggingface/knockknock
. Briefly: KnockKnock decorates Python functions notifying you when said functions begin execution and fail/complete execution. My goals are approximately the same, just with Julia. (I realize this is attempting to use @macro
s as @decorator
s, and that they are distinct ideas with differing goals.)
Questions
- Can
@macro
s modify the function body, define the function, and return said function – but with the redefined body without needing to define a custom function? (One of my many attempts appears to fail at this.) - “Meta question”: Would achieving the above present capability issues with chaining macros? (From my own searching, I’ve vaguely grasped “yes”.)
- If so, would instead creating a syntax of…
@knockknock <messaging-client> func()
at-all sidestep this? (<messaging-client>
would be something likeTelegram
or whatever else.)
- If so, would instead creating a syntax of…
Attempting to produce a @macro
that does (1)
The general problems I’ve run in to are the following:
- KnockKnock-specific functions are executed when defining functions, instead of at run-time of the function.
- When modifying the function definitions (i.e.
def[:body]
), I seem unable to actually “define” the function in Julia such that callingfoo(bar; baz=12)
actually works.
Of the many variants I’ve tried, I believe this snippet generally represents what I’m trying to do:
macro knockknock(func::Expr)
def = MacroTools.splitdef(func)
body = def[:body]
def[:body] = quote
# KnockKnock specific function, properly imported
local t0 = setup(def)
# Your function body (which is represented as a `quote ... end`)
local retval = $body
# KnockKnock specific function, properly imported
local (t1, tt) = teardown(def, t0, retval)
return retval
end
func = MacroTools.combinedef(def)
quote
$func
end
end
Then using something equivalent to this:
@knockknock function test()
println("sleeping...")
sleep(10)
println("...done.")
end
Running the above prints the output of setup
and teardown
. Then, running test()
produces an UndefVarError
(in the REPL is you’ll receive something like #32#test (generic function with 1 method)
).
I’ve been basing much of this off the @gen
macro from Gen.jl
. Following it’s execution leads me to this, which appears to use quote ... end
to define the original function, then Gen
’s DynamicDSLFunction
. The main caveat here is that the DynamicDSLFunction
needs to be run through Gen
’s library functions which seem to use dispatch to call the DynamicDSLFunction
variant (which seems undesirable given my goals are to make usage require minimal changes to existing code (and not require knowing much about how the function is executed)).