Giter Club home page Giter Club logo

Comments (22)

jashkenas avatar jashkenas commented on July 23, 2024

I'm a bit confused as to how we propose to compile it. I think that jnicklaus' proposal created the "self" variable the first time that an @Property was mentioned. That won't work if the @Property is first mentioned within an inner function.

It might make more sense, instead of having a special way to refer to this, to have a shorthand for binding a function to the current context (a-la Prototype and Underscore's bind and bindAll functions). I often have cause to define a function and bind it on the spot.

from coffeescript.

weepy avatar weepy commented on July 23, 2024

what would the longhand JS look like ?

from coffeescript.

jashkenas avatar jashkenas commented on July 23, 2024

Something like:

(function() {
  return original_func.apply(bound_obj, arguments);
})

from coffeescript.

weepy avatar weepy commented on July 23, 2024

ah so something like

new_func: original_func <= bound_obj

or you could call it on the spot

(click <= this)( => $(this).move())

from coffeescript.

jashkenas avatar jashkenas commented on July 23, 2024

In the ECMAScript 4 notes you took, they take this a step farther, and make this behave like any other lexically scoped variable. I'm not quite sure what the semantics of that would be, because you have cases like this one:

car: {
  drive: =>
    this.wheels.each() wheel =>   # this should be 'car'
      this.power(wheel)           # this should still be 'car'
      wheel.position: =>
        this.pos + car.pos        # this should be 'wheel'
}

This isn't a problem in Ruby, because a method is not the same thing as a Block/Proc, a method's self is the object it's called on, a block's self is the lexical self where the block was defined. JavaScript has no such distinction. Defining a method is the same as defining a block, and where we might be able to distinguish between functions that are assigned as properties, versus functions that are passed into method calls, it falls apart if you assign a function to a temporary variable, and then pass it into a call.

from coffeescript.

weepy avatar weepy commented on July 23, 2024

yes it's clear that it's not directly straight forward which 'this' we're talking about. Only thing that springs to mind would be attaching 'self' to the named function (which is always in temporary scope) ala:

car: {
  drive: =>
    this.wheels.each() wheel =>   # this should be 'car'
      drive.this.power(wheel)           # this refers to wheel, but drive.this refers to car
      wheel.position: =>
        this.pos + car.pos        # this refers to wheel
}

from coffeescript.

weepy avatar weepy commented on July 23, 2024

As you mentioned above, I think a special way to call a function with the context set to this would be useful. Not sure what the syntax would look like, here's some ideas:

method-->(x)
method!(x)
method:(x)

would compile as either

(function() { return method.apply(this, arguments); })(x)
or
method.call(this,x)

from coffeescript.

weepy avatar weepy commented on July 23, 2024

The first option is probably the most flexible. I.e.

myfunc*
(function() { return myfunc.apply(this, arguments)})

myfunc*(1,2,3)
(function() { return myfunc.apply(this, arguments)})(1,2,3)

from coffeescript.

jashkenas avatar jashkenas commented on July 23, 2024

Nice ideas for syntax -- however, we don't want to bind to this at call time, we wan't to bind to this lexically, at the point where the inner function is defined, before it gets passed into some other function and loses its sense of identity. So, perhaps something like this:

square: x => x * x

square: x ==> x * x

Compiles to:

square = function square(x) {
  return x * x;
};

__a = this;
__b = function(x) {
  return x * x;
};
square = function square() {
  return __b.apply(__a, arguments);
};

from coffeescript.

weepy avatar weepy commented on July 23, 2024

Ah. It would be useful to be able to bind functions at runtime also, how about:

square: x => x*x         # normal square function
square2: *square         # new square function that's bound to the current context 
*square(5)                   # calling a function, bound to the current scope

to

var __self = this;

square = function square(x) { return x * x };

square2 = (function () {
  return square.apply(__self, arguments);
})

(function() {
  return square.apply(__self, arguments);
})(5)

from coffeescript.

jashkenas avatar jashkenas commented on July 23, 2024

There's a hiccup in our proposed implementations of binding ... they're multiline statements, meaning that you'd need to wrap them in a closure in order to use them as part of an expression -- and wrapping them in a closure makes their __self = this; assignment refer to the incorrect this.

We could do something along these lines:

square = (function(self) {
  var __a;
  __a = function(x) {  
    return x * x;
  };
  return (function square() { return __a.apply(self, arguments); });
})(this);

It's getting p-r-e-t-t-y ugly.

from coffeescript.

weepy avatar weepy commented on July 23, 2024

Can we not do something like:
When we come across a binding like *my_func, which means "give me back a function like my_func, but bound to the current value of 'this' ", we push a variable __self to the top of the scope and set it to this. Then I think the code I suggested should work as is ?
Otherwise I think I'm missing the point somewhere ........

from coffeescript.

jashkenas avatar jashkenas commented on July 23, 2024

(responding to the email here)

Yeah, you're right. The initialization of __self can be pushed up to the top of the current scope, maintaining the function declaration as an expression. It's not a problem.

I think that your proposed implementation will work beautifully. I'm still not sold on the syntax through. We need some kind of symbol that looks like it means "bind", or perhaps we should just appropriate "bind" as a keyword. The last thing is -- should you be able to pass in an object to bind to, or is binding always done with the current value of "this"?

from coffeescript.

weepy avatar weepy commented on July 23, 2024

Hmm, a symbol that looks like it means bind... a tough one. Perhaps use & as it looks a bit like a knot !

&my_func(a,b,c)
context&my_func(a,b,c)

Any idea how we might use 'bind' as a keyword ?

from coffeescript.

liamoc avatar liamoc commented on July 23, 2024

Haskell's syntax for a different kind of bind is >>=

from coffeescript.

weepy avatar weepy commented on July 23, 2024

How about ^ (bind to scope) as it seems to point to to current scope.

from coffeescript.

weepy avatar weepy commented on July 23, 2024

I was just thinking that maybe the bind should fit in with a curry type function with more variables, so the syntax might look like:

create<this>             # this is bound to the current value of this
create<this: scope>      # a function bound to another scope
create<x,y>                  # binding x,y to their current values.
create<x:a,y:b>             # binding x,y to their current values.

==>

function(_this){
  return function() { create.apply(_this, arguments) } 
}(this)

function(_this){
  return function() { create.apply(_this, arguments) } 
}(scope)

function(_this, x,y){
  return function() { create.apply(_this, x, y) } 
}(this, x,y)

from coffeescript.

jashkenas avatar jashkenas commented on July 23, 2024

Okay, bound function declarations are now on master. I'm using the long arrow ==> to signal a function that's bound to the current value of this. Weepy: I don't think that you ever need a way to bind a function to the current this as you call it, because that's what already happens when you assign a function to a local variable and call it. Likewise, this proposal leave out currying syntax, because it's not to often needed.

Here's the common-case example of binding a jQuery handler function, and wanting to access properties of this:

view: {
  this.name: "Robert"
  this.initialize: =>
    $('#robert').bind('click') event ==>
      $(event.target).text(this.name)
}

Compiles into this:

var view;
view = {
  name: "Robert",
  initialize: function initialize() {
    var __a;
    var __this = this;
    return $('#robert').bind('click', (function() {
      __a = function(event) {
        return $(event.target).text(this.name);
      };
      return (function() {
        return __a.apply(__this, arguments);
      });
    })());
  }
};

It's a little long -- but I can't think of a way to make it shorter. We need to cache the compiled function in the __a local variable here to make it run fast.

Closing the ticket. Write back if you have a better implementation, and we'll reopen it.

from coffeescript.

weepy avatar weepy commented on July 23, 2024

How would you use this syntax with a pre-existing function ? Seems a shame to leave that out.

Can you example be written like so :

(function(__a) {
  return (function() {
    return __a.apply(__this, arguments);
  });
})(function(event) {
    return $(event.target).text(this.name);
  }))

In which case it would work with a prexisting function (with a different syntax).

from coffeescript.

jashkenas avatar jashkenas commented on July 23, 2024

It's certainly possible to bind pre-existing functions to an object, I just think that it's something better handled by libraries like Underscore or Prototype. We don't have a nice syntax for it, it's not all that common, and the generated code would be quite long compared to _.bind or Function#bind.

The reason why the above arguments don't apply equally to the long arrow, is that it's extremely common to want iterator or callback functions bound to the current this. You have to do it all the time. Here's an article about it:

http://alternateidea.com/blog/articles/2007/7/18/javascript-scope-and-binding

His example (in CoffeeScript, with Prototype):

this.abilities.each((ability =>
  this.executeAbility(ability)
).bind(this))

And using the long arrow:

this.abilities.each() ability ==>
  this.executeAbility(ability)

If you come up with a really nice syntax for binding pre-existing functions, we can certainly add it.

from coffeescript.

weepy avatar weepy commented on July 23, 2024

You wanted a syntax for pre-existing functions, how about:

fn: x => x*x
y: =fn=>

similar to 
y: x ==> x*x

from coffeescript.

hen-x avatar hen-x commented on July 23, 2024

It seems to me that while it can be useful to bind a pre-existing function, the common case would be to create a 'forwarding' function to bind a method to its current receiver, rather than binding a free function to an arbitrary object. In this case, The current fat-arrow/property-shortcut/argument-splat syntaxes already conspire to make this scenario fairly concise and readable without its own particular syntax, eg:

nodeWrapper.addEvent 'click', => @handleClick(arguments...)

from coffeescript.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.