LiveScript icon indicating copy to clipboard operation
LiveScript copied to clipboard

--> function binder shorthand?

Open determin1st opened this issue 7 years ago • 9 comments
trafficstars

for example, i have this code:

api =
  method: (me) -> !->
    me.flag = true

it compiles to:

api = {
  method: function(me){
    return function(){
      me.flag = true;
    };
  }
};

later, i iterate a list of those methods and bind them with this code:

for name in apiList
  @[name] = api[name] @

i could do:

for name in apiList
  @[name] = api[name].bind @

but with multiple objects, function.prototype.bind works slow. what you think about this syntax:

api =
  method: (me) !-->
    me.flag = true

..or, if it does return something, it could be --> without !. i could use let syntax, but it creates binder functions each time. how to approach this?

determin1st avatar Oct 04 '18 18:10 determin1st

hmm.. not good. sorry. ->-> is okay.. was in hurry.... wanted to use @ inside those methods..

determin1st avatar Oct 04 '18 18:10 determin1st

I'm sorry, I don't quite understand what you're proposing... perhaps you figured out that --> already means something? What should be shorthand for what here?

rhendric avatar Oct 05 '18 04:10 rhendric

well, i thought about this syntax

method = (param1, param2) !-->
  @property = true

to this syntax

method = function(this$) {
  return function(param1, param2) {
    this$.property = true;
  };
};

so, it will act like bind with only first parameter thisArg specified (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)

--> - is free, it does not generate any syntax, only simple function.

It looks very implicit.. ye. but if you know how you defined it shouldn't be the problem. shorthand is for both function and first parameter that will become @ inside the body.

determin1st avatar Oct 05 '18 08:10 determin1st

method = (param1, param2) !-->
  @property = true

currently produces a curried function, so that exact syntax is out.

However, there's precedent for ‘assigning to this’ with the let keyword, so perhaps instead of yet another arrow variant, could we compromise on the below?

method = (this) -> (param1, param2) !~>
  @property = true

(The ~ would be necessary to keep the inner function using the same this as the outer one.)

It's more verbose than your proposal, but also more explicit and made of more reusable parts.

rhendric avatar Oct 05 '18 15:10 rhendric

oh, i didn't noticed that with parameters it will be curried function...

well, i like (this) -> (param) ~> more than (me) -> (param) ->, ye, it will be more useful, but it doesnt work for now, says compile error..

in case, when there is no parameters in the inner function it will be:

method = (this) -> !~>
  @property = true

which doesn't look great, right? what about using more compact syntax with this or @ as the first parameter to make binder:

method1 = (this) !~>
  @property = true

method2 = (this, param1, param2) !~>
  @property = true

hmm.. docs are saying that ~> creates a bound function, so, some crazy idea came now, it probably can be used to create variable binder like:

method1 = (this, boundParam1, param2, param3) !~~>
  @property = true

method2 = (this, boundParam1, boundParam2, param3) !~~~>
  @property = true

or better

method1 = (this, boundParam1, [param2, param3]) !~>
  @property = true

method2 = (this, boundParam1, boundParam2, [param3]) !~>
  @property = true

but i compromise to your variant, anyway

determin1st avatar Oct 05 '18 19:10 determin1st

Repeating the ‘shaft’ of a function arrow (-> to -->, ~> to ~~>, etc.) is the cue to make the function curried, so we can't use that as a clue for how many parameters should be bound.

On principle, I'm opposed to two things that these last few suggestions would require:

  • creating the equivalent of more than one function with a single (non-curried) arrow symbol
  • letting the presence of this in the parameter list significantly change how the rest of the parameter list is interpreted

I'll take this in parameter lists as a low priority feature for now. There are possibly some issues that I need to think about further—consider the following:

f = (this, a = @a) -> a

should probably compile to

var f;
f = function(this$, a){
  a == null && (a = this$.a);
  return a;
};

and

f = (a, {obj: this} = a) -> @foo

should compile to

var f;
f = function(a, arg$){
  var this$;
  this$ = (arg$ != null ? arg$ : a).obj;
  return this$.foo;
};

but then for consistency, I think

f = (a = @a, {obj: this} = a) -> @foo

has to compile to

var f;
f = function(a, arg$){
  var this$;
  a == null && (a = this.a);
  this$ = (arg$ != null ? arg$ : a).obj;
  return this$.foo;
};

so the effect of this-parameters can reach forward but not backward through the parameter list. I think that's probably fine? Anyone else think that this is possibly fishy, or see anything else wrong with the proposal?

rhendric avatar Oct 09 '18 17:10 rhendric

Okay, i understand your first example, but the rest look complicated to me, why not reduce the syntax trigger to only the first this parameter specified, for now, and in other cases, drop syntax errors? That will be easier, i think, and maybe later you will come up with other cases. Also, you skipped binder variant, how do you see binder?

i mean something like this:

method = (this, param1, [param2, param3]) !~>
  @property = true

to

var method = function(this$, param1) {
  return function(param2, param3) {
    this$.property = true;
  };
};

..using this as first parameter perfectly fits the MDN docs (about .bind)

determin1st avatar Oct 09 '18 20:10 determin1st

Again, I don't want to create more than one function with a single arrow symbol. So to create that JavaScript code, which contains a function that returns a function, you'd write

method = (this, param1) -> (param2, param3) !~>
  @property = true

Sorry if I confused you with all those other examples; they weren't meant to apply to your use case. What I'm trying to do is show the implications of letting this be bound in a function parameter, and how that would interact with other advanced features of function parameters in LiveScript. It's important for us to work through potentially complicated interactions before we put new features in, to make sure that we don't box ourselves into any corners that it would then be hard to get out of without breaking backwards compatibility.

rhendric avatar Oct 09 '18 22:10 rhendric

Okay, now i got it.

determin1st avatar Oct 09 '18 23:10 determin1st