Heavy macro use or not?

Makes me wonder if a Terse.jl package would be worthwhile; exporting things like a little, boilerplate-reducing @singleton macro:

function f(@singleton(MY_CONST::MyType), x)
  println("Can I even do this in function arg scope?")
end
# expands the @singleton arg to `::MyType` and evals the below in module scope:
struct MyType end
const MY_CONST = MyType()

I kind of miss these kind of conciseness-affordance macros from lisps.

1 Like

As an educator I am against macros because they are a fundamentally more advanced concept than typical programming that most academics would be familiar with. As a developer, I realize that macros are a powerful feature of the language that can be beneficial when used correctly. But they can be brutally hard to code and debug :frowning: I still dont know how to write macros after 8 years of using the language.

However, I always, absolutely, without any shadow of a doubt, am 100% against using macros when a function would do exactly the same thing with the same level of code complexity.

6 Likes

The @lift macro in Makie and the DataFramesMeta macros do the same thing, they let you write an expression that resolves to a function, where otherwise you’d have to write each variable at least three times. Once as an input to the function, once as an argument, and once in the function body.

@lift $observable_a + $observable_b + 10
# is equivalent to
lift(observable_a, observable_b) do obs_a, obs_b
    obs_a + obs_b + 10
end

Vanilla DataFrames can be quite verbose due to this

3 Likes

When I was working on DuckDispatch.jl, I realized that the user would need to define multiple copies of each of the required methods for a new DuckType. One for fallback, and one that unwraps the DuckType wrapper can calls the original function. It also has a reasonably complex syntax for declaring the supertype of a new DuckType and that supertype needs to match the methods you made exactly. Then, there is a whole other set of functions that you need to define if you want to dispatch on a DuckType.

A declarative DSL driven by macros allows me to make sure all of that is synced up and throw informative errors if the user messes something up.

I plan to document exactly what the macros are producing and make all of it public, but I would see it as highly inadvisable to circumvent the macro API.

2 Likes

Base already exports macros heavily, e.g. with @inbounds, @enum , @view, @.

There are packages which wouldn’t make much sense without a macro interface, e.g. Match.jl, MLStyle.jl, Accessors.jl, ArgParse.jl, JuMP.jl.

I’m a bit bothered by the fact that macros don’t compose well and there’s no plan to fix this issue.