Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"fake" multiple dispatch for different expression types in macros #20929

Open
ExpandingMan opened this issue Mar 7, 2017 · 10 comments
Open

"fake" multiple dispatch for different expression types in macros #20929

ExpandingMan opened this issue Mar 7, 2017 · 10 comments
Labels
kind:speculative Whether the change will be implemented is speculative

Comments

@ExpandingMan
Copy link
Contributor

It would be really cool if one could do something like

macro m(expr::ExprHeadType{:call,:(=)})
    f(expr)
end

macro m(expr::ExprHeadType{:block})
   g(expr)
end

which would be equivalent to

macro m(expr)
    if expr.head  [:call, :(=)]
        return f(expr)
    elseif expr.head  [:block]
        return g(expr)
    else
        throw(ArgumentError("You gave me an expression I don't recognize."))
    end
end

(of course we should think of a better name than ExprHeadType). Of course, this would have to then require that the expr argument be an Expr rather than a Symbol or literal. Any macros that aren't written with ExprHeadType would behave normally.

Additionally, it would be nice to be able to dispatch functions on expression types (mainly for the purpose of helping macros), sort of like it's currently possible to do with specific values using Val. (I don't think that's a crazy extrapolation from current behavior, but I know very little about the compiler.)

Is this completely crazy from a compiler perspective, or something people might be interested in?

@yuyichao yuyichao added the kind:speculative Whether the change will be implemented is speculative label Mar 7, 2017
@quinnj
Copy link
Member

quinnj commented Mar 7, 2017

I'm pretty sure I remember this being brought up before and people thought it was a good idea. I also know there's been talk of "finalizing" our AST/Expr representation for 1.0 as well.

@StefanKarpinski
Copy link
Sponsor Member

StefanKarpinski commented Mar 7, 2017

This would largely rely on changing the AST representation to a more type-based one, where instead of using Expr everywhere with different values for the .head field, we use different types to represent different syntax nodes with specific structures. This would be a fairly disruptive change, but if we're going to do it, before 1.0 is certainly the time to do so. Now that macros can do dispatch (it's real dispatch, btw, just on ASTs), it would also allow writing some transformations more concisely and conveniently.

@ararslan ararslan added the domain:types and dispatch Types, subtyping and method dispatch label Mar 7, 2017
@bramtayl
Copy link
Contributor

bramtayl commented Mar 7, 2017

Going further, there could even be fully typed trees, like:

ForExpr.iterator
IfExpr.condition

@ExpandingMan
Copy link
Contributor Author

Going further, there could even be fully typed trees, like:

ForExpr.iterator
IfExpr.condition

I would be very worried that that sort of thing would make symbolic manipulation too complicated. You'd have to remember or look up the fields for every possible type of expression. I think using head and args makes it pretty easy to infer what the structure of an expression will look like, it just gets really annoying sometimes to have to write big ugly conditional constructs to identify the heads. (And it seems somehow "anti-Julian"!)

@bramtayl
Copy link
Contributor

bramtayl commented Mar 7, 2017

I can see how it might be an issue to iterate. Maybe a dict? IfExpr.args[:condition] for example

@JeffBezanson
Copy link
Sponsor Member

This is the kind of thing pattern matching is good for.

@JeffBezanson
Copy link
Sponsor Member

What I mean is that while dispatching on expression heads is somewhat useful, you need to be able to match on full tree structures to get any real benefit. Expression structures are also very flexible and dynamic, so they are not a great fit for the design assumptions of our multiple dispatch. This kind of programming really demands a feature that converts a series of tree patterns to a nest of if statements. Such an approach also makes it easier to change the representation of expressions, since you only need to change the pattern compiler.

@ExpandingMan
Copy link
Contributor Author

ExpandingMan commented Mar 8, 2017

I've found #12102 which seems to be a suggestion that pattern matching for expressions be included in Base. The result seems to be that the poster wrote the MacroTools package which seems to still be actively maintained.

I find it interesting that most of the discussion in that post is about users not necessarily being knowledgeable about the AST. Personally, I find that to be a very small issue, I simply use the REPL to check what the heads of various expressions are, and usually the args are pretty obvious. Actually writing the macro code once I know exactly what I need to do is what I'm still finding slightly awkward.

@ExpandingMan
Copy link
Contributor Author

It seems that this has now effectively been implemented through Val, though this cannot directly be used in macro definitions.

Maybe I'm crazy but I could have sworn that at some point Val was not working for Symbols. However, now it does. My original example becomes

h(::Union{Type{Val{:call}},Type{Val{:(=)}}}, expr) = f(expr)
h(::Type{Val{:block}}, expr) = g(expr) 

macro m(expr)
    h(expr.head, expr)
end

It's not beautiful, but it's certainly an improvement.

Is there some simple way of using Val to allow macros declarations to behave as if they're dispatching on expression types?

@vtjnash
Copy link
Sponsor Member

vtjnash commented May 3, 2017

Is there some simple way of using Val to allow macros declarations to behave as if they're dispatching on expression types?

Use a real pattern-matching library (like the previously mentioned MacroTools package)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

8 participants