It is a special form, like %{}. It is not directly part of the syntax, but treated in a bit special way. Kind of a hardcoded macro, internally working pretty much like a sigil, but not exactly as them.
You (the elixir community in general, not you specifically) seem to use the word syntax in a way Iâve never seen it used⊠What youâre saying is akin to: âThis is not syntax - Itâs just transformed by the compiler into an AST in which the root is a macro that canât be redefined by the userâ. Isnât that what syntax is? The rules used for the compiler to transform text into an AST?
The syntax, for me, is exclusively what is handled in the parser. Anything beyond that is not âsyntaxâ but âlanguage featuresâ. How binaries work has no special treatment in the parser, so to me, itâs a language feature that uses regular Elixir syntax.
Yes, but who turns <<a, b, c>> into: {:<<>>, [], [{:a, [], Elixir}, {:b, [], Elixir}, {:c, [], Elixir}]}? Isnât it the parser? (I assume it is, even though I have no idea how Elixir parses Elixir).
This is not the same as turning: def d(x), do: x into:
The parser seems to use different rules in each case: in the def case, the parser just expands function calls into AST nodes according to what you call the âsyntaxâ of the language. In the <<>> case, the parser uses some rules (different from just expanding function calls) and turns it into: {:<<>>, [], [{:a, [], Elixir}, {:b, [], Elixir}, {:c, [], Elixir}]}.
Those rules are the syntax.
Of course the parser doesnât know that <<>> is a binary, itâs not itâs job. Iterpreting the AST generated by the parser is semantic analysis or something like that. The parser doesnât even know that the :<<>> atom is non rebindable. But it does know that when it finds <<...>> it must output the AST [{:<<>>, [], [...]}].
Itâs very cool! Just tried to quote some <<>> expression and the minus operators expand into actual minus operators inside the AST. I still contend that <<>> looks a lot like syntax (see above)
Therefore, syntax wise, <<>> can mean anything. Thatâs why I said you wonât find the documentation for what <<1::byte>> means in the syntax reference. The syntax allows you to put whatever you want on the right side of ::, the meaning comes from elsewhere.
This is a big contrast to other languages, such as Erlang, where what is allowed inside <<>> is a directly known by the parser.
I would say that that is a language developers way of looking at it. For most users of Elixir whether parts of the âstandard syntaxâ like def and if are built-in syntax or macros is completely irrelevant. How I write them and how do I use them are the important bits. do ... end vs do: ... is a little more complex but I think you can happily just describe what they look like and how they equate to make most users happy and to get them right.
Again, I think most users, even those who write big complex systems, will not define their own macros even though they will be using lots of things defined by macros. In one way it is similar to the fact that using OTP you can write large extremely concurrent and parallel systems without a spawn, send or receive in sight. You should know that things are being done concurrently but you donât need to use the explicit concurrency primitives.
Ok, thanks! I agree with you, then. The types inside the <<>> are certainly not syntax, and they shouldnât be highlighted any differently in a syntax highlighter.
I agree. What a binary looks like is very much syntax, the same as for all the other data types. The syntax describes what things look like. What they are parsed to is basically irrelevant to most users.
I think the important thing is to understand for whom you are writing a syntax description.
I donât think we agree. You say it looks like it is syntax. I say it is syntax. Itâs a sequence of symbols thatâs translated into an AST in a very unconventional way compared to the rest of the language (the same goes for maps, tuples, etc).
Youâve written this, which makes me think you think these cases are analogous. My position is that def and iflook like syntax (they are turned into an AST node the way any function call is), while <<...>>is syntax (the parser does funny stuff with it to turn it into an AST node).
I wonder if there should be two reference guides: one for Developers who donât want to write macros and one for Developers who want to write macros, maybe titled something like:
Reference for Developers who donât like LISP or donât know what it is, which basically describes elixir like if it were python. After all, it has def, if, with, Enum.reduce_while (basically a python for loop that doesnât leak outside the scope). defmacro does not exist and the |> operator is a special form that does magic with your functions to put the arguments in the right place. Modules are like classes that have no internal state and canât be instantiated, unless they inherit (sorry, use! they use!) GenServers and you mess with something arcane like the process registry. Then you get gets and sets and mutable internal object state. Ok, Iâll stop now
Reference for Developers who think that LISP is the best thing ever and that the characters that compose the program are mere distractions from the holy truth of the AST, which describes elixir as if it were LISP and in which after chapter 2 all programs are written directly by manipulating the AST using functions (do ... end? defmacro? who needs them? We write our AST directly!)
Despite the joking nature of these titles, and the parody-like description, Iâm being serious, and Iâd totally buy a book like number two if someone were to write it. And if @rvirdingâs right, then reference #1 might be useful for many people too.
We do agree. I did not say that âit looks like syntaxâ, what I said was âwhat a binary looks likeâ âis very much syntaxâ. I could flip the order and say syntax is what they look like.
Again I did not say looks like syntax, but what it looks like is syntax. And I see def and if as syntax as they are part of the standard definition of the Elixir language. In the same as data types.
Here Iâm not sure we agree. The definition of syntax I use (itâs been a long time since Iâve read a book on the subject) is the same as the one given on Wikipedia (Syntax (programming languages) - Wikipedia):
In computer science, the syntax of a computer language is the set of rules that defines the combinations of symbols that are considered to be a correctly structured document or fragment in that language.
While semantics is (from the same article):
The syntax of a language describes the form of a valid program, but does not provide any information about the meaning of the program or the results of executing that program. The meaning given to a combination of symbols is handled by semantics (either formal or hard-coded in a reference implementation). Not all syntactically correct programs are semantically correct.
From the point of view of the syntax, there is nothing special about if and def. The rules you use to decide whether they are part of a valid program are the same. They are both ordinary identifiers.
I admit my perspective might be too pedantic, strict and theoretical. After all, youâre the one who has implemented (real, used by may people) languages in practice, so I certainly respect your mental models regarding this topic!
But in this case, the difference these definitions draw between Syntax and Semantics is useful to me, while your nebulous notion of âitâs syntax if most programmers agree it isâ is to vague for me personally.
Just an aside, if really should not be a special form or parsed with the syntax or anything of the sort in Elixir, it could easily be just a macro like:
defmacro if(cond_ast, bodies) do
then_body = bodies[:do]
else_body = bodies[:else]
quote do
cond do
unquote(cond_ast) -> unquote(then_body)
true -> unquote(else_body)
end
end
end
Or something of that sort. Thereâs no reason for it to be anything but a macro in Kernel, oh and look it is (although it does some weird stuff like special case the random atom nil and such⊠*cough*still not a fan of nil being special at all), but yea it is not syntax, nor is def as it is just a macro as well.
The point of this is, since they are macroâs then the user could override them to make them do something else (like how I override def in my defguard library to allow you to define super-guards like is_struct (I still think my style (though complete) of defguard should be built-in to elixir) (I might be in a lispây moodâŠ)), but because of that syntax coloring them special may not always make sense, like say in a DSEL.
What I really really hate being special-formâd are things like with and for, both of those could have been done in other more traditionally âmacroâ ways without the comma-splosion, but since they are special-formed then syntax coloring on them can be specializedâŠ