18 ms·
I'd be afraid of inheriting any codebase that made extensive use of these JS macros. You really have no idea what this is doing (the canonical example from swe
by sync 13y ago
I'd be afraid of inheriting any codebase that made extensive use of these JS macros.
You really have no idea what this is doing (the canonical example from sweetjs.org):
class Person {
constructor(name) {
this.name = name;
}
say(msg) {
console.log(this.name + " says: " + msg);
}
}
It's not javascript -- it's your own made up "language" of macros.
I do believe with a steady hand this could lead to some great things, but the example on sweetjs.org seems rather heavy handed. Having different `class` macro definitions between codebases that use sweet.js will devolve into madness.
- jlongster 13y agoYou're absolutely right, and we need to establish a good culture that doesn't abuse macros. Of course, some people always will and let's hope we don't have to work with that code. There are a lot of ripe ES6 features to implement as macros. That `class` macro is actually taken from ES6 and has been standardized for JavaScript, so it's not exactly random.
- pfraze 13y agoThe syntax "crowding" could be solved by scoping macro rules. Maybe `macro class, foo, bar` at the top of the file?
- jlongster 13y agoThe next big thing sweet.js is working on is modules. You will be able to actually pull in macros just like you would ES6 libs: import { foo, bar } from "macros"; The scoping of macros will all stay in tact; any other macros from "macros.js" will be available, but the code that `foo` or `bar` expands to will be able to access them (this is really nice for helper macros and other things). So yes, modules are going to be a big part of distributing and composing macros.
- 6cxs2hd6 13y agoRacket shows how, with strong module support, a whole "tower of languages a.k.a. macros" can work reliably. Else not so much.
- klibertp 13y agoAlso, macros in racket are lexically scoped. Any modern macro system should follow their design, IMHO.
- jlongster 13y agoI just noticed a typo: I said "will be available" when I meant "will not be available". Any macros you don't import will not be in scope.
- drivingmenuts 13y ago> we need to establish a good culture that doesn't abuse macros I'm sure everyone who has ever looked at C macros has thought the same thing. It's a great theory. In practice, having macros will lead to someone abusing them and eventually, that abuse will be become institutionalized. Don't say "it could never happen here" because it can and it inevitably will. I don't have a specific problem with all of this, except I keep thinking a better solution would be to hammer browser manufacturers to keep their shit up to date or explain why they are not doing so.
- yeahbutbut 13y ago> I don't have a specific problem with all of this, except I keep thinking a better solution would be to hammer browser manufacturers to keep their shit up to date or explain why they are not doing so. That's the thing though. When a new proposal comes out, if it's released in the form of a macro it can be tested without vendor buy in. The pressure relief on vendors to keep up to date with the standard is just an unintended (maybe negative * ) side effect. * Personally I like being able to count on "current" features and I'm not opposed to using shims to patch the environment up to a workable level.
- chc 13y agoDo you even Lisp, bro? (Forgive the irresistible pun, but the sentiment is sincere: This feature is based on Scheme, so looking at C seems misguided.)
- jfb 13y agoThe C preprocessor is terrible, but rampant cpp insanity is much, much less prevalent these days -- the C culture has made its peace with the technology. A similar accommodation would doubtless happen with JS macros, particularly as there's almost no chance that the implementation would be as brainless as C's.
- cgag 13y agoI think the Clojure community manages to do pretty well in discouraging macros except as thin sugar over functionality avaible through normal channels. It also has some very complicated macros that give it a type system and lightweight threading and channels that would have have had to be implemented by the language designers in other languages. I'm willing to run into the occasional macro abuse to get goodies like core.async and core.typed.
- windsurfer 13y agoDo you know exactly what your compilers are doing? Do you open your compiled C programs in a disassembler? I don't think worrying about "correctness of the implementation" is constructive.
- RussianCow 13y agoI think it's less about correctness of implementation and more about abuse of the interface. Not that I agree, but I think it's a completely valid criticism, in the same way that you could argue against operator overloading in OOP languages.
- nawitus 13y agoIt doesn't matter what the assembly looks like, if the definition of language is well-defined. With macros this is not true, different 'macro' definitions probaly work in a lot of different ways. It's true that different compilers and interpreters sometimes do slightly different things, but atleast there's a standard which should improve over time. I don't see that happening with macros. Not sure how modularity is achieved with macros either.
- windsurfer 13y agoWhy can't macros be well defined?
- nawitus 13y agoThey can be, but rarely are.
- michaelmior 13y agoMacros CAN be well-defined, but I think the cherry picking of macros mentioned in the article leads to a "language" that is ill-defined vs picking up CoffeeScript or LiveScript. The idea of implementing ES6 via macros is pretty attractive though.
- EpicEng 13y agoUmmm... yes? Sometimes you have to. I was looking into a bug about a year ago that was caused by the compiler I was using (Intel) wasn't properly saving the return address in some situations. This led to seemingly random crashes and thrashed memory. So yeah, "correctness of implementation" is something to worry about, you just haven't had to (yet).
- Mikeb85 13y agoAgree. Implementing classes with macros is not only useless and potentially harmful, but also redundant, since ES6 has classes (which can be used today with dev versions of Firefox, or compiled with Traceur).
- aaronem 13y agoYou and the comment to which you respond both seem to be mistaking the specific example on the sweet.js homepage, which is explicitly described as providing ES6-standard functionality early, for the limit of the possibilities inherent in a hygienic macro system. This is a pretty grave mistake, in that it makes understanding the proposition at hand nearly impossible. sweet.js is more or less a Lisp macro system for Javascript. Gaining some familiarity with Lisp macros would probably serve you well in terms of being better able to understand what's on offer here and how useful it can potentially be.
- moron4hire 13y agoI think the idea would be to do something like Racket's approach to Scheme, wherein the vast majority of the language is implemented via macros on a very small core language.
- badman_ting 13y ago> Having different `class` macro definitions between codebases that use sweet.js will devolve into madness. Urgh, I just got a sinking feeling in my stomach because I know how right you are.
- yid 13y ago> Having different `class` macro definitions between codebases that use sweet.js will devolve into madness. As long as you don't have different definitions in the same JS file, it's not really a problem because each file can be compiled down to JS independently of the others. I'd imagine you could even add a package.json flag to specify which version of a sweet.js "syntactic sugar" library to use for a given package, and npm could compile the files automatically on install. The more transparent the sweet.js workflow can be (much like LESS/SASS is for CSS), the more likely it is to be adopted.
- Nitramp 13y agoIt could be made to work technically, certainly. But it'd be a complete mess of a code base. Code is read much more often than written, easily understanding a code base is incredibly important, and really hard in larger systems. If even your syntactical constructs behave subtly different (let alone the code you're writing!), you're setting yourself up for unpleasant surprises. There's an excellent book on UX, "Don't make me think". The same applies to code: strive to reduce the cognitive load it takes to understand a piece of code as much as possible.
- couchand 13y agostrive to reduce the cognitive load it takes to understand a piece of code as much as possible. Agreed. And it seems macros can really help with that, by encouraging a DRY codebase.
- Nitramp 13y agoAs others have noted, macros in theory could really help with that. But with macros in practice, I wouldn't be so sure. Macros essentially add syntax to languages. Syntax to help with common tasks is nice, but if you end up with lots of ad hoc syntax for lots of very divergent, and maybe not so common tasks, you're in trouble. The problem is just the multitude of syntax constructs that typically end up way underspecified, as opposed to the much more formal and strict models of a language that went through a specification process. Imagine learning not three kinds of loops (for, while, do), but 300 subtly different ones in one code base. Ugh. On the other hand, lots of boilerplate make code unreadable just by the sheer amount of it. This is a very hard balance to strike, I'd rather err on not giving every developer on a code base the power to add new syntactical abstractions.
- davexunit 13y agoBeing able to define a language tailored to your problems is a wonderful thing. Don't be afraid of it. Scheme and other Lisps macros to build new syntax on top of a small core language. Are you tired of typing (function() { ... })() and other such forms? If so, you will like macros.
- smrtinsert 13y agounless I can import a macro like clojure then no thanks. javascript debugging is already a major nightmare since any object can be edited anywhere, i dont need macros multiplying that disaster.
- klibertp 13y agoActually you could easily use macros to reduce this nightmare. And yes, I wish for sane module system in JS too - my ideal is Racket in this regard, especially after recent addition of nested submodules.
- coldtea 13y ago>javascript debugging is already a major nightmare since any object can be edited anywhere No it really cannot, except if it's exported there.
- CCs 13y agoRight. Look at the many wonderful and widely used applications or websites implemented in those heavy DSL systems! Here is the full list:
- kenko 13y agoThis is a funny comment to read on Hacker News.
- stefantalpalaru 13y agoHe did say "wonderful" ;-)
- hajile 13y agoDo we get madness because different libraries have different implementations of AJAX? In most lisp dialects, macros are lexically scoped. As long as sweetJS follows lexical scoping, a set of macros could be contained within a self-executing lambda like most libraries already are.
- mattgreenrocks 13y agoWhy is this a problem with JS and not, say, Clojure?
- wonderzombie 13y agoYou're more or less making up a "language" every time you write an API. Among other things, the extent to which you notice this depends on the degree to which one API interoperates well with another one, and the degree to which an API is specific. (See also DSLs in such as Ruby.) I'm not saying you're wrong, exactly, because there are qualitative differences. Manipulating syntax is definitely more powerful, and enables some truly crazy and wonderful constructs. It should be used responsibly. But when we define an API, we're inventing a new system of primitives for the problem at hand. It's really not as conceptually dissimilar from a language as we'd like to think.
- jarrett 13y agoThe difference, though, is that the sweet.js example of classes aims to implement something that is traditionally a language feature. APIs tend not to do this. You might argue that the distinction between APIs and language features is arbitrary. But I'd say there is a meaningful difference. An API helps you tackle a particular problem domain, such as making an HTTP request, communicating over a USB port, or writing an image. Whereas a language feature is much more generic. It's not limited to any particular problem domain. Rather, it cuts to core of how we express problems in general. If we're all ostensibly writing JavaScript, I don't think we should be using multiple, incompatible variants of the same language features.
- deleted 13y ago[deleted]
- discreteevent 13y agoAs Dave Thomas (of OTI not pragprog) said once. "Its important to be able to debug at the level of the abstraction". So in theory making up a language is the same as writing an API. In practice when you are in a hurry trying to fix something and your livelihood depends on it you may end up cursing the macro writer. I do think they can work when there's only one person on the team, which sometimes happens, or if the team are mature and disciplined, which rarely happens. They can also work in any team for trivial stuff like logging etc.
- klibertp 13y agoI have only one thing to say here, to you and to all people who are opposed to macros and new languages in general: go learn some more (let's say 5) languages and then come back[1]. Don't bother before that. Why? Because learning languages gets easier every time you do it. And it opens your eyes to languages' internal structure, the way languages are composed, which makes using given language effectively easier. So now you know 5 or 8 languages and you discovered a few basic principles behind most of them and you understand how semantic constructs compose and you know about various syntactic representation of any given semantic statement (and the other way around, similar syntactic constructs having different meanings). And you come upon a macro, like the one in the example. You don't know what it's doing - well, you just check the docs and then you know. It's as easy as learning what a function does, really. So what was learning those other languages for? It was just to reduce your fear of introducing new syntax for things. You won't think "oh, how dangerous this could be" but rather you just start using it, because you do it (change syntactical constructs you use) all the time when you switch between languages. At this stage you can learn some Lisp. And write some real macros. And maybe try Nimrod, which has wonderful macros too. And maybe Rust, which I didn't try but I read good things about. After this you'll understand what macros are, how they are constructed and how they compose - and write many of your own - and then you look at the class example above and you instinctively[2] know that there has to be a syntax transformer which matches class keyword, a keyword and a block, and then there has to be another transformer, perhaps recursive (like in Scheme) or just iterating over the body (like in defmacro) and that all they do is to add some keywords here and there and a statement or two at the top of the block. In short - you know exactly what to look for and even docs are unneeded, you just take a quick look at a macro source and go on using it happily. Alternatively you can look at generated code and work out macro implementation from it easily, too. I'm a happy user of LiveScript, and CoffeeScript before that. The only reason for not switching to JS with sweet.js is the fact that I would need to write a whole host of macros by myself, while in CS and especially LS they are already written. And of course modifying their grammar is not that hard either. Had I somehow been unable to use LiveScript, I'd use sweet.js for sure. What I'd implement? Probably some kind of "let" statement for sane scope management, a loop macro for iterating over custom collection classes (loop in CL, for/* in Racket, also in others), function currying (partial application) and maybe something like "with" context managers from Python would be among the first. There are many things which are better abstracted with syntax than with (for example) functions. Would the language be JavaScript? Well, hard question, it would be a superset with underlying semantics intact, but it sure wouldn't "feel" like JS. But would that matter? Not at all - syntactic extensions would save me a ton of time and I'm used to many different syntaxes anyway. And I expect anyone who'd like to work with me to be able to pick up any language in reasonable time - the ability to pick up a few additional syntactic constructs on top of already known language is essentially the same thing, so I think such person would have no problems with it either. Anyway, macros are good; using them is good; the only dangerous thing is having many people implement essentially the same macro over and over again, but I think this could be solved with a sane module system for macros which I read is already planned. There should be more languages rather than less; more exploration of different syntaxes and semantics for things, not less - and macros are one way of making this happen. And if you have problems with learning what a "class name body" does, then I can only refer you to the first paragraph. [1] After I wrote this post I realized I could sound a bit rude. It was not my intention and I'm sorry if I offended anyone; while written generally, it's actually only a description of a road I personally traveled, so obviously YMMV. [2] I know completely nothing about sweet.js in particular, so I'm completely just guessing.
- gcb0 13y agogood. now you know how everyone else thinks of you using compilers. Can we all agree that each project needs to use a set of utility functions and move on?
- bickfordb 13y agoI suppose you're not the first person to attack macro systems, but can you be clear why it would devolve into madness? It seems like you're saying that developing a common language within an organization is madness, even though this just appears to be factoring common work into syntax. In the example you cited, it seems like a pretty good language versus other examples I have seen for defining Javascript types?
- ScottBurson 13y agoAs someone with decades of Lisp experience, I can assure you that macros can devolve into madness. They have to be applied judiciously -- just like, say, operator overloading, and for similar reasons: you're not just adding new APIs to the language, you're adding new syntax. So there will be newbies who make messes with macros. It's happened in the Lisp world for decades -- though not as often, probably, as some people fear -- and it will surely happen here. Some people will overreact to that (as they have to misapplication of operator overloading) and prohibit their teams from using them. Eventually, knowledge of how to use them well will spread wide enough that most people will be able to be trusted using a language that has them, even if that means, in many cases, that they know they don't have the experience to use them properly and so avoid writing their own. In this vein I'll close with a quote from the great Lisp hacker David Moon: Functions compute; macros translate.
- joubert 13y agoisn't that valid ES6? http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes http://wiki.ecmascript.org/doku.php?id=strawman:maximally_mi...
- specialist 13y agoI'd be afraid of inheriting any codebase that made extensive use of these JS macros. I will not be doing metaprogramming again any time soon. I'm doing just fine using composition/iteration and creating better, more fluent APIs.