Closed zaynv closed 8 years ago
Decorators.
Any discussion about this?
Why not private
instead of #?
@eranimo #14
Not a huge fan of the #
symbol :/
Is there a possibility for the ~
to be used instead?
class Point {
~x;
~y;
}
Edit: nvm, it's a bitwise operator.
Personally I see it similarly to how Mark saw it in https://github.com/tc39/proposal-private-fields/issues/14#issuecomment-216291344, that #
is not so bad.
OTOH I don't know whether it's too late to "swap symbols" with decorators. Although we'd be asking decorators users to change their syntax, we're already asking TypeScript users to change their syntax for private state, so in some cases, asking for a syntax change is OK.
There's actually a lot of symbols we can use. Anything which is an infix operator and not a prefix operator is OK, since we decided that when supplying the receiver, you do x.#y
. So we have the following symbols in our toolbox in theory (though I'd agree that most of them are bad choices):
~ @ # % ^ & | < > , ?
How about if the current proposal stays with #
, but the question is raised to TC39 for resolution at the next meeting?
There's actually a lot of symbols we can use.
Since we have the shorthand syntax, we have to be careful of infix operators creating additional ASI hazards.
class A {
&x
constructor() {
1 + 1 // trying to use asi here
&x = 1
}
}
How about if the current proposal stays with #, but the question is raised to TC39 for resolution at the next meeting?
That seems like the best path.
we're already asking TypeScript users to change their syntax for private state
So TypeScript is going to change to using a symbol as well?
:sob:
R.I.P. Attractive languages.
Oh, sorry, I shouldn't've said that. TypeScript can do what it wants. Historically, TypeScript has followed backwards-incompatible changes to match JavaScript's evolution, and I was thinking that might continue here, but it might not.
I'd really be interested in the opinions of the TS team on this matter.
Status update: @wycats, @ljharb and I have been discussing a possible "sigil swap" between decorators and private state, where private state could use @
and decorators could use #
. Personally, I'm neutral on this issue. It's still not certain whether this will happen. I'll keep this thread posted on any progress.
I don't really see the point in that.
@
is already quite widely used, in TypeScript, previous Babel versions, and by the most popular JS frameworks (Angular 2, Aurelia, etc.)a
in the at symbol can refer to attribute
or annotation
, which makes sense for decorators@
doesn't really look any better than #
in this context (other than looking slightly less like a comment character)Please keep @
for the decorators, since I might want to use them.
:+1: for #
for private fields.
I'd even suggest using neat unicode chars but haven't quite studied what problems might arise.
@
has precedence as being instance-related from Coffeescript.
#
is now mostly read "hashtag", and "hashtag enumerable" for a decorator flows much more nicely when read aloud than "at enumerable".
I realize many people think of decorators as "annotations", but that's not what they are - although that's certainly one of the things you can do with them.
Counterpoint, for the record: Python uses @
for decorators.
If we allow pronounciation as an argument, we should first make a scheme for which native tongue is worth how many votes.
Fortunately, snark is worth zero points.
I'm sorry, I didn't mean to be impudent. I was just shocked for a moment by the imagination of "Gartenzaun enumerable" in german. Took me a second or two to think or "Raute enumerable" and it's not that much better. Made me worried whether other languages might turn out to have even worse words for characters that sound ok in english.
@mk-pmb Impudence is entertaining ; )
Personally, I find the octothorpe really distasteful as a private field designator and less distasteful when used for decorators. It's an aesthetic judgement and as such resists explanation, but I'll try anyway.
The #
character is, I think, overwhelmingly associated with comments in programming languages. We are accustomed to perceiving everything to the right of the #
as "outside" of the imperative flow of the program. To see it right smack in the middle of an expression is jarring. It creates a cognitive dissonance which can be overcome by repeated exposure. But one of the goals of javascript syntax is to provide a "familiar" programming environment for users coming from other traditional programming languages. We should not force cognitive dissonance on new users, if possible.
Even though decorators are an imperative programming feature, the syntax is designed to allow users to express themselves in a declarative fashion. From a strictly code-reading point of view, decorators are syntactically "outside" of the imperative flow. Furthermore, decorators will most commonly be placed on a line by themselves above the thing being decorated, similar to comments. Taking both of these points together, using #
for decorators introduces less cognitive dissonance than using #
for private fields.
Regarding Python and Java: of course it would be an obvious choice to use @
for decorators if we didn't also have to consider private fields. It is completely understandable why TypeScript made the mistake that it made in choosing @
, since it did not have to consider type-free private fields. However, TypeScript's mistakes don't have to be Javascript's mistakes.
From verbal discussions at the last (July 2016) tc39 meeting, echoed in the comments above, I have changed my mind and am now in favor of swapping # and @. In fact, I am now strongly in favor of it.
Even before the swap, I favored expr#name
over expr.#name
. With the swap, I feel even more strongly that expr@name
is superior to expr.@name
. Of the various reasons, the most amusing one: The @
glyph can be thought of as an overgrown dot.
expr@name
together with the @name
shorthand is an ASI hazard. But fortunately, I think @name
would be used most of the time, mitigating the aesthetic issues of expr.@name
.
Thanks @zenparsing, I've been struggling for some time to articulate my position on the subject and I think you've done it perfectly. I would much prefer to see @ for privates and # for decorators
Sorry. I am aware of the ASI issue and should have mentioned it. I would rather take the hit of specifying the infix syntax as no-newline-allowed to the left of the @
than to impose the .@
syntax on all user of JavaScript. I understand that introducing more no-newline-allowed cases into the syntax has costs. If we focus only on costs to users (JavaScript programmers), then the costs of no-newline-allowed for this case are largely theoretical while the costs of the extra dot are very practical.
Well, I think there's an existing idiom of putting .
on the next line. I guess this is mostly for method calls, but if we think we may later add private methods, it seems like a potentially important refactoring hazard if you couldn't do
foo@bar(baz)
@bing(quux);
when the same is possible with .
@littledan You are correct. I did not anticipate that layout, but it is convincing. Sigh.
@shelby3 wrote:
@bakkot wrote:
I don't think this issue is quite the place for that discussion, but the proposal is to use '#' for decorators because '#' is already an idiomatic (in the linguistic sense) way to indicate a descriptive tag.
Ah the social media revolution. But we are in the specialist realm of programming. Does the concept really carry over well. I didn't get it, even though I use hashtags in social media. My mind was focused on programming terms. Perhaps I am too old (51). I don't have my mobile phone in front of my face all day. (its on silent and turned face down for the past several days and went lowbatt, Lol)
hashtags for encapsulated fields. Mmm yeah that is very intuitive. (not)
@shelby3 wrote:
@ljharb engineers think that way, which is why they are horrible marketers. It doesn't work that way. The way users think is much more simplistic and direct, and not theoretical connecting hashtags in their experience in social media to encapsulated field access in programming. The two concepts don't relate, even though an engineer can dream up a definition and think they will. I've tried to name things and then been totally shocked when no one gets the theory of the name I had in my mind. I learned my lesson.
@shelby3 wrote:
@erights, you all say not to discuss it here, and I don't know where that discussion is. So I will just add one final point, which is I hope you all do focus groups with a sufficient sample of real (e.g. social media) users and programmers (from all demographics and ages) who are just becoming programmers (or what ever your theories claim) to test your theories about the translation of hashtags in social media to programming and other theories about relevance from obscure definitions. I hope you all actually measure and not just trust your theories. I predict you will be in for some surprises if you do. Theory and practice very often diverge. That is one reason to be conservative and reuse historic norms in programming languages. Also it takes a long time for all the effects of C and other preexisting languages to become impotent, because beginners are still learnig these languages anew. That doesn't mean asking your buddies in your committee. Groupthink is a powerful obfuscating effect. That is not an accusation of anyone. It is just something that happens to all of us and why we need to measure objectively.
The
@
glyph can be thought of as an overgrown dot.
This are exactly the sort of theories that are entirely meaningless when you test them in a focus group. No one will think of your abstract rationalization.
From what I can tell the arguments are purely aesthetic (vs technical reasons why one is better than the other, if I am mistaken please correct me).
There is a strong technical reason why we should stay with the current choice. It is that millions of lines of code have already been written using the current syntax for decorators. Going to hundreds of thousands of developers and asking them to change the code because some of us aesthetically prefer it that way is a hard sell given that there would be no technical benefits. Additionally there are linters, IDEs, code formatters and let's not forget transpilers which would have to be updated in a coordinated way so that the community can continue to build application. It would be a huge coordination effort without any business value.
Here are just some of the users of decorators as they are speced today. Frameworks (Angular, Aurelia) and libraries (core-decorators) which many developers depend on everyday to build their application. Angular 2 alone has close to 500K unique active developers per month. Many of the top fortune companies have already built and released their Angular 2 application into production. The numbers above are for Angular only, the overall community must be larger.
I get that these are not yet finished specs and that we are using them at our own risk. But most of the changes to the semantics and APIs can be absorbed in a backward compatible way by the decorator creators (frameworks and libraries). As long as the syntax of the decorators stays the same there is no work for the developers that use the decorators (vast majority of developers). So if there are technical reasons to change the spec, to get tangible technical benefits, I am all for it and will work at explaining the value to our users, but changing syntax on aesthetics seems like misplaced effort.
For the sake our community, please let's not do this.
Aren't all the current libraries and transpilers using completely different semantics from decorators compared to the latest specification? In that way it might actually be a blessing to switch the syntax, to match the switched semantics.
@domenic We may not be 100% aligned with the spec, but any changes would only effect the decorator authors not the decorator users. Additionally the decorators can be written in a way where they could detect which semantics / API the platform provides and auto adjust accordingly further shielding the decorator users.
I don't see how it would be a blessing. It would just be a huge amount of effort. Think about the coordination required. You want to upgrade to latest version of Angular which uses #
but your transpiler is not ready. Or your transpiler is ready but your IDE does not understand it. Then linters. Then some libraries are still using @
while others have switched to #
.
We may not be 100% aligned with the spec, but any changes would only effect the decorator authors not the decorator users.
That is not clear to me, but maybe it is true.
Think about the coordination required.
Right. This is the blessing. Otherwise you have half your tools interpreting your decorators with one set of semantics, and half your tools interpreting them with another set of semantics. With a sigil switch, everyone has to have the same understanding. (And tools could even have both understandings at once---old with @, new with #.)
When you say semantics I assume you mean that different decorators will be using different APIs to get their job done. Such APIs can easily be polyfilled. On Angular team we do this all the time. We change APIs in backwards compatible way, provide temporary fills. A well understood problem.
Every decorator I have seen in a wild so far has been pretty straight forward and simple in what and how it does things. I get that decorators can have complex behavior where semantics could matter, but in practice it does not.
I would gladly take the API change over syntax change any day. Especially if the API change provides technical benefit.
Where is the technical value in changing syntax in this case? If there is no value, then why are we doing it?
PS: Please don't try to sell it to me as a blessing, because it is not. Sell it on technical merits.
We may not be 100% aligned with the spec, but any changes would only effect the decorator authors not the decorator users. That is not clear to me, but maybe it is true.
It was certainly a goal of the most recent draft, and I'd be very open to tweak to it to make it more true if necessary.
In the past, I've expressed some enthusiasm about the sigil swap, but when I brought it up last (in Munich, six months ago), I mentioned that it was probably our last opportunity to do the swap.
I pretty much agree with Misko that the appeal of decorators is that many, many more people use decorator functions, (using rather abstract and simple syntax), than are needed to write and maintain the decorator libraries themselves.
It's probably on the same order as jQuery or underscore in terms of the split between the author and consumer (and just as with underscore and jQuery, there are a certain amount of people who write their own decorators in their apps, but they are dwarfed by the number of people using decorators through libraries).
I get that decorators can have complex behavior where semantics could matter, but in practice it does not.
@bterlson and I worked through core-decorators, which is probably the place doing the most semantically involved decorator work, and tried to make sure that the current draft would continue to support them. As I said, if that turns out not to be true for some reason, I'd be quite open to changes.
Regardless of whether any decorators in the wild exist whose semantics could not be replicated using the current draft, a huge percentage of decorators I've seen are, as Misko said, relatively simple transformations whose names and parameters would maintain valid despite changes to the internal mechanics of decorators.
I'm still persuadable about a sigil swap, but I think the benefits would have to be stronger than the ones already enumerated.
Thank you @wycats
Where is the technical value in changing syntax in this case? If there is no value, then why are we doing it?
The technical value is in ensuring that tools and libraries consistently interpret decorators with the same semantics.
PS: Please don't try to sell it to me as a blessing, because it is not. Sell it on technical merits.
I understand that consistent semantic interpretations may not be a blessing to you, so I will avoid using that word. Still, from my perspective, it is a "good thing" (not using the prohibited word). And I imagine that others on the committee will find that to be the case as well.
For example, it would be disastrous to combine a version of Angular that uses old semantics with a version of TypeScript that uses new semantics. Using different sigils for each would give an early error on attempting this (or would Just Work, if TypeScript maintained both versions). Whereas using the same sigil for both would give strange errors, probably at runtime, or even just subtle bugs that don't result in errors but instead in misapplied decorations.
I understand that consistent semantic interpretations may not be a blessing to you, so I will avoid using that word.
As I said, I'm still persuadable here, but this wouldn't be the first JavaScript feature that went through significant semantic changes after transpilation was already available (classes went through pretty significant semantic changes at the last minute).
Especially since the changes happened between Stage 1 and Stage 2, and the fact that they impact implementors of decorator functions more than users, changing the syntax just to signal that some changes have occurred seems like a pretty big hammer to use here.
@mhevery wrote:
but any changes would only effect the decorator authors not the decorator users.
@wycats wrote:
I pretty much agree with Misko that the appeal of decorators is that many, many more people use decorator functions, (using rather abstract and simple syntax), than are needed to write and maintain the decorator libraries themselves.
Readability is the most important feature of a language by none[1], according to Eric S. Raymond, especially as open source (the term he invented/promulgated instead of free software in his famous Cathedral and Bazaar analogy and essay) has proliferated.
Familiarity is one of the most important factors in these choices, because it reduces the number of cases and concepts (i.e. the cognitive load) and contributes to more immediate recognition.
That so many languages copy each other's concepts and syntax, is why I can pick up a new language in 24 to 48 hours these days as my experience has grown.
Newness/change isn't necessarily a virtue unless it is really needed.
When I was first learning Haskell and Scala (and still sometimes with Scala because it can use as methods names as infix at the use site with any gobbledygook symbols string), these strange symbol semantics that I had never seen before was one of the hindrances to being able to deduce the code semantics. It required painstaking lookup of all the symbols and their semantics.
@domenic wrote:
Aren't all the current libraries and transpilers using completely different semantics from decorators compared to the latest specification? In that way it might actually be a blessing to switch the syntax, to match the switched semantics.
Arguing that the transition is easier because of forcing a change away from familiarity seems to be highly dubious to me. I bet if you tested that on a focus group, you would discover that familiarity is the most important. But better to confirm than to trust my intuition.
[1] He actually said paraphrased, "Over time I've become convinced that readability, that is the ability to read your own code after you haven't looked it for a long time, is the most important feature of a language bar none".
I get that these are not yet finished specs and that we are using them at our own risk.
If you bet an ecosystem on a stage 1 proposal I'd say that's a huge risk.
There was a history of language proposals for ecmascript using the @ character for field and property names, not to mention the existing usage of @@ in the current specification to represent built in symbols. This existing history seems to have been ignored.
If you bet an ecosystem on a stage 1 proposal I'd say that's a huge risk.
I don't disagree, and as I've said, I was once somewhat enthusiastic about the sigil swap (before Angular 2.0 RC1).
There was a history of language proposals for ecmascript using the @ character for field and property names, not to mention the existing usage of @@ in the current specification to represent built in symbols. This existing history seems to have been ignored.
Honestly, this feature sort of dragged at Stage 1, and we didn't take the opportunity to discuss and come to a conclusion about the sigil swap in the beginning of this year. At this point, we're well within our rights to tell early adopters of the syntax that they'll have to make a change, but we need a stronger justification than other proposals that aren't much used via transpilers or spec internals.
(fwiw, Ember chose to wait on decorators until they were advanced to Stage 2, so I don't have a personal stake in this)
@wycats wrote:
we need a stronger justification than other proposals that aren't much used via transpilers or spec internals.
What is the incentive for switching from @
to #
other than to give @
to the proposal for private
properties?
Because if that other proposal rejects the use of @
or a sigil (which IMHO I think is somewhat likely or let's say plausible if my logic is compelling), then what other incentive remains?
It appears that @
for decorators is reasonably well established both for other popular languages such as Java, and (based on statements upthread) also within the the existing ES/JS ecosystem. So I am wondering what possible justification could override what seems to me be a slamdunk obvious choice?
It is great to wrangle+deliberate over it and cover all the bases. This one seems so obvious to me, but I ask because I didn't read the entire discussion (very late to this party), so wondering if someone could summarize the major justification? The tl;dr?
I am obviously biased heavily in favor of consistency of use of symbols and other constructs across programming languages when there is no greater overriding justification to do otherwise. And this bias is because developers are becoming more multi-lingual in the open source era. Code is another way we talk to each other and the community now. We are no longer lonesome teams in a closed-source company as we were in the 1990s and before.
I obviously am not arguing that all languages should be identical in every way. I am arguing that for commonalities, we shouldn't differ without significant justification to do so.
No disrespect to @domenic intended. I was thinking more about his most recent point while I was driving, and it seems to me that the overriding concern is how the language performs over the long-term, not some short-term argument unless that short-term argument is fully compelling, overriding in importance to the long-term, and we are sure that the compelling case is true. I am not even sure that the effect @domenic argued is even how the game theory plays out (game theory is very often miscalculated), and even if so, how compelling is that short-term benefit compared to diverging long-term from the consistency of other popular uses of @
for decorators. Perhaps I am not aware of all the popular programming languages that use #
for decorators???
Also I want to make more clear my point upthread about how theoretical connections rarely are true in reality. We may think that if #
has been popular for comments in programming languages and as linguistic prefix for a tag in social media, that this somehow translates to understanding+familiarity when used as a decorator. I believe not at all (based on my experience with focus groups and theories I've had). Decorators are their own unique thing. It is somewhat analogous to theorizing that if apples are popular+familiar+understood for apple pie, then beef is popular+familiar+understood for desserts.
P.S. Apologies my prior comments were made punch-drunk due to sleeplessness and also rushing out the door to meet a deadline. And I'm still operating on only 3 hours sleep.
Swapping @
and #
will affect a lot of Angular 2 (and Ember?) users but on the other side even #
should be adopted by TypeScript (instead of or along with private
) to fit ECMAScript specification. So it was Angular 2 design fault to use decorators everywhere. Personally I am being TypeScript user don't rely on private
keyword or decorators to be sure my code is future-proof (but I don't use Angular 2 TBH). I wonder why doesn't TypeScript provide these features under some sort of experimental
compiler flag if it tries to be JavaScript's superset? All arguments for swapping look reasonable.
@domenic, @ljharb, @bakkot readibility is far too important in open source to go changing the sigil every time we want to version a breaking semantic change. We'll have chaos out there for readers who are trying to read open source code (different DVCS branches with different decorator syntax, etc). Since the point and semantics of the decorator sigil is it can be followed by nearly any text, then I trust the free market can version them (within that text) how it best sees fit with more degrees-of-freedom fitness closer to each tool set case than we could with top-down chaos forced on everyone. You might retort that coordination is required to come from the top-down. Yet the readers pay the cost for this coordination "benefit". And long-term we all pay the price of having a generator sigil which is not consistent with other popular languages. "Why did JavaScript change (adopt) their sigil to be different than Java, Python, etc?". And we'll have to explain it was because the transition to the ES standard was going to messy for developers either way and we wanted to make the short-term somewhat less messier for them (we hypothesize, but perhaps we have no clue how the mess will sort out) at the expense of the reader and the long-term (intra-language and iter-language) consistency.
@domenic I noticed you downvoted all my comments. Note I only downvoted @ljharb's one comment because regardless of how @
came about (@nnotations), that is irrelevant now. What is relevant are the impacts on the inertia that exists with changing that sigil choice. I did not downvote your comments, because I can't clearly state they are wrong and I can only argue why I think they are not optimal. If you think all my comments are wrong (or if that is not the intended meaning of your downvote), I appreciate you expressing that. I just wanted to clarify my downvote. I upvoted comments that I think are making stronger arguments than others (and nothing wrong in the comment). So my requirements for a downvote are more stringent than for an upvote.
I am obviously biased heavily in favor of consistency of use of symbols and other constructs across programming languages when there is no greater overriding justification to do otherwise.
For what it's worth, Ruby uses @foo
to mean "private field lookup".
@chicoxyzzy From my understanding, I think the two could co-exist, but it would certainly be a pretty big confusion for new users. But I mostly see that as part of another discussion.
The question is whether or not the sigil swap should take place. You can always say that users/authors/tool writers shouldn't have "taken a bet" on these features, but the fact of the matter is that a lot of people have at this point. In addition to the above, I'll also mention that MobX is successfully using decorators in their current form (@mweststrate).
Regarding the aesthetic perspective: if #
is aesthetically unacceptable for privates, what exactly makes them any more acceptable for decorators? Is there a sentiment that users of decorators would be just as happy with #
? I don't think we can confidently say that, but I can bet users don't want to have to swap the symbols around in their working code either.
@DanielRosenwasser, #
is more aesthetically acceptable for decorators because it is already used to indicate a descriptive tag in both programming (comments in Python, shell scripts, and other languages) and in internet vernacular. And we need to consider future users, not just current ones (who are a very small subset of eventual users).
@bakkot I might even agree that #
is more aesthetically accepted or at least let's say familiar as a prefix for hashtags and comments, but those are not like decorator/annotations which operate on some target. I can't agree #
is any where near as familiar for annotations in programming languages. And afaik we are concerned here with annotations (and general decorators functionality) in programming languages, not other general uses of prefixes of text which are not similar.
@wycats wrote:
For what it's worth, Ruby uses @foo to mean "private field lookup".
Its only one language that apparently doesn't have significant family familiarity with JavaScript, and certainly isn't as familiar for private access as `private'.
Decorators aren't annotations - annotating is just one thing you can do with decorators. As such, using Java's "annotation" character (@
) isn't necessarily appropriate.
@ljharb I wrote, "but those are not like decorator/annotations which operate on some target". Annotations are more similar to semantics of decorators than comments and hashtags.
Decorators have no common functionality and familiarity with comments and hashtags, or do they?
We are competing against preexisting familiarity. If we were starting with a clean slate, I argue we could more readily argue for general acceptability instead.
Edit: then again, I have much less issue with using #
for decorators (if we didn't have all the inertia with @
for existing JS code), than I do with butchering private
and this
for private access control and replacing them with a sigil and which opens up new opportunities programmer mistakes when they inadvertently access through this.x
instead of #x
.
Also there's no need for the duality here, it's not one xor the other. We could use .#
or .@
for private property access.
I noticed that in this commit the symbol was changed from
@
to#
. Was there any reasoning behind this?