Sugar
The following would let people create syntax sugar for their favorite paradigms.
I really have to suggest you learn about macros before trying to reinvent them. This reading list is a good start:
http://library.readscheme.org/page3.html
Dave Herman wrote:
The following would let people create syntax sugar for their favorite paradigms.
I really have to suggest you learn about macros before trying to reinvent them. This reading list is a good start:
http://library.readscheme.org/page3.html
The idea is to avoid the unsolved problems of macro hygiene. That's why the arrangement has only function calls, no macros.
Dave Herman wrote:
The following would let people create syntax sugar for their favorite paradigms.
I really have to suggest you learn about macros before trying to reinvent them. This reading list is a good start:
http://library.readscheme.org/page3.html
ingvar-sugar isn't a macro system. it's pretty similar to python's @decorator syntax. www.python.org/dev/peps/pep-3129
Felix wrote:
ingvar-sugar isn't a macro system. it's pretty similar to python's @decorator syntax. www.python.org/dev/peps/pep-3129
Yeah, you're right -- IIUC it's very much like Python decorators, though not class decorators but function decorators, right? IANA Python expert.
http://www.python.org/dev/peps/pep-0318/
Ingvar, I've read your proposal more carefully. If I'm reading it right, I think your description is off a meta-level-- it's not so much a general syntactic sugar mechanism as a way of defining one specific kind of sugar: a function decorator. Basically, a decorator is syntactic sugar for function composition. The first thing I'd change is to replace the "sugar" keyword with "decorator." I think this would make its purpose clearer and connect it with precedent from other languages.
I guess I don't have much of a reaction... I understand people get a lot of mileage out of Python decorators, but if it came down to choosing between decorators and macros, I'd take macros. Regardless, I don't think we've been considering meta-programming facilities to be on the near-term agenda.
Ok, I'm really confused about the exact semantics of this new syntax. Can you give explicit rules? As far as I can tell, this "sugar function" can either desugar to a (const declaration + assignment + function call + anonymous function) or just (function call + anonymous function), and I'm not sure whether a specific sugar function usage desugars to the former or the latter.
Dave Herman wrote:
The first thing I'd change is to replace the "sugar" keyword with "decorator." I think this would make its purpose clearer and connect it with precedent from other languages.
Indeed they seem similar to python decorators. But "decorator" suggests that there's something you're decorating. The keywords that I'm proposing can be used independently.
Suppose you don't like the word |function|, and want to say |fn| or |lambda| or |closure| instead:
use sugar fn;
sugar function fn (func) {return func}
myArray.sort (fn (a, b) {a - b});
Or suppose you wish that let(a=1){...} would desugar exactly to (function(a=1){...}()):
use sugar lt;
sugar function lt (func) {return func()}
lt (a=1) {...};
The desugaring that I showed in the thread starter was abbreviated for simplicity. If one detail is added, keywords can create control structures, if your programming style has no problems with continue/ /break/return/var getting locked up inside the resulting function:
use sugar unless, until;
sugar function unless (cond, work) {if (!cond()) work()}
sugar function until (cond, work) {while (!cond()) work()}
unless (x < 42)
{ until (y > 42)
{ ++y;
}
}
So this sugar is more general-purpose than a decorator.
Regardless, I don't think we've been considering meta-programming facilities to be on the near-term agenda.
One reason I brought them up now was that Java-style classes were discussed. Significant parts of this class functionality could instead be offered by third-party library vendors using these keywords. We'd get more variation, greater freedom, and much faster adaptability, than if it's defined in a standards body.
Of course performance becomes a big issue. I think ES implementations would detect popular patterns and optimize for them. For example, Java-style classes would undoubtedly become very popular and very well optimized.
This would be self-reinforcing. Applications would choose patterns that have high performance on many platforms, and so the optimized patterns would become even more popular.
Data type is another issue, but it may be too early for that discussion.
YR Chen wrote:
Ok, I'm really confused about the exact semantics of this new syntax. Can you give explicit rules? As far as I can tell, this "sugar function" can either desugar to a (const declaration + assignment + function call
- anonymous function) or just (function call + anonymous function), and I'm not sure whether a specific sugar function usage desugars to the former or the latter.
First, to give a simple rule, you can use these keywords just like the |function| keyword. Similar syntax forms have similar meanings. For example:
use sugar Class;
...
function Point (...) {...}
Class Point (...) {...}
Here we have a Class declaration that looks just like a function declaration -- it's in a statement position, not in an expression, and there's a name before the "(". When a sugar keyword is used in this way it binds the newly created function/class/constructor/etc to the name.
Desugaring the above:
const Point = Class (function Point (...) {...});
However:
Pt = function Point (...) {...}
Pt = Class Point (...) {...}
Pt = function (...) {...}
Pt = Class (...) {...}
Here we use the keyword in an expression, so that it returns the newly created function/class/constructor/etc. Then if we write a name before the "(" it's only internal.
Desugaring the above, in order:
Pt = Class (function Point (...) {...});
Pt = Class (function (...) {...});
However, just like any other function, a sugar keyword can have very different meanings, depending on what the sugar-function code does. Depending on the meaning, some of the above forms may not make sense for a given keyword.
There's also a form that is not allowed with the |function| keyword but can make perfect sense for a given sugar keyword. You can use it in a statement position without a name before the "(":
use sugar until;
...
until (x > 42)
{ ++x;
}
The simplified desugaring that I showed in the thread starter can't implement the above functionality. A more complete desugaring would be:
until
( function() {return x > 42},
function()
{ ++x;
}
);
(But this is still simplified. For more, see other post.)
One reason I brought them up now was that Java-style classes were discussed. Significant parts of this class functionality could instead be offered by third-party library vendors using these keywords. We'd get more variation, greater freedom, and much faster adaptability, than if it's defined in a standards body.
At the great expense of interoperability. In the grand scheme of things, I don't need greater freedom, variation, or adaptability in the way that I define a class. Especially if it means I have to tack on many kilobytes of library code to use widget X, and then many more Kb's to use widget Y, and cross my fingers they don't eat eachother. Much better to have a single built in implementation for that feature that everyone codes against- So I can use code without having to include any libraries. The end user ultimately doesn't care that you used a clever class library, only that the application works, is fast, easy to use, and bug free. Language features should be aimed squarely at helping programmers achieve those goals, and I don't see how building a new tower of babel helps.
But you know, just my opinion as a lowly developer.
Breton Slivka wrote:
One reason I brought them up now was that Java-style classes were discussed. Significant parts of this class functionality could instead be offered by third-party library vendors using these keywords. We'd get more variation, greater freedom, and much faster adaptability, than if it's defined in a standards body.
At the great expense of interoperability. In the grand scheme of things, I don't need greater freedom, variation, or adaptability in the way that I define a class. Especially if it means I have to tack on many kilobytes of library code to use widget X, and then many more Kb's to use widget Y, and cross my fingers they don't eat eachother. Much better to have a single built in implementation for that feature that everyone codes against- So I can use code without having to include any libraries. The end user ultimately doesn't care that you used a clever class library, only that the application works, is fast, easy to use, and bug free. Language features should be aimed squarely at helping programmers achieve those goals, and I don't see how building a new tower of babel helps.
But you know, just my opinion as a lowly developer.
You do have a point.
But the problem isn't interoperability or library size. The problem is the copy-pasting and mixing of code. If you're using one set of sugar keywords, then in that same { } block you can't copy-paste code that uses a different set of sugar keywords.
However you can copy-paste it into a nested block or a neighboring block.
Interoperability is not a problem. Everything translates into the same primitives, so they all communicate in the same way.
Library size is hardly a problem either. Sugar is just a translation between neat and messy notation. Each keyword definition is tiny and the number of keywords is very small.
Even so, nothing prevents that the standards body define a couple of built-in sugar-keyword librares.
Essentially the result would be that the platforms would support a few specialized programming languages for different purposes, like there are in many fields.
But we would get dialects, so copy-pasting within the same { } block does become a problem.
Ok, it really does sound like a hygienic macro system for |x(y) {...}| and |x {...}| statements and expressions. Call it what you want, those are definitely a type of macro. Since I like hygienic macros, I'm pretty sympathetic to them.
However, ES-Harmony shouldn't introduce anything either not tested in other languages or extensively researched in academia. I would place hygienic macros for procedural languages in that category. Maybe we ought to look in existing research papers for some inspiration: scholar.google.com/scholar?hl=en&lr=&safe=off&q=hygienic+macro+procedural&btnG=Search, scholar.google.com/scholar?hl=en&lr=&safe=off&q=hygienic+macro+procedural&btnG=Search
Some macros, like the until loop you've shown as an example, can create new control abstractions, which in turn should generally satisfy Tennent's correspondence. That is, the statements/blocks contained within the control abstraction should inherit |this|, |arguments|, |var| scope, return/continue/break continuations, etc. I've proposed a Ruby-like block proposal for this, which I consider a bit less radical because a similar language has them (Ruby), but I've already found a couple flaws in that proposal, which I may or may not elaborate on if I have the time.
My point is that I don't think these proposals are ready for ES-Harmony yet. We don't want to implement a feature, and later realize that we could've done it better but doing so would now be backwards-incompatible. Let's defer them to a future ES version, once they've been discussed, researched, and tested thoroughly. Or even better, make your own language and interpreter to test your ideas out. I'm already tempted to do so :)
On 2008-09-03, at 02:24EDT, Yuh-Ruey Chen wrote:
However, ES-Harmony shouldn't introduce anything either not tested in other languages or extensively researched in academia. I would place hygienic macros for procedural languages in that category. Maybe we ought to look in existing research papers for some inspiration: scholar.google.com/scholar?hl=en&lr=&safe=off&q=hygienic+macro+procedural&btnG=Search <scholar.google.com/scholar?hl=en&lr=&safe=off&q=hygienic+macro+procedural&btnG=Search
The Java syntactic extender is the descendant of Lisp macros, adapted to Algol-like syntax via
Dylan, and probably the best candidate for study, IMO.
There's a lot of prior work on macros, including macros for Java and other non-S-expression based languages-- JSE isn't the only candidate for study.
As I've said, macros aren't on the agenda for this go 'round.
On Wed, Sep 3, 2008 at 8:55 AM, Dave Herman <dherman at ccs.neu.edu> wrote:
As I've said, macros aren't on the agenda for this go 'round.
Is there an official wiki location which states what the committee has agreed upon for Harmony? For example, if it is definitely known that macros and/or meta-programming is unanimously off the table by those with a vote then it would save a lot of energy.
Peter
On Sep 3, 2008, at 3:11 PM, Peter Michaux wrote:
On Wed, Sep 3, 2008 at 8:55 AM, Dave Herman <dherman at ccs.neu.edu>
wrote:As I've said, macros aren't on the agenda for this go 'round.
Is there an official wiki location which states what the committee has agreed upon for Harmony?
Not yet. The agreements in Oslo were summarized in my "ECMAScript
Harmony" post, and we've corresponded here since then about types,
classes as sugar, etc.
For example, if it is definitely known that macros and/or meta-programming is unanimously off the table by those with a vote then it would save a lot of energy.
Why not discuss these or other "future" topics if you have the
interest? This is es-discuss, it's not targeted only at near-term
discussions.
On Wed, Sep 3, 2008 at 3:49 PM, Brendan Eich <brendan at mozilla.org> wrote:
On Sep 3, 2008, at 3:11 PM, Peter Michaux wrote:
[snip]
For example, if it is definitely known that macros and/or meta-programming is unanimously off the table by those with a vote then it would save a lot of energy.
Why not discuss these or other "future" topics if you have the interest? This is es-discuss, it's not targeted only at near-term discussions.
Excellent point. I suppose some folks might be confused about what is up for discussion now and what is for future versions and investing energy hoping to get features into the next version.
If real macros are not ready for ECMAScript prime time then I'm glad meta-programming is not on the table for the next major edition. Better to wait and do it right. Adding built-in sugar (that could otherwise be macros) for the most painful points is a better intermediate fix, I think.
Peter
Yuh-Ruey Chen skrev:
Ok, it really does sound like a hygienic macro system for |x(y) {...}| and |x {...}| statements and expressions. Call it what you want, those are definitely a type of macro. Since I like hygienic macros, I'm pretty sympathetic to them.
I'm no expert, but I've always understood macros to involve text substitution, the macro definition specifying source code that replaces the invocation. The sugar keywords only have unusual arguments, but unusual as they are, they are passed in a regular, run-of-the-mill function call, without any text substitution.
The fact that the until() parenthesized expression becomes a function body (or maybe one of your Ruby blocks) doesn't mean that it involves text substitution. Despite odd syntax, it's just a function or Ruby block, just like the code block below is a function or Ruby block, to be passed as an argument.
Or even better, make your own language and interpreter to test your ideas out. I'm already tempted to do so :)
And I've already started! :-D Sort of.
I'm adding sugar keywords to JavaScript in a server-side test arrangement. I got tired of talking about abstract ideas here, always wondering if my explanations were clear. I longed for something concrete that people can test.
I think this can be useful even if the sugar keywords aren't considered for es-harmony. When discussing classes etc. you can use this testbed to implement classes as easily defined sugar, and then test the resulting classes to see how they behave, and decide if you like working with them.
In addition to the sugar keywords, the testbed will also feature your Ruby blocks. The two complement each other very nicely.
Unfortunately, implementing this is somewhat time-consuming. I hope I'll have time. I'm pretty confident that I'll get there within a reasonable time span.
If real macros are not ready for ECMAScript prime time then I'm glad meta-programming is not on the table for the next major edition. Better to wait and do it right. Adding built-in sugar (that could otherwise be macros) for the most painful points is a better intermediate fix, I think.
This is my feeling, too.
The following would let people create syntax sugar for their favorite paradigms.
Suppose we want the word |Constructor| to become a syntax-sugar keyword. We inform the compiler at the top of the scope:
We define |Constructor| as a function:
Now we can use |Constructor| as a keyword:
This has become syntax sugar for creating a new function named Example() and passing it to the above function Constructor():
Sugar keywords are also intended for expression constructs:
This desugars to:
In this case the name for the new function is optional. The sugar function can of course do whatever it wants with the new function, including calling it.
We can combine several sugar keywords:
This desugars to:
However, the desugaring shown here is inefficient, and I've chosen it for its simplicity, a real desugaring will be different. Here, frozen() and inherits() return objects that Constructor() recognizes and acts on.
If the parser needs stable rules that don't depend on the meaning of individual keywords, it can look for the first "(", "{" or ";". Then, if the preceding identifier is a sugar keyword, an anonymous function is created, otherwise this identifier becomes the name of the newly created function.
The nearest sugar keyword before that first "(", "{" or ";" becomes the main, enclosing sugar-function call.
All sugar keywords are called as functions. Anything else, like |new Parent (...)| above, is an expression whose value becomes an argument to the nearest preceding sugar function.