Skip to content

Instantly share code, notes, and snippets.

@genericallyloud
Created April 9, 2012 18:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save genericallyloud/2345080 to your computer and use it in GitHub Desktop.
Save genericallyloud/2345080 to your computer and use it in GitHub Desktop.
Proposal for bind operator

Proposal for bind operator

This is closely related to the @ operator that could be used as a shorthand for "this" in class methods, like in CoffeeScript. My proposal does not depend on it, but I think it would work nicely with it. It is intended to cover binding issues in both the short function syntax proposal, as well as the majority use case of <function>.bind as used today.

Examples

//let say I have some object foo with a method bar that I want called as a callback
//right now I have to use bind, or wrap the call in an additional function
needsCallback(foo.bar.bind(foo);

//also happens inside the class itself, and you'll see
needsCallback(this.bar.bind(this));

//and finally, the case we're addressing now
needsCallback(function(x,y){
	if(x){
		this.doX(x);
	else{
		this.doY(y);
	}
}.bind(this));

What if we had a shorthand for bind that worked in both of these cases

//here the # acts as both a . and bind in one
needsCallback(foo@bar)
needsCallback(this@bar)
needsCallback(@bar)//shorthand matches this.bar, but does the additional binding

//in this case, it obviously doesn't access a property, it just does a bind
needsCallback(@function(x,y){
	if(x){
		this.doX(x);
	else{
		this.doY(y);
	}
});
//or with the new syntax
needsCallback(@(x,y)=>{
	...
});

Semantics

In place of . and bind

I'm overloading @ here in a couple of related ways.

contextExpr@property

In this case, @ is used in place of . and accesses the property. If that property is a function, bind is used. It desugars to:

 do { let obj=contextExpr; obj.property.bind(obj) } 

It can be used with |this| like:

this@property

//but because it is such a common case, also works with the shortcut
@property

//desugaring to
this.property.bind(this)

As a sugar for "this."

Because it provides a nice shorcut for |this|, in the above case for methods, it is reasonable to want to use @ for non-method properties, but without the additional bind semantics.

class Point {
	new(x,y){
		//not part of class syntax, just sugar for this.x
		@x = x;
		@y = y;
	}
}

With shorter function syntax

With concensus reached on one => syntax, I was hesitant to even include any of the function binding stuff as part of this proposal, but with the renewed complaints that it won't work well for event handlers, I thought maybe I'd give it a go anyway. This is how I would see @ composing with the new syntax:

x => { return this.x; } // dynamic this block
x => this.x // dynamic here too, but expression instead of block

@(x) => { return this.x; } // lexical this
@(x) => this.x // ditto for the expression-body form

Doing this changes the default for =>, but attempts to kill 3 birds with one stone (bind,this.property,lexical/dynamic |this|), and is maybe a better warning sign that the behavior of |this| is going to change in a short function.

Drawbacks

There are 2 big potential drawbacks here.

  1. Changing the defaults of => means that users will be forced to add a @ to get the desired lexical binding. Leads to more @ where they wouldn't be before, which means more grawlixy, cumbersome code. (If this were a showstopper, it could be dropped from the proposal. I think it would be nice for the other two reasons.)
  2. Uses up @ when it could be used in other ways. Right now there are a couple of proposed uses of @. One is for private names, and the other is for instance properties on classes. The private names syntax is unambiguous, but could get confusing. The instance properties syntax is ambiguous but semantically similar, and I think it could get worked out. I'll demonstrate how I think it could work below. These are not part of the proposal, but are ways of avoiding potential conflict/future hostility.

Possible solution for instance properties.

Instance properties have similar semantics of the shorthand @propertyName I am proposing here, but has some points which would colide. Primarily, it dictates that instance properties are not the same as public string based properties:

class Point {
	new(x,y){
		//in the instance properties proposal, these would create new instance properties, and therefore not
		//be accessible as this.x or from outside as p.x
		@x = x;
		@y = y;
	}
}
//working with another class proposal suggestion
//could solve the problem
class Point {
    private x; //add this here
	new(x,y){
		@x = x; //refers to private x, not accessible as this.x or p.x
		@y = y; //simply a shorthand for this.y
	}
}

Possible solution for this.@privateName

This isn't so much a change in syntax as much as a demonstration that they look ok when composed. private x; class Point { new(x,y){ this.@x = x; //uses private name x from outside of class @y = y; //is this confusing? }

	get x(){
	    return this.@x;
	}
}

//Can we tie the syntax together a little better?
private x;
class Point {
	new(x,y){
		@@x = x; //uses private name x from outside of class
		@y = y; //is this confusing?
	}
	
	get x(){
	    return @@x;
	}
}

Notice that both examples could still be legal, and the @@ syntax is really just a conversion of the first @ to 'this.', which is consistent - there is in fact, no syntactic extension made to accommodate this example.

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