# How to discourage macros: disable automerge of General registry PRs?

**URL:** https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529
**Category:** Internals & Design
**Tags:** macros, metaprogramming, general-registry, macro-hygiene
**Created:** [October 3, 2023, 8:43am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529 "2023-10-03T08:43:31Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [October 3, 2023, 8:43am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/1 "2023-10-03T08:43:31Z")

</div>

It seems to me that macros are defined much too often in the Julia ecosystem and the (error-prone) definitions of such macros are often very complex.

FWIW, the Julia Manual page on metaprogramming already heavily discourages defining macros:

> `eval` and defining new macros should be typically used as a last resort.

It seems to me that (almost?) the only good way to design a package that includes macros is like this:

1. the macro simply provides some syntax sugar over an actual Julia function, with only minimal logic used in the definition of the macro itself
2. if the macro is part of the public API, the function that the macro wraps should also be public (with `public` or `export`, in future Julia versions) and documented

Even if these rules were followed, each macro introduces its own syntax on top of Julia, causing extra cognitive load for the programmer and trouble for tooling, meaning that both macro usage and macro definition should perhaps be discouraged to a degree within public packages, even if a macro/DSL is sometimes really necessary.

One way of discouraging unnecessary definition of macros would be to disable [automatic merging](https://juliahub.com/ui/Packages/General/RegistryCI) (automerge) for General registry packages when the package includes a macro definition (perhaps with the restriction that the macro name is public instead of just internal). Another potentially good restriction would be to whitelist macros that define new string literals. @ShalokShalom suggests that it may be better to just give some kind of warning/tag.

A more conservative approach would perhaps be to only do this when the definition of the macro crosses some complexity threshold.

Are these ideas good?

---

<div class="post-metadata">

### Author: ![ShalokShalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shalokshalom/32/52462_2.png) [@ShalokShalom](https://discourse.julialang.org/u/ShalokShalom)
#### Post date: [October 3, 2023, 8:45am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/2 "2023-10-03T08:45:54Z")

</div>

Me and nsajko launched our posts simultaneously, can somebody please merge them?

> [@General Registry: Create tag for macro usage](https://discourse.julialang.org/t/general-registry-create-tag-for-macro-usage/104528):
>
> In a recent discussion about newbie friendliness, the topic about [macros](https://discourse.julialang.org/t/julia-as-first-language/104383/79) came up. Someone suggested, that it may be beneficial to prevent auto merges to the general registry, for code that uses them. I think that’s a bit too harsh. But what about creating a tag, so that we can review the PR, and possibly comment on the overuse of it? Macros are overused in nearly every language that uses them, and I think this could be a way to deal with this issue. Eventually might even the compiler be able…

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [October 3, 2023, 10:10am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/3 "2023-10-03T10:10:34Z")

</div>

> [@nsajko](#):
>
> Are these ideas good?

This seems very arbitrary. Almost any feature can be misused and punishing someone in this kind of way for using a language feature feels off.

---

<div class="post-metadata">

### Author: ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)
#### Post date: [October 3, 2023, 10:52am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/4 "2023-10-03T10:52:12Z")

</div>

We don’t even block automerge for packages that have no tests.

We don’t enforce standards at the package registry level.  
I can imagine we might start to do some basic ones, like the aforementioned tests being required,  
but I can’t imagine we will ever have the something as subjective as this in the General Registry CI tests.

---

<div class="post-metadata">

### Author: ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)
#### Post date: [October 3, 2023, 10:54am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/5 "2023-10-03T10:54:55Z")

</div>

I mostly push back on excessive macro use by using this quote from  
@stevengj 's 2019 JuliaCon keynote.

> Functions are mostly good enough for Jeff Bezanson.  
> Don’t try to outsmart Jeff Bezanson.

 ![slide conveying above information](https://global.discourse-cdn.com/julialang/original/3X/1/1/11de0eff4ec818e9ea41f7309df6f9a32c968bd4.jpeg)

Video: [https://youtu.be/mSgXWpvQEHE?t=578](https://youtu.be/mSgXWpvQEHE?t=578)

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [October 3, 2023, 11:15am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/6 "2023-10-03T11:15:19Z")

</div>

> [@nsajko](#):
>
> One way of discouraging unnecessary definition of macros would be to disable [automatic merging](https://juliahub.com/ui/Packages/General/RegistryCI) (automerge) for General registry packages when the package includes a macro definition (perhaps with the restriction that the macro name is public instead of just internal). Another potentially good restriction would be to whitelist macros that define new string literals. @ShalokShalom suggests that it may be better to just give some kind of warning/tag.
> 
> A more conservative approach would perhaps be to only do this when the definition of the macro crosses some complexity threshold.

👎

---

<div class="post-metadata">

### Author: ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)
#### Post date: [October 3, 2023, 11:19am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/7 "2023-10-03T11:19:23Z")

</div>

blocking automerge is a **very** heavy handed approach to influencing the ecosystem and creates a lot of manual work for registry maintainers. I think it should be used very sparingly, and something like defining a macro is a totally legit thing for a package to do.

IMO if you want to influence folks you need to convince them, e.g. write blog posts showing how some particular code that uses macros would be better without it (or PR such code). But your case will need to be solid to actually change someone’s mind.

---

<div class="post-metadata">

### Author: ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)
#### Post date: [October 3, 2023, 12:10pm UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/8 "2023-10-03T12:10:17Z")

</div>

To me this seems plausible, at least to mark the registration PR with a `macro` label and/or extend the the auto-merging period. [I’ve never second-guess anyone on adding a macro, also since I might not know, I have blocked some package registrations for other reasons, and occasionally look at code before registered.]

I’m not sure I agree with the phrase “punishing” users. For the user of the relevant package, it could be “punishing” to include a macro(?), not its absence (I guess the intention is though to always help the user, do you have a good counterexample?). I think Kristoffer meant punishing the user which is trying to register its package. Not doing it automatically might be taken that way, but I think it would happen anyway, at some point.

> [@oxinabox](#):
>
> We don’t even block automerge for packages that have no tests.

There’s a bit of a difference, then we are lowering the standard, _allow doing less_; we want more tests (which can be added later). We could require tests (or at least one…) maybe for 1.0 versions of a package?

But doing a macro definition is doing more.

> 1. if the macro is part of the public API, the function that the macro wraps should also be public (with public or export, in future Julia versions) and documented

I’m confused about that. Why? The macro should be exported or public (if not, no change from status quo, since only for internal use), but does it follow from it that the function should be (which is just an implementation detail?)? I don’t use macros much (not defining my own), mostly e.g. `@code_native` and I never use `code_native` directly. It is exported for some reason though.

> Another potentially good restriction would be to whitelist macros that define new string literals.

Why? It’s not very common to add such, and I guess could be discussed in each case. There’s a proposal for a new one, upper case S (for styled strings) into Julia’s Base, but it seems it will end up there, but not exported.

> [@oxinabox](#):
>
> I mostly push back on excessive macro use by using this quote from  
> @stevengj 's 2019 JuliaCon keynote.

It’s a good quote, that I note most may not be aware of, and it seems an argument for not merging so fast.

Since I don’t make my own macros, I neither do `@generated` functions (nor really taken the time to understand that concept and macro). Would that be something to restrict too (or rather)? I at least think the quote from @stevengj would apply to it equally, or even more.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [October 3, 2023, 12:48pm UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/9 "2023-10-03T12:48:40Z")

</div>

> [@nsajko](#):
>
> A more conservative approach would perhaps be to only do this when the definition of the macro crosses some complexity threshold.

This seems backwards. Unnecessary `@eval` and macros tend to simply tweak and paste the input into existing language structures. On the other hand, very useful macros can do very complicated code transformations (Accessors, BenchmarkTools, Tullio, LoopVectorization, etc), and their existence is worthy _because_ it’s not straightforward to manually write out the `@macroexpand`ed expression. And these packages tend to have restraint and only release a couple distinct macros and very similar variants. Why restrict them more than someone who forgot about parameters and higher order functions and designed 5 dozen macros that each do barely anything?

---

<div class="post-metadata">

### Author: ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)
#### Post date: [October 3, 2023, 3:38pm UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/10 "2023-10-03T15:38:26Z")

</div>

I feel like macros in Julia are a quite self-regulating _because_ they are difficult to implement. At least every time I’ve written a non-trivial macro it quickly turned into “This is really hard… Is there any way I can do this without writing a macro?”

As such, I don’t see that there is a problem with overuse of macros across the ecosystem.

Also, in [the other thread](https://discourse.julialang.org/t/general-registry-create-tag-for-macro-usage/104528), there seems to have been some confusion between _defining_ macros and _using_ macros. Difficulties with, e.g., jumping to the definition of a macro are a tooling problem (and IMO, immature tooling may be Julia’s biggest concern, but just a consequence of the language being so young), not a problem of macros per se. Certainly, macros are very much at the core of the language (`@test`, `@assert`, `@show`, `@warn`, `@printf`, …) and calling them is completely normal.

As for _writing_ macros, the warning in the manual applies, but I really don’t think we need to do anything to nudge people away from them beyond that.

> Are these ideas good?

Sorry, but no 😉

---

<div class="post-metadata">

### Author: ![ShalokShalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shalokshalom/32/52462_2.png) [@ShalokShalom](https://discourse.julialang.org/u/ShalokShalom)
#### Post date: [October 4, 2023, 2:27am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/11 "2023-10-04T02:27:56Z")

</div>

> [@goerz](#):
>
> Certainly, macros are very much at the core of the language (`@test`, `@assert`, `@show`, `@warn`, `@printf`, …) and calling them is completely normal.

Thats what the other thread is trying to convey: It might be obvious to you, but currently, there is not clear, explicit teaching, that calling macros is completely fine for everyone, and so, I think it can get confusing to people.

Lets make that distinction clear, is all what I am saying. 🙂

---

<div class="post-metadata">

### Author: ![Barget](https://avatars.discourse-cdn.com/v4/letter/b/94ad74/32.png) [@Barget](https://discourse.julialang.org/u/Barget)
#### Post date: [October 6, 2023, 6:21pm UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/12 "2023-10-06T18:21:26Z")

</div>

I’d ask a rhetorical question: who uses goto’s? No one. Because it’s (now) common knowledge to avoid spaghetti code (except in some rare cases when you absolutely know what you do). Same for “unsafe” in rust.

My point being (not an original opinion here ^^), maybe a stronger statement could be added to the documentation.

But at least, this conversation is participating in “raising the awareness”, which is always a good thing 🙂

---

<div class="post-metadata">

### Author: ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)
#### Post date: [October 6, 2023, 6:50pm UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/13 "2023-10-06T18:50:44Z")

</div>

> [@Barget](#):
>
> who uses goto’s? No one. Because it’s (now) common knowledge to avoid spaghetti code

I reject both premises. namely, that

1. nobody uses `@goto` (they do!)
2. it necessarily leads to spaghetti code (not always!)

yes you have to be careful. but Julia `@goto` only works to jump to a `@label` inside the same function anyway, so there is significantly less potential for abuse than classic `goto`

---

<div class="post-metadata">

### Author: ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)
#### Post date: [October 6, 2023, 11:55pm UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/14 "2023-10-06T23:55:34Z")

</div>

I actually used a `@goto` once. If I recall correctly, it was mainly to avoid a really long `if` block (and reduce indentation levels). Perhaps there was a better way, but I couldn’t think of one. The code for that function had lots of complicated exception handling, and I couldn’t figure out a more modular way to write it.

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [October 7, 2023, 12:26am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/15 "2023-10-07T00:26:50Z")

</div>

Using goto is the clearest way of implementing state machines.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [October 7, 2023, 12:57am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/16 "2023-10-07T00:57:34Z")

</div>

> [@adienes](#):
>
> nobody uses `@goto` (they do!)

If we get really nitpicky, early `return`s, `continue`s, `break`s, and exceptions are also one-way gotos, and some people e.g. Bertrand Meyer have considered them just as bad.

> [@adienes](#):
>
> it necessarily leads to spaghetti code (not always!)

if we get nitpicky again, all the structures we use are just the maintainable goto patterns, you can see them in the compiled code. So if we don’t neglect the provided structures, carefully using a `@goto` to do something those structures can’t (like a multi-level break) isn’t abnormal. A lot of really bad GOTO practices are prevented by `@goto` not being able to jump into or out of function bodies. However, it can jump between `let`/`if`/`begin` blocks and out of a `for` block (the REPL just dies if you try to jump into a `for` block), so the docstring saying “can’t jump between top-level statements” doesn’t describe the limitations that well.

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [October 7, 2023, 1:01am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/17 "2023-10-07T01:01:16Z")

</div>

> [@Benny](#):
>
> out of a `for` block

This is actually pretty nice. I don’t think I ever used it in Julia, but it can be useful when one wants to exit multiple nested loops at the same time. A simple `break` only exits the innermost loop.

Some languages actually have labelled breaks, that enable using `break` for this purpose (breaking out of multiple nested loops) instead of goto. Go is an example as far as I remember.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [October 7, 2023, 1:07am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/18 "2023-10-07T01:07:43Z")

</div>

It’s the go-to (different meaning, no pun intended) example of a clear and useful GOTO that typical language’s structures don’t provide. I’m honestly surprised that `break` and `continue` statements don’t typically come with an optional label (`break _label_`) or depth (`break 2`) restricted to the 1 active nested for-loop (so a `for ... function ... for ... ` is not regarded as a nested for loop because the function’s inner loop does not run by default in the outer loop).

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [October 7, 2023, 8:22am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/19 "2023-10-07T08:22:38Z")

</div>

> [@Barget](#):
>
> I’d ask a rhetorical question: who uses goto’s? No one. Because it’s (now) common knowledge to avoid spaghetti code (except in some rare cases when you absolutely know what you do). Same for “unsafe” in rust.
> 
> My point being (not an original opinion here ^^), maybe a stronger statement could be added to the documentation.
> 
> But at least, this conversation is participating in “raising the awareness”, which is always a good thing 🙂

`goto`s are not a very good analogy for macros. Instead, a better analogy would be functions (since that’s really all macros are, they’re functions that rewrite code). All the usual complaints people make about macros could be made about functions.

Maybe we should have a registry flag that discourages people from writing functions in their packages since it’s _so confusing_ and functions can lead to spaghetti code where definitions for things are all over the place and obscures what’s going on from a user!

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [October 7, 2023, 9:03am UTC](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529/20 "2023-10-07T09:03:36Z")

</div>

Well, in the end everything becomes a goto (or function call) sooner or later:

```julia
julia> function f(n)
           for i = 1:n
               println(string(i))
           end
       end
f (generic function with 1 method)

julia> @code_lowered f(2)
CodeInfo(
1 ─ %1 = 1:n
│ @_3 = Base.iterate(%1)
│ %3 = @_3 === nothing
│ %4 = Base.not_int(%3)
└── goto #4 if not %4
2 ┄ %6 = @_3
│ i = Core.getfield(%6, 1)
│ %8 = Core.getfield(%6, 2)
│ %9 = Main.string(i)
│ Main.println(%9)
│ @_3 = Base.iterate(%1, %8)
│ %12 = @_3 === nothing
│ %13 = Base.not_int(%12)
└── goto #4 if not %13
3 ─ goto #2
4 ┄ return nothing
)

```

Thus, `for` gets rewritten by the compiler – according to the [docs](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-iteration) into an equivalent `while` loop calling into the interface methods for iteration and in turn, into goto’s as the lowered code shows.

To me, macros are somewhat like user-defined special forms, i.e., language keywords with special semantics (slightly restricted to local code transformations though). On the one hand, they should be used sparingly as they extend the language with new keywords \[1\]. On the other hand, there can be good reasons to extend the language, e.g., documenting definitions or simplifying notations in special domains \[2\].

* * *

1. Clojure has `(with-open [f my-file] ...)` for file handling, whereas the do-notation in Julia achieves much the same via `open(myfile) do f ...`. Yet, `do` is just another build-in macro. 

2. Good examples for definitions are `@testset, @test` and [Tullio.jl](https://github.com/mcabbott/Tullio.jl) is just awesome.

[Next page](https://discourse.julialang.org/t/how-to-discourage-macros-disable-automerge-of-general-registry-prs/104529.md?page=2)
