Why can't macros have an arbitrary number of arguments?

Why can’t macros have an arbitrary number of arguments? Is this a fundamental limitation (because of the BEAM, or something low level like that) or a deliberate design decision?

1 Like

Design decision

2 Likes

Hm… Ok. If webhadn’t this restriction then for and with could have been regular macros, right?

For it’s current syntax yes.

Though I’d still prefer this as it’s syntax personally (and is doable as a macro ‘now’ too ^.^)…

with do
  {:ok, value} when is_integer(value) <- get_something() # <- is still assign
  value = value * 4 # Look!  No nasty comma-turds (erlang term) littering all over!  ^.^
  do_something(value) # Last value is returned value of course
else
  e -> Logger.info(e) # Still can do else clauses too!
end

Elixir Macros are just functions that create elixir code. Since functions are identified by their name and arity, there is no way to have a function (and by extension a macro) take an arbitrary number of arguments. this has some implications where you can do things such as:

def some_function()
def some_function(arg1)
def some_function(arg1, arg2)

where if for some reason you wanted, some_function/0, some_function(1) and some_function(2)
can all do completely unrelated things.

Whatever you want to do can almost certainly be implemented in a different (tho no better or worse) way.

lets take printf(...) for example.
say we have some module

defmodule SomeModule do
   import PrintfLib
   def some_function() do
      printf ["doing some function! heres an integer: %i and heres a string: %s", 123, "some string"]
      printf ["heres another format, it only has one arg."]
   end
end
defmodule PrinitfLib do
    # yes you can do this
   defmacro printf([format | ...]) do
      # actually implement printf here.
   end
end

Obviously 1) you don’t actually need a macro for this, and 2) its not technically an arbitrary number of args, but you can kind of think of it as such with a list

I do the same thing in ExSpirit, hence the blah([otherBlahs]) all over the place. >.>

Just checked ExSpirit out! looks pretty cool

The latest version has an experimental module that is using an expression template style builder, it removes the need for [/] everywhere and I’ll be able to later do optimizations on the generated code that are fairly difficult to impossible otherwise (plus it might be faster to compile?). :slight_smile:

I’ve been studying StreamData, which gets around this limitation by making the clauses seem to be arguments to a non-existent function, if I am understanding the code correctly.

That is actually exactly what my ExSpirit experimental module does as well as my MlElixir and others too. ^.^;

But yes, a lot of things do that to work around it, though it means you have to have a call before the call… ^.^;

Yes, the ugly check all thing is exactly what motivated me to ask this :slight_smile:

2 Likes

I endorse ExSpirit as the best thing ever.

2 Likes

Heh, I thought the same but noticed why it was being used. ^.^;

LFE macros are like normal lisp macros and can take variable number of arguments. Basically you get a list of all the arguments with which you can then do what you want. :wink:

3 Likes

Apparently you can build LFE projects from mix. I have to try it someday

Yes, I have heard that as well but never tried that.

I’ve done! And I used some of lfe’s internal calls to build up an ast that I then operated on! ^.^

Could you explain what you mean by this?

Lol, I embedded lfe as a scripting language and used its compiler to get it’s ast and ran through it manually. ^.^;

Also, why not base ExSpirit 1.0 on LFE? You’d get all the postfix operators you want :stuck_out_tongue: (ok, I’m half joking here)