# Macros and standard evalution

**URL:** https://discourse.julialang.org/t/macros-and-standard-evalution/876
**Category:** Internals & Design
**Created:** [December 12, 2016, 12:59am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876 "2016-12-12T00:59:07Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 12, 2016, 12:59am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/1 "2016-12-12T00:59:07Z")

</div>

I’ve been using this in ChainMap for a while, inspired by hadley’s non-standard evalutation paradigm.

Imagine a function

```julia
function binary(a, b, c)
    Expr(:call, b, a, c)
end

```

I’ve been using a macro called `@nonstandard` to generate the code below automatically:

```julia
@nonstandard binary
# expands to
macro binary(es...)
    binary(es...)
end

```

Which means you could then do stuff like

```julia
[1, 2] == @binary 1 vcat 2

```

But it seems like you could skip the this whole process altogether, including the macro definition, simply by having `@binary` simply always refer to the `binary` function.

Advantages:  
All macros would be also available as standard evaluation functions. You could use them for mapping, reducing, etc.  
(Less) macroexpand debugging!  
More intuitive, at least for me.

Disadvantages:  
Might require shuffling around the namespace. For example, `@time` and `time` both exist in Base, I think.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [December 12, 2016, 1:25am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/2 "2016-12-12T01:25:56Z")

</div>

What are you proposing?  
It’s a bad idea to make macro and functions to point to the same code since they almost never do exactly the same thing.

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 12, 2016, 1:42am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/3 "2016-12-12T01:42:26Z")

</div>

Sorry if I wasn’t clear. I’m not sure if I’m using the right vocabulary here.

So basically, if I define

```julia
function binary(a, b, c)
    Expr(:call, b, a, c)
end

```

Then, without any extra steps,

```julia
[1, 2] == @binary 1 vcat 2

```

Basically, in this case, `@f` is syntax for during parse time, bring arguments in as expressions, pass to `f`, then insert the resulting expression into the code. Named macros wouldn’t exist anymore.

For my purposes, it’s almost always useful to have access to the standard evaluation version of a macro.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [December 12, 2016, 1:57am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/4 "2016-12-12T01:57:53Z")

</div>

Correct, that’s exactly what I said is a bad idea.

> [@bramtayl](#):
>
> All macros would be also available as standard evaluation functions. You could use them for mapping, reducing, etc.

This is rarely useful. Definitely not in public API, rarely in internal APIs. Even then, most of the time, just emitting the call to another macro is enough.

> [@bramtayl](#):
>
> (Less) macroexpand debugging!

What’s wrong with `macroexpand`? With `@macroexpand` there’s even less to type. Printing in the macro should also work on 0.5 and master.

> [@bramtayl](#):
>
> More intuitive, at least for me.

Quite the opposite. The `macro` at definition time is a clear signal that the function is meant to generate expression, which is rarely the case for a normal function (I doubt any public API functions can be used as a valid and meaningful macro). Similarly, related to this point but unrelated to the proposal, the `@` at runtime clearly signals custom syntax.

> [@bramtayl](#):
>
> Might require shuffling around the namespace. For example, @time and time both exist in Base, I think.

This essentially means that the change is undoable. Again, I don’t know a single case where a public function and a public macro share the exact same implementation.

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 12, 2016, 2:08am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/5 "2016-12-12T02:08:56Z")

</div>

Hmm. Ok, I see what you’re saying about this not being useful for a lot of users (who aren’t doing meta programming). Now that I think about it, though, at least the time issue could be handled using multiple dispatch (defining a method for ‘time(e::Expr)’ )

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [December 12, 2016, 2:18am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/6 "2016-12-12T02:18:37Z")

</div>

> [@bramtayl](#):
>
> defining a method for ‘time(e::Expr)’

No it can’t. `@time a` or `@time 1.0` is perfectly valid and should continue to be. You can of course try to add all kinds of signatures to either but then you should realize that the two has nothing to do with each other and shouldn’t conflict in the first place.

> [@bramtayl](#):
>
> not being useful for a lot of users (who aren’t doing meta programming)

I never find it useful when doing meta-programming. Apart from the small saving of typing of `macroexpand`, if you are calling macros as functions a lot in your code, it may suggest that you are not using macros correctly. e.g. in all cases I can think of you can just use `@binary` directly in another macro that uses it. (FWIW, your `binary` is not a hygienic macro)

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 12, 2016, 2:44am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/7 "2016-12-12T02:44:42Z")

</div>

Hmm. I think we’re talking past each other?

If the code from `macro time` gets moved over to `time(e)`, then `@time a` and `@time 1.0` will continue to be valid, I think? `time()` could continue to return the current time.

The macroexpand was more of a bonus, but imagine, instead of  
`macroexpand(:(@time a) )`  
you could just do  
`time(a)`

Here’s an example of how you might want to reuse `binary`.

```julia
function map_macro(e)
    Expr(:call, :map, e.args...)
end

```

```julia
function map_binary(es...)
    map_macro(binary(es...) )
end

```

I also wasn’t suggesting ending hygiene scrubbing. Unless I’m confused, it would work perfectly well in this proposal to have `@f` scrub the results of `f` for hygiene, unless there was an `esc` in the expression f returns.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [December 12, 2016, 3:14am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/8 "2016-12-12T03:14:27Z")

</div>

> [@bramtayl](#):
>
> time(e)

This isn’t the signature you posted before. And `@eval @time $(...::TmStruct)` should still be valid too.

> [@bramtayl](#):
>
> you could just do `time(a)`

It actually looks pretty terrible and won’t work, you still need to quote `a`. `@macroexpand @time a` is pretty clean and requires no quoting so it’ll be much cleaner for any non-trivial input expressions.

> [@bramtayl](#):
>
> map\_macro(binary(es…))

The reason this is bad is because you are constructing a valid macro return and then parse it again in another function. It’ll be very unclear for the reader what expectation you have on both macro/functions since there are trivial changes that’s valid for a normal macros that aren’t valid for these anymore (e.g. `binary` cannot just have an overall `esc` and `map_macro` has to accept `esc` as input which a normal macro never does).

---

<div class="post-metadata">

### Author: ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)
#### Post date: [December 12, 2016, 4:30am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/9 "2016-12-12T04:30:10Z")

</div>

I would encourage you to spend a few weeks reading the literature on [Fexpr](https://en.wikipedia.org/wiki/Fexpr)’s to learn why the majority of the Lisp community decided that Lisp’s now-eradicated equivalent of R’s non-standard evaluation was a bad feature in programming languages. Particularly worth reading is Kent Pitman’s paper on [“Special Forms in Lisp”](http://www.nhplace.com/kent/Papers/Special-Forms.html), which features this very important section:

> In this paper, the motivations for using special forms are discussed, followed by a summary of the advantages and disadvantages of employing MACRO’s, FEXPR’s, and NLAMBDA’s as tools for their implementation. It is asserted that MACRO’s offer an adequate mechanism for specifying special form definitions and that FEXPR’s do not. Evidence is given which supports the author’s contention that FEXPR’s interfere with the correct operation of code-analyzing programs such as the compiler. Finally, it is suggested that, in the design of future Lisp dialects, serious consideration be given to the proposition that FEXPR’s should be omitted from the language altogether.

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 13, 2016, 6:18am UTC](https://discourse.julialang.org/t/macros-and-standard-evalution/876/10 "2016-12-13T06:18:11Z")

</div>

Great! Thanks for the helpful article. I’m not sure I understand it, and I’m also not sure what I was proposing corresponds exactly to Fexpr (in fact, non-standard evaluation might be a misnomer), but I am glad someone smarter than me has thought about this thoughtfully.
