You're absolutely right; Babel's parser is very much hand-coded, and adding syntax requires deep knowledge of the internals. Not impossible, but not for the faint of heart. My dreams of having the safe navigation operator from Coffeescript (a?.b?.c) must yet remain unfulfilled...
The Law of Demeter doesn't always apply neatly, especially when you're introspecting JSON sent over the wire and you don't have a "class" with object oriented behavior for each sub object (at best, they're strongly typed). And the runtime overhead AND verbosity of a function may not be ideal, with the string parsing required in lodash and the awkward syntax of the curried function. Something that compiles natively in a DRY way to a && a.b ... would be used widely imo.
That's not just "AST transform system", Sweet.js provides a way to extend grammar with new productions. That allows to introduce new syntax constructs.
Coming from a Scheme background, if there's one thing I can't believe we live without in Javascript, it's macros. Hell even C has macros... I've looked at Sweet.js a few times to add support for macros to the Linode Manager. Between m4, the gcc preprocessor, and something native, this seemed like the easiest potential sell. However, I've been turned off by how complicated this looks compared to any of the other options and I'm not sure it actually even supports the feature I want: allow some code to show up in "development" mode but for that code to not even exist in the compiled output of "production" mode. (The other feature that's just as important though is being able to wrap shared code up in a single function that gets compiled in at compile time, but I think Sweet.js supports that.)
Who uses m4? It has been around forever, but I have never really seen it used except in autoconf. When I looked at it (a long time ago) it struck me as really tricky and confusing, even more than lisp macros (but maybe on a par with TeX). However, this was just a first impression -- I didn't go too deep.
I have used it recently. I have a similar attitude towards m4 as shell scripts: they are good for quick hacks, proofs of concept, and very simple systems. When I need to sprinkle just a bit of macros on something, m4 is great. For example, a one-off piece of technical documentation I wrote is markdown interspersed with code examples. I wanted to make sure the code passed its unit tests, so it lives in separate files and I use m4 to include it into the bigger document. This is nicer than catting separate file chunks together because the text can all be contiguous, but if I needed to do anything more sophisticated I would probably switch to purpose-built templating or static site system.
I once learned a lot about m4; more than twenty years ago. I remember all the features it has, like redefining the delimiters for macros, diversions, for loops and all that jazz.
So it's not due to lack of familiarity that I won't use it; it is simply atrocious.
Recently I needed a preprocessor (featuring just simple if/ifdef/elif/endif) in a Linux distro build system (Yocto). I didn't want to add anything new.
To avoid inflicting m4 on myself and everyone who has to interact with this in the future, I wrote a simple awk script wrapped around cpp.
The tiny awk script implements this pipeline, which involves encoding and decoding the input so that cpp never sees the syntax of the file:
this is our 1 1 this is our
original 2 2 --> [dec] original
@ifdef FOO --[enc]--> #ifdef FOO --[cpp]--> 6 file
input 4
@endif #endif
file 6
this works with nearly any textual input. Your input can contain broken C tokens and comments and whatnot.
I switched the # to @ to remind people that this isn't the C preprocessor, and because # is a comment character in the preprocessed language, which could look confusing.
The in-the-wild code I've seen that uses Sweet.js has been atrocious. Of course I'm not saying that this is necessarily the case. I'd love to see some real world examples whter this is used effectively.
Separately, could you point to some examples of the bad Sweet code you've seen? If it's anything like C macro misuse, it'll at the very least be educational to see just how badly one can shoot oneself in the foot.
The last thing the JS community needs is macros IMO. From what I've seen in other languages, macros are difficult to maintain and document, and they add syntax constructs to languages that aren't supported by code highlighters. The difference between this and babel, is documentation. Babel is working off of a specification of how the language should work, whereas I doubt someone will document their macros as well as TC39 does the JS syntax
We were looking into sweetjs for adding cross-module contracts to the graphistry stack, but nixed the project when it became too much to generate code that passed our basic linters. TS largely scratches that itch, so we've been moving to that. I'm still hopeful though :)
Say you're creating a programming language and you know everyone is going to love it and use it. You add some nice features like if statements, switch statements, and for loops which allow the people that use your language to decide when certain code runs and shortens the syntax for common patterns.
Five years down the line your language is losing popularity fast, because all the hip new languages have an "unless" statement which is the opposite of an if statement. They have for-each loops, cond statements, and their if/else statements return values, so you can write less code to do those common patterns in those new languages than your language.
You rewind time 5 years using a time machine and this time, when you create your langauge, you add all those cool features, only to realize in another 10 years your language has lost popularity because there's a new set features they want, lambdas, argument piping, etc.
So this time when you go back in time, you add macros to your language. Macros are bits of code that allow people using your language to write code that produces more code. Now, you don't even have to write an unless statement, you can let the community write one for you and release it as a package. Anyone at any time can effectively add features to the language in their own project.
That sounds fantastic, and it often is, but macros need to not be abused. If a developer writes a bunch of code using lots of his own macros in your language, anyone reading that code later is going to be very confused seeing that many language features that aren't in the language docs, because that random developer wrote them himself. Functions are much more explicit than macros, so if you can write whatever you're trying to write as a function instead of a macro, you'll be better off. For every success story of a language becoming easier to use because of macros, there's another story of a different language becoming frighteningly complicated due to macro abuse.
A "macro", in the sense we are using (i.e. not "C preprocessor macro" or "Excel macro"), is basically a function or procedure that "spits out" (returns) source code. It is writen in the programming language you use, and outputs source in the programming language you use.
In other words, a macro is a program that writes programs.
In languages that make heavy use of macros (like Lisp), a macro is compiled almost transparently, so you can use it as if it were a function. It behaves like a function but can do a lot more.
One simple use is to eliminate having to write repetitive or "boilerplate" code, since you can just program a macro to write generate code for you. This generation occurs on the fly and transparently, so the code is more maintainable as well.
Macros run some code at compile time, that takes raw unevaluated source code as arguments, and returns new source code to replace it in the code. Then use this returned code instead in the compilation.
36 comments
[ 3.5 ms ] story [ 79.7 ms ] threadhttps://github.com/babel/babylon/blob/master/src/parser/expr...
But in this case it's pretty straightforward to write a function like "get('b', 'c')(a)" or use a lib like lodash [1]
[1]: https://lodash.com/docs/#get
Are there any transpilers that do use Sweet.js?
Not for long: https://github.com/babel/babel/pull/5813
So it's not due to lack of familiarity that I won't use it; it is simply atrocious.
Recently I needed a preprocessor (featuring just simple if/ifdef/elif/endif) in a Linux distro build system (Yocto). I didn't want to add anything new.
To avoid inflicting m4 on myself and everyone who has to interact with this in the future, I wrote a simple awk script wrapped around cpp.
The tiny awk script implements this pipeline, which involves encoding and decoding the input so that cpp never sees the syntax of the file:
this works with nearly any textual input. Your input can contain broken C tokens and comments and whatnot.I switched the # to @ to remind people that this isn't the C preprocessor, and because # is a comment character in the preprocessed language, which could look confusing.
I.e. a macro program is a piece of code that defines new keywords, operators, etc. and their implementation.
Five years down the line your language is losing popularity fast, because all the hip new languages have an "unless" statement which is the opposite of an if statement. They have for-each loops, cond statements, and their if/else statements return values, so you can write less code to do those common patterns in those new languages than your language.
You rewind time 5 years using a time machine and this time, when you create your langauge, you add all those cool features, only to realize in another 10 years your language has lost popularity because there's a new set features they want, lambdas, argument piping, etc.
So this time when you go back in time, you add macros to your language. Macros are bits of code that allow people using your language to write code that produces more code. Now, you don't even have to write an unless statement, you can let the community write one for you and release it as a package. Anyone at any time can effectively add features to the language in their own project.
That sounds fantastic, and it often is, but macros need to not be abused. If a developer writes a bunch of code using lots of his own macros in your language, anyone reading that code later is going to be very confused seeing that many language features that aren't in the language docs, because that random developer wrote them himself. Functions are much more explicit than macros, so if you can write whatever you're trying to write as a function instead of a macro, you'll be better off. For every success story of a language becoming easier to use because of macros, there's another story of a different language becoming frighteningly complicated due to macro abuse.
In other words, a macro is a program that writes programs.
In languages that make heavy use of macros (like Lisp), a macro is compiled almost transparently, so you can use it as if it were a function. It behaves like a function but can do a lot more.
One simple use is to eliminate having to write repetitive or "boilerplate" code, since you can just program a macro to write generate code for you. This generation occurs on the fly and transparently, so the code is more maintainable as well.
It is also essentially JavaScript so no special syntax had to be learned.
[1] https://github.com/dcodeIO/MetaScript