Inconsistencies in `prototype` shorthand (::) and `this` shorthand (@) #1601

Open
geraldalewis opened this Issue Aug 12, 2011 · 96 comments

Projects

None yet
@geraldalewis
Contributor

The :: .prototype(.) shorthand should behave consistently with the @ this(.) shorthand.

Adding symmetry in how each shorthand is implemented will give developers a better mental model of their behavior and reduce issues.

@ currently compiles to a literal this, access this. or invocation this( depending on context.
:: currently compiles to a literal .prototype or access .prototype. depending on context.
It does not compile to an invocation.

@ will not behave as :: in every context. Below is a breakdown of where they behave consistently and where they behave inconsistently.


Consistent

# JavaScript output indicated in comments
# code wrapped in -> as :: can indicate a line continuation

as value (unless :: standalone)

-> @              # this
-> C::            # C.prototype

member access (unless :: standalone)

-> @member        # this.member
-> C::member      # C.prototype.member

index

-> @['member']    # this['member']
-> C::['member']  # C.prototype['member']

applying ::

-> @::   # this.prototype
-> C:::: # C.prototype.prototype

Inconsistent

invocation

class C; C:: = (a) -> console.log a

-> @ 'invoke'     # this('invoke');
-> C:: invoke     # C.prototype.invoke; // (acts as member access)
# -> C:: 'invoke' # error (unexpected 'STRING')

list comprehensions (from #1477 by @dbrans)

for k of @ when k isnt constructor then   # for (k in this) { if (k !== constructor) {} }
for k of A:: when k isnt constructor then # for (k in A.prototype.when(k !== constructor)) {}

instanceof

@ instanceof C   # this instanceof C;
C:: instanceof B  # C.prototype["instanceof"](B);

standalone

-> @              # this
# -> ::           # error; any use-case?

standalone member access

-> @member        # this.member
# -> ::member     # error; any use-case?

Proposal

:: should:

  • still raise an error if used standalone
  • behave like @ in all other ways:
    • not indicate a line continuation
    • work in list comprehensions
    • be callable Edit: See @jashkenas comment
      (it technically is, but it looks like this line prevents implicit calls)

or

  • :: should always compile to .prototype.
  • @ should always compile to this.
  • @ should continue lines

Personally, I'm in favor of #1


Related issues: #1477, #1554 (fixed), #1234 (fixed)

@jashkenas
Owner

Making it callable to be more consistent is one thing ... but there's never a real-world use case where your prototype object is actually a function you'd want to call ... is there? I certainly can't think of one.

@geraldalewis
Contributor

@jashkenas Agreed; [I couldn't find any use-cases](http://www.google.com/codesearch#search/&q=%5C.prototype%5C(%20lang:%5Ejavascript$%20case:yes&p=6&sq=&type=cs). In fact, it might cause some confusion/issues. Updated the issue.

@michaelficarra
Collaborator

@jashkenas: Even if it's not a common use case, it's better to allow implicit calls so that it is consistent with a regular member access. { prototype: -> }:: 0 should compile to a function invocation because { prototype: -> }.prototype 0 does and they should behave identically.

I agree with everything from @geraldalewis's (edit: original) post, including the recommendation. For the unary ::, see my proposal in #1220. I'm still in support of it.

@jashkenas
Owner

Personally, I'm somewhat a fan of disallowing standalone @ and standalone Obj:: entirely. These inconsistencies demonstrate why.

For readability's sake, I don't know why you wouldn't always choose to write: this and Obj.prototype

@michaelficarra
Collaborator

One more consistency worth noting:

@::   # this.prototype
C:::: # C.prototype.prototype

They can both have :: applied to them.

@michaelficarra
Collaborator

@jashkenas: I think standalone @ or obj:: are in use all over the place, so that might cause a little bit of an uproar. But I'm really not one to care about that kind of stuff. Either way, I think they're not exactly pretty but the consistency outweighs the ugliness. If you don't like how they look, you can always use this and obj.prototype. So I think they should stay.

@aseemk
Contributor
aseemk commented Aug 12, 2011

@jashkenas: standalone @ I've come to find really nice. It really is shorthand for this. Less keystrokes, stands out, etc. Not a big deal, of course, but it's a nice little thing I've come to like.

@geraldalewis
Contributor

@michaelficarra You raise some good points. Regardless of its practical viability, the proposal calls for symmetry with @ where it's correct to do so (e.g., error on standalone ::), and a callable :: is technically correct.

ES5 Spec:

Function's prototype is a function that accepts any args and returns undefined

Callable :: is also consistent with @ (as your example points out). I won't re-edit my original post, since the strikethrough has been referenced, but I'm once again in favor of a callable ::.

@jashkenas I favored standalone @ over this for a bit before I too came to the conclusion that this is more readable. I felt I was writing in the idiom of CoffeeScript by using standalone @. Ironic since there's such focus on readability in CoffeeScript. I understand why you'd want to lose them. I do like them, and find them to be readable, in loops k for k of @, k for k of C::

Also, another inconsistency:

@ instanceof C   # this instanceof C;
C:: instanceof B  # C.prototype["instanceof"](B);
@satyr
Collaborator
satyr commented Aug 13, 2011

Note that @pthis.p doesn't always hold:

$ bin/coffee -bpe '{@p}'
({
  p: this.p
});

$ bin/coffee -bpe '{this.p}'
Error: Parse error on line 1: Unexpected 'THIS'
...

$ bin/coffee -bpe '{@::}'
Error: Parse error on line 1: Unexpected '::'
...
@geraldalewis
Contributor

@satyr That's interesting. What was the rationale for not allowing

{this.p}

?

@michaelficarra
Collaborator

@satyr: Nice catch. We should make it so.

@geraldalewis: #1089. It really should be allowed.

@rstacruz
rstacruz commented Sep 1, 2011

Also, {a.b: c} doesn't work as well.

@satyr
Collaborator
satyr commented Sep 1, 2011

{a.b: c} doesn't work as well

What's the expected compilation?

@rstacruz
rstacruz commented Sep 1, 2011

@satyr, oops, that was never valid JS to begin with. Sorry about that, just assumed it was.

@michaelficarra
Collaborator

@geraldalewis: what's the status of this issue? Are you still planning to work on it? I'd love to see this all fixed.

@geraldalewis
Contributor

I'm still in favor of proposal #1 (I'm again in favor of making :: callable, though I'd redacted it earlier):

:: should:

  • still raise an error if used standalone
  • behave like @ in all other ways:
    • not indicate a line continuation
    • work in list comprehensions
    • be callable

I haven't moved forward with a patch because it didn't look like it had strong support (@jashkenas voiced misgivings about having standalone @ at all). Though maybe until that point the @'s fate is decided, it'd be helpful to have it and :: act consistently?

#1089 (Accesses in LHS & RHS destructuring assignments) still feels like its own issue -- do you agree? Or was that the issue you'd like to see fixed.

@satyr
Collaborator
satyr commented Sep 6, 2011

#1089

@jashkenas: ... we should remove {@foo}. The reason why it's there is because @foo is treated like an identifier, grammar-wise.

Sounds like we're removing it. And with that logic, (@name) -> should be disallowed as well.

@jashkenas
Owner

Yep, I'm afraid I still have strong misgivings about it.

not indicate a line continuation

:: is a close cousin of ., but instead of referring to a property on an object, you're referring to a property on the prototype of an object. If you can write:

object.
  property.
    value

you should equally be able to write:

object::
  property.
    value

be callable

Again, :: should feel like . when you use it. If you can write a. b to mean a.b, then a:: b should mean a::b in the same fashion.

@geraldalewis
Contributor

you should equally be able to write:

I think this is where standalone-@'s inconsistencies appear again:

this.
  property #this.property;

@
  property #parse error

If you can write a. b to mean a.b, then a:: b should mean a::b

Again, there's an inconsistency with standalone-@:

this. a    # this.a;
@ a        # this(a);
@jashkenas
Owner

Yes, and that's why standalone @ is the unsatisfactory bit of syntax to blame here. On both readability grounds and inconsistency grounds.

Does it want to mean this or does it want to mean this.? If we choose the latter, that implies getting rid of standalone @.

@geraldalewis
Contributor

Now I get it. Even if we patched the inconsistency between @ and ::, @ would still be inconsistent with this. (in some contexts) and :: would then be inconsistent with o.prototype.. "Fixing" the inconsistency would create more inconsistencies... Ouch.

In favor of removing standalone-@s now (which would also resolve this issue).

@jashkenas
Owner

A good change for a 1.2 release? Let's do it.

@michaelficarra
Collaborator

So I'm still not quite clear on the status of this discussion. Does this mean we're getting rid of both standalone @ and postfix unary ::?

@jashkenas
Owner

Yes please. Let's keep the sigils limited to the cases where the trailing dot makes sense. this. and .prototype., respectively.

@michaelficarra
Collaborator

Okay, I'm cool with that. It makes sense. There's going to be some unhappy users though. Can't wait for the backlash...

@pyrotechnick

+1

We support the removal of ambiguity and thus welcome change. Although this one is particularly bitter-sweet since we have @ all over the place :(

At least it's reasonably easy to replace.

Now would be a great time to sanction a single option for the other ambiguous parts of CoffeeScript.

@devongovett

Totally in favor of these changes. I never used standalone @ anyway preferring this in that case for readability. I only used @ when accessing members or calling functions. As for Obj::, that just looks funny, and yes, I think for consistencies sake it should act like a . as @jashkenas stated above.

+100

@geraldalewis
Contributor

sanction a single option for the other ambiguous parts of CoffeeScript.

Any issues in particular come to mind?

@pyrotechnick

(Object.keys foo).length

vs

Object.keys(foo).length


do foo

vs

foo()

@jashkenas
Owner

Sure thing, Object.keys(foo).length is canonical, but the former will always continue to work.

@michaelficarra
Collaborator

I'm strongly in favour of (Object.keys foo).length, but I try to use the Object.keys(foo).length style when working on the compiler. But I feel the former is a much more clear style because the result of the function invocation is a value, upon which we are accessing the length member.

@pvande
pvande commented Sep 7, 2011

I'm going to guess that this change makes the @[key] syntax officially deprecated as well, then. Confirm / deny?

@jashkenas
Owner

Absolutely deny. This change is just to remove @ as this, all by itself.

@pvande
pvande commented Sep 7, 2011

Let's keep the sigils limited to the cases where the trailing dot makes sense. this. and .prototype., respectively.

Thanks for the clarification; I hope you can see where the confusion might have stemmed from. Good to have it on record.

@pyrotechnick

There's also the case of @.something which currently transforms to this.something;. I have never used or seen this being used so I presume it's going too?

@jashkenas
Owner

Yes, you would write @something instead.

@misfo
misfo commented Sep 7, 2011

Absolutely deny. This change is just to remove @ as this, all by itself.

Isn't @['something'] a case where the trailing dot doesn't make sense? this.['something'] is a syntax error in JavaScript...

@jashkenas
Owner

I'm sorry -- I wasn't being exhaustive. I mean this. or this[] ... where [] is the dynamic way to access a property. Ditto for object::[key], naturally.

@jashkenas
Owner

Good question. It's nasty, but I'd lean towards allowing it, as long as there was a suffix. @::prop or @::[key]

@satyr
Collaborator
satyr commented Sep 7, 2011

What about @?.something?

@devongovett

@?.something better be allowed! I use it everywhere!

@jashkenas
Owner

I'd say SyntaxError -- that's treating @ as a value, not a prefix.

@satyr
Collaborator
satyr commented Sep 7, 2011

So @[key] is allowed, but @?[key] is not?

@jashkenas
Owner

@devongovett: got an example you can share?

@devongovett

NOOOOOOO! OK, calming down now. I REALLY don't want to have to write this?.something everywhere though. @?.something is so nice!

I think standalone @ should be removed, as in for prop in @, because that is ugly, but for the same reason stated above by @jashkenas for @::prop, "as long as there was a suffix" applies here as well. It has a suffix. It just happens to have a ? between it and the property it is accessing. Same function (retrieving the something property off this), but it just happens to check existence before accessing it. Right?

@devongovett

Hmmm... it must be early. Just realized that: "why would this NOT exist". :P So, I guess I'm OK with this. It was more @something?.somethingElse that I use regularly. Sorry about that. :)

@jashkenas
Owner

OK -- fair enough, you're right. It has a suffix, it's still a prefix. Let's allow it.

@pvande
pvande commented Sep 7, 2011

I'm really not interested in thinking about the cases where you could legitimately expect this to be undefined.

@wavded
wavded commented Sep 7, 2011

one more thought to put into the mix. I have always understood to @ to mean something that is part of the variable name. kinda like $name in PHP or Perl. So something like

  @ name  # note space

Feels like a syntax error to me.

@pyrotechnick

@wavded @ foo currently calls this with foo and is useful (if your function is bound to a function).

But that is now this foo...

@wavded
wavded commented Sep 7, 2011

right, I was referring to a comment above:

#1601 (comment)

But the callable aspect seems off too IMO, i would think that would be syntax error as well.

Just my 2 cents

@TrevorBurnham
Collaborator

Whoa, whoa, I just caught @jashkenas' tweet on this, which was no doubt intended to attract dissent, so here it is...

Having two short names for the same thing is annoying. But I'd much rather disallow this than @.

As @aseemk put it,

standalone @ I've come to find really nice. It really is shorthand for this. Less keystrokes, stands out, etc.

"Stands out" is the key here. A very large fraction of mistakes that JavaScript and CoffeeScript coders make is from forgetting that this means something else from a callback. this is such a singular concept that it makes perfect sense to give it its own character with no other meaning in the language, just to make it easier to spot (not to mention grep). Yes, it's aesthetically odd—especially coming from JavaScript—to see something like

$('a').click ->
  href = $(@).attr 'href'

But @ should be glaring. It shouldn't look like just another variable name.

Look, I realize that it would be too opinionated for us to actually ditch this, but I think it belongs in the same category as && and ||, the category of "things that make it easier to paste in JavaScript code but aren't considered proper CoffeeScript style." If the CoffeeScript community embraced the consistent use of @ over this, the result would be more readable, less error-prone code.

(Relatedly, I've heard a lot of people calling for an "official" style guide, like Python has. I was thinking of writing one for the wiki. Sound good?)

@michaelficarra
Collaborator

@jashkenas: Are we keeping F::::m? Technically the first operator is a trailing ::, upon which an approved use of the :: operator is applied. So by your arguments above, we would be disallowing it.

@jashkenas
Owner

@michaelficarra: I'd rather not, unless there's a real-world use case for it. Usually, you'd never have a prototype directly on a prototype -- rather on the constructor.

@kgn
kgn commented Sep 7, 2011

I'd like to cast a vote for keeping stand alone @. I just wrote some code yesterday that returned @ at the end of some functions so I could easily chain calls. This is also useful when writing jQuery plugins which should almost always be chainable.

Here's a stripped down example of my code:

class Canvas2d
    constructor:(id)->
        @canvas = document.getElementById id
        @ctx = @canvas.getContext '2d'

    rect:(x, y, width, height)->
        @ctx.rect x, y, width, height
        @

    fill:(style)->
        @ctx.fillStyle = style
        @ctx.fill()
        @

    stroke:(style)->
        @ctx.strokeStyle = style
        @ctx.stroke()
        @

canvas = new Canvas2d('canvas')
canvas.rect(0, 0, 100, 100).fill('green').stroke('red')
@aseemk
Contributor
aseemk commented Sep 7, 2011

I try not to be reactionary to changes like this, and I've already spoken that I and my team have come to find standalone @ quite nice, but I'll just add that (a) we use @ for jQuery just like @TrevorBurnham shows in his example, and (b) that's some beautiful code, @InScopeApps!

@michaelficarra
Collaborator

@InScopeApps: I don't think you understand. You can still return this. Just the currently available @ standalone shorthand for this is being removed.

class Canvas2d
    constructor:(id)->
        @canvas = document.getElementById id
        @ctx = @canvas.getContext '2d'

    rect:(x, y, width, height)->
        @ctx.rect x, y, width, height
        this

    fill:(style)->
        @ctx.fillStyle = style
        @ctx.fill()
        this

    stroke:(style)->
        @ctx.strokeStyle = style
        @ctx.stroke()
        this

canvas = new Canvas2d('canvas')
canvas.rect(0, 0, 100, 100).fill('green').stroke('red')
@aseemk
Contributor
aseemk commented Sep 7, 2011

@michaelficarra I think he/she understood that just fine and was commenting that standalone @ makes the code nicer. =)

@kgn
kgn commented Sep 7, 2011

@michaelficarra true, I just find @ to be a beautiful feature of CoffeeScript and having to mix @ and this seems more cumbersome because you'd have to know when you can use @ and when you have to use this.

@aseemk he :)

@jashkenas
Owner

@InScopeApps, @aseemk: If you want to make the case for @ -- do you have ideas or preferences for how to handle the callable value vs. prefix inconsistencies listed at the top of this thread?

@kgn
kgn commented Sep 7, 2011

@jashkenas I don't have a problem with the inconsistencies between @ and ::. I've been happy and impressed with how 'smart' @ and :: were.

As for @geraldalewis's example this does work:

@.
    something

This is different then other use-cases of @ but requiring the . in this case seems better then having to use this in some cases for several reasons: 1) the syntax doesn't need to change 2) at least in my coffeescripting I have never used this syntax, but I've returned @ several times 3) removing standalone @ means that @ and this would have to be mixed.

I don't think there is a case in the current syntax where you ever have to use this, this is a great feature of CS that I would hate to loose.

@aseemk
Contributor
aseemk commented Sep 7, 2011

@jashkenas I don't have any good ideas for how to fix the inconsistencies, but from the start of the thread, I've wondered why the inconsistencies were worth worrying about in the first place.

What I mean is, the inconsistencies seem to be edge cases*, so are they worth fixing if it means removing one of the more commonly used parts of CoffeeScript?

* E.g. even though prototypes can technically be callable, there are no examples in the wild [according to @geraldalewis's Google Code search link] where people actually call prototypes directly. And I have no data here, but in my experience, people generally call prototype functions with call or apply since otherwise the function would always have the prototype or constructor as this, which you almost never want, and calling with call or apply works today just fine.

@geraldalewis
Contributor

@wavded wrote:

I have always understood to @ to mean something that is part of the variable name. kinda like $name in PHP or Perl. So something like @ name # note space Feels like a syntax error to me.

I like the sentiment, but that's the kind of inconsistency I propose we get away from. A Coffee dev's mental model should be:

Whenever I see @, mentally substitute this.

Anything that impedes building that model:

@ means this. I can write this. property, but @ property just raised a syntax error. @ must have some weird rules...

creates that little bit of anxiety that makes programming less fun.

@aseemk
Contributor
aseemk commented Sep 7, 2011

Do people really write @ foo (with any amount of whitespace between @ and foo) expecting it to work as a property access? This might not be an answerable question, I realize, but just wondering if anyone will chime in and say they do or did.

@wavded
wavded commented Sep 7, 2011

@aseemk, never crossed my mind till this issue

@kgn
kgn commented Sep 7, 2011

@geraldalewis @. property does work, though I don't think this should be a recommended(or maybe allowed) style. I haven't experienced any anxiety over @, in-fact the current behavior of @ is one of the reasons why CS is one of the most fun languages I've coded in!

@weepy
weepy commented Sep 8, 2011

If you get rid of standalone @, does that mean that @[dynamic_prop] will have to die too ? Whilst I can see it's a good idea to improve consistency, I fear that ultimately we'll end up making everyday CoffeeScript more confusing by this move.

@michaelficarra
Collaborator
@kgn
kgn commented Sep 8, 2011

While coding yesterday I was reminded of another nice use of standalone @ in the call function.

myFunc.call @, args...
@disolovyov

@geraldalewis I believe, this mental model shouldn't be about output code concatenation, after all. Thinking about glueing JavaScript promotes the abuse of CS to JS conversion implementation. Yes, CoffeeScript is just JavaScript, but I'd rather interpret this as a semantical equality, not plain syntactical macro expansion.

By this logic, nothing wrong with standalone @ — just semantics, special to CS.

@alexkg
alexkg commented Sep 9, 2011

Inconsistent or just different?

Let's not forget that unlike the other two forms :: and ., @ denotes a receiver, and so I think it's perfectly reasonable that standalone it can be used as a reference to that receiver.

If there's any hard-and-fast rule in this situation I think it's that space means application, i.e. that separating prototype access by an identifier should be considerer erroneous application, not access.

The indented case can be treated differently (since we can't have indented application), so we might say indentation followed by an identifier means access.

So I'm adding my -1000 for this one...

@aseemk
Contributor
aseemk commented Sep 9, 2011

I think I'm starting to see the light on this one -- I agree w/ you, @alexkg.

@jashkenas, I like the way you compare :: to ., e.g. that if you can have whitespace after a ., you should be able to have whitespace after :: too. I think that's great and worth keeping.

If you want whitespace after @ for access, you can simply append a . to the @. This is nice because it allows both things: standalone @ as well as whitespace before access.

@michaelficarra
Collaborator

Very good points in the above two comments.

@showell
showell commented Sep 9, 2011

Yet another way to look at "@" is that it is always semantically equivalent to "this", and then you just view "@bar" as a very convenient shorthand/contraction for "@.bar". More precisely, the model is that you can contract "@." to "@" when it's followed by a keyword.

See below:

~ > coffee -ecb "@"
this;
~ > coffee -ecb "@.bar"
this.bar;
~ > coffee -ecb "@[bar]"
this[bar];
~ > coffee -ecb "@(bar)"
this(bar);
~ > coffee -ecb "@ bar"
this(bar);
~ > coffee -ecb "@. bar"
this.bar;
~ > coffee -ecb "@bar" # @bar is a legal contraction for @.bar
this.bar;
@michaelficarra
Collaborator

@showell: I'm convinced. I think those are perfectly sane compilations.

edit: Thought I should note that I'm still for removal of trailing ::. I can't see a way to make that consistent.

@geraldalewis
Contributor

@ denotes a receiver

as well as access, no? Just as :: denotes both a receiver and access. Maybe my wires are crossed -- mind embellishing?


If there's any hard-and-fast rule in this situation I think it's that space means application, i.e. that separating prototype access by an identifier should be considerer erroneous application, not access.

I wish things were so clean :)

ES5 Spec:

Function's prototype is a function that accepts any args and returns undefined

And as @pyrotechnick clued me in on: function prototypes [are not unheard of](http://www.google.com/codesearch#search/&q=%5C.prototype%5C.apply%5C(%20lang:%5Ejavascript%24%20case:yes&type=cs)

@ arg #this(arg) is an almost equally uncommon pattern in my experience.

If you want whitespace after @ for access, you can simply append a . to the @.

Which might be seen as:

this..
  property

I don't personally mind @ so much, it's the ambiguity that bothers me. Here's what a CoffeeScript developer needs to currently understand about @:

@ -> this
@ -> this.
@.property -> this.property (not descendant access: this..property)
@ arg -> an invocation with arg as its argument: this(arg)
@arg -> a property access: this.arg
@\nproperty -> this;property
this.\nproperty -> this.property

Also, use :: just as one would @, except:

C:: arg -> is not invocation C.prototype.arg
C:: instanceof B -> reserved words are even worse: C.prototype["instanceof"](B);
c for c of C:: when c -> results in a mangled loop for (c in C.prototype.when(c))...

The proposed behavior is:

@ -> this.
:: -> .prototype.

I'd like to clarify that it's not just that I prefer that there are fewer things to understand about the syntax, it's that the behavior is transparent and clearly derived.

I think we'd all agree that one of the best things about CoffeeScript is that it clears up some of the more ambiguous aspects of JavaScript. There is no mandate that CoffeeScript stays clean and unambiguous. It is more complex and less complicated than JavaScript, and I'd love for it to stay that way.

@alexkg
alexkg commented Sep 9, 2011

@geraldlewis

as well as access, no? Just as :: denotes both a receiver and access. Maybe my wires are crossed -- mind embellishing?

Yes, as well as access. :: doesn't denote a receiver really, just a different kind of access. It still requires the receiver to be supplied e.g. @::.

Function's prototype is a function that accepts any args and returns undefined

Well, it's only "erroneous" if the prototype is an object. I still think the space should mean application, just like the rest of CoffeeScript.

@ arg #this(arg) is an almost equally uncommon pattern in my experience.

class Thing

    @factory = ->
        new @ args...

I don't personally mind @ so much, it's the ambiguity that bothers me.

@ is pretty easy to interpret in a variety of contexts – the standard rules for identifiers apply, with the additional shorthand pointed out by @showell above.

I think the ambiguity comes from :: having multiple meanings:

  1. it behaves in a similar way to ., i.e. to provide access with optional space before the key.
  2. it behaves in a similar way to @, i.e. without an identifier it provides access to the prototype object.

As pointed out in the OP, these can be hard to distinguish in certain situations.

I don't think removing the standalone @ solves any problems. On the other hand, removing case 2 keeps :: consistent with normal property access ., and makes it pretty much uncomparable with @.

@showell
showell commented Sep 9, 2011

Just to have it on the record, I added an issue to deprecate "::" altogether:

#1678

@geraldalewis Why not view "@" simply as "this"? (see my earlier comment)

@geraldalewis
Contributor

@showell you must have posted while I was composing. It did cross my mind that I've been biased toward the @IDENTIFIER form (and thus this.), since it had precedence (occurring before standalone-@ in Coffee, and for its existence in Ruby).

I still think constraints are a great thing, especially in a beautiful language like CoffeeScript. I still feel like standalone-@ is not as readable, apparent, or as aesthetically pleasing as this.

-> "@"
this;
-> "@.bar"
this.bar;
-> "@[bar]"
this[bar];
-> "@(bar)"
this(bar);
-> "@ bar"
this(bar);
-> "@. bar"
this.bar;
-> "@bar" # @bar is a legal contraction for @.bar
this.bar;

is really nicely put together, but in my opinion, not as elegant as

this.
.prototype.
@weepy
weepy commented Sep 9, 2011

I think there's alot of over-analysis going on here. The main concern seems to stem from a concern for newer developers coming to terms with what the symbols mean. In reality I don't think there's any problem whatsoever here. I recently explained CoffeeScript to my younger brother who's only done a bit of Javascript. He was fine with it - makes sense - in his words.

@misfo
misfo commented Sep 9, 2011

I hear a lot of people begging for my opinion in here, so I'm gonna give the people what they want:

Why not pare @ and :: down to what they're really useful for?: simple and beautiful shortcuts for property access. I think this is what @geraldalewis is saying, but I'd take it one step further for clarity. If we think of them as simple shortcuts there's no reason to allow for following spaces or square brackets or any other funny business:

-> "@"
parse error
-> "@.woops"
parse error
-> "@[woops]"
parse error
-> "@(woops)"
parse error
-> "@ woops"
parse error
-> "@. woops"
parse error
-> "@hooray"
this.hooray;

To me this allows for a much simpler idea of what @ and :: are: simple shortcuts. Also, it seems like it would make the complitation simpler, too, but I'll leave that judgement to the geiusus.

@michaelficarra
Collaborator

@misfo: If you're thinking of @ as a shorthand for this., @ prop would also be a valid access. But I prefer @showell's suggestion of thinking about @ as this and allowing a contraction of @.prop to @prop. Now @ becomes a much more useful sigil.

@misfo
misfo commented Sep 9, 2011

But doesn't that still leave weird inconsistencies?

Straight from the docs:

As a shortcut for this.property, you can use @property.

That rule couldn't be any simpler. Why not just leave it at that? For all other uses, there is always this, right? Besides, don't the other uses look kind of gross compared to using this anyways?

@wavded
wavded commented Sep 9, 2011

I feel understood @misfo, that's exactly what I was trying to get across above: #1601 (comment)

Although I feel fine with allowing @ to mean this as well. The other stuff, IMO, I don't think is used that much anyway.

@geraldalewis
Contributor

The main concern seems to stem from a concern for newer developers coming to terms with what the symbols mean

Just want to clarify that any aid that simplifying these shortcuts gives to new developers is purely incidental to my desire for less ambiguity in the language.

@showell
showell commented Sep 9, 2011

@misfo I've looked at a fair amount of code that uses "@" beyond its documented use ("As a shortcut for this.property, ..."), and I have to say it looks just fine to me. Coming from Python, I tend to be more explicit in my own code, but I think there are lots of people that appreciate the brevity in some of the other @-based idioms. I also give them credit for not just focusing on brevity--"@" has the nice side effect of calling out code that is tightly bound to the class, so it makes it more readable in a way, as somebody mentioned earlier.

@misfo
misfo commented Sep 9, 2011

@wavded Your comment makes complete sense. I understand @geraldalewis's concern for having a simple mental model of what @ means:

@wavded wrote:

I have always understood to @ to mean something that is part of the variable name. kinda like $name in PHP or Perl. So something like @ name # note space Feels like a syntax error to me.

I like the sentiment, but that's the kind of inconsistency I propose we get away from. A Coffee dev's mental model should be:

Whenever I see @, mentally substitute this.

But can't the mental model be what's already in the docs?:

As a shortcut for this.property, you can use @property.

It's just a more specific mental model than what @geraldalewis proposed above.

@TrevorBurnham
Collaborator

OK, so there are clearly a very wide range of opinions here (even just on the issue of the standalone @). Given that, I think the prudent thing to do is to avoid making the language more restrictive and wait for stylistic standards emerge organically. Until then, folks can use @ or this freely as they prefer.

Sound reasonable?

@arbales
arbales commented Oct 26, 2011

Late to this party… but… the issue came up in one of our pull requests, so…

I agree with @showell and @michaelficarra that we should think of @ as sometimes being used in a contraction. This allows @ to mean this without being inconsistent.

What that doesn't really do is justify the removal of the standalone @ — which does look pretty lonely all-by-itself. In the end, it seems like we can rationalize removing or keeping lone @'s till the end of time. They do appear everywhere, though, and that should count for something. If they are to be removed, I think the decision would be more stylistically motivated than anything else. Not that there's anything wrong with that! 💅

Now, if only this were named self……

@artyomtrityak

Really i don't understand standalone @ issue.

We have @ alias for this. We know how it works. We always use @ when mean this.

To be consistent we should always use @ instead of this.

So we have 3 choices:

f = ->
  @
f = ->
  this
f = ->
  return @

imho

  1. the worse. We should not use this because coffee gives us @ - it's shroter and cleaner.

  2. Is the best - it's clear and short. In my projects it works and looks okay

  3. we know that coffee returns last statement so return @ can be used only for readability improvement

@vendethiel
Collaborator

@artyomtrityak The last comment on this issue was 2 years ago,
I agree with you that bare @ looks okay - a lot of people don't.

@michaelficarra
Collaborator

I removed standalone @ support from CoffeeScriptRedux in michaelficarra/CoffeeScriptRedux@31ad76f. CoffeeScriptRedux now respects both outcomes of this issue: no standalone @ and no postfix ::.

@peyerluk peyerluk referenced this issue in upfrontIO/livingdocs-engine Sep 3, 2013
@peyerluk peyerluk Update styles in SnippetView
Add and remove classes according to the values in SnippetView.model.styles. Style changes trigger SnippetTree#snippetHtmlChanged events which are handled in the Renderer.
7cb70b3
@emmenko emmenko referenced this issue in sphereio/sphere-node-sdk Jan 23, 2014
@emmenko emmenko Start defining basic layers 4ba733f
@testbrian

A lot of people do like the bare @. An inconsistency with :: doesn't justify not using one of the hallmarks of coffeescript

@otse
otse commented Oct 8, 2015

I have an extended class Klas, and I want Klas to use its own method foo, not the override-foo

I achieve this with Klas::foo.call this, param. Good form ye?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment