Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit naming of this #30

Open
gilbert opened this issue Jan 1, 2016 · 18 comments
Open

Explicit naming of this #30

gilbert opened this issue Jan 1, 2016 · 18 comments

Comments

@gilbert
Copy link

gilbert commented Jan 1, 2016

Hi all, I wanted to gather your opinions on the explicit-this proposal since I think it is directly related to this proposal. Personally, it would put me fully on board with moving the pipeline functionality of es-function-bind forward (not that I'm anyone important).

To save you a click, here is a code example of what the explicit-this proposal would allow:

function array.zip (otherArray) {
  return array.map( (a, i) => [a, otherArray[i]] )
}

function array.flatten () {
  return array.reduce( (a,b) => a.concat(b) )
}

function subject.delayedLog () {
  setTimeout( () => console.log(subject), 1000 )
}

[10,20]
  ::zip( [1,2] )
  ::flatten()
  ::delayedLog()
@benjamingr
Copy link

For analogy, C# does something like:

function flatten (this array) {
  return array.reduce( (a,b) => a.concat(b) )
}

Disadvantages are mostly the fact that any existing code cannot be used, for example, you won't be able to call Array.prototype.map on a NodeList.

@gilbert
Copy link
Author

gilbert commented Jan 18, 2016

for example, you won't be able to call Array.prototype.map on a NodeList.

Could you explain this point further? I don't quite understand what you mean.

@Artazor
Copy link

Artazor commented Jan 18, 2016

@mindeavor - imagine that you already have an implementation of the virtual method you need in some other class (i.e. Array).

var {map} = Array.prototype;
var anchors = document.querySelectorAll("a");
var urls = anchors::map( a => a.href );

Here querySelectorAll returns a NodeList - something that is Array-like (with .length and indexed access) but is not inherited from an Array.

How would you rewrite this example with explicit this naming?

@gilbert
Copy link
Author

gilbert commented Jan 18, 2016

The explicit this naming proposal only affects how you write the definition. Otherwise it runs the same way as before.

function array.zip (otherArray) {
  return array.map( (a, i) => [a, otherArray[i]] );
}

// Equivalent to:

function zip (otherArray) {
  var array = this;
  return array.map( (a, i) => [a, otherArray[i]] );
}

To be clear, I am not proposing any notion of types, as function flatten (this array) { seems to imply.

@zenparsing
Copy link
Member

@mindeavor Thanks! As has been discussed many times, the primary objection to the :: operator is that it uses this as a parameter, and as such you don't have the ability to do naming, destructuring, etc. in the parameter list.

The syntax you present is a cool solution to that problem, although I think that having Identifier . Identifier is going to be a little confusing given the fact that it appears to be a member expression, but actually introduces to separate bindings. I think a more likely syntax would be the C# style:

function zip(this array, otherArray) {
  return array.map( (a, i) => [a, otherArray[i]] );
}

That would also allow you to do destructuring:

function something(this { foo, bar }) {
    // ...
}

What do you think?

In any case, the :: operator needs to stand on its own, with "explicit this" parameters as a potential follow-up.

@spion
Copy link

spion commented Jan 22, 2016

I like this idea.

That said, @zenparsing is that really the main objection, the reason why bind isn't moving forward? I don't see anyone objecting to class methods being unable to destructure this. Or is it default argument values? I don't see how that is a problem either...

Really though, why isn't this proposal moving? I think many high-profile projects are excited about it. Babel implemented it, in TypeScript it got general approval, RxJS 5 implements bind operator versions of their operators here: https://github.com/ReactiveX/RxJS#es6-via-npm and calls it the best overall method, which Angular 2 developers agree with ... Whats exactly is missing to get it moving to other stages, and (since I'm getting off-topic now) can we open a checklist issue with it? I'm really excited about it, and would be really disappointed to see it wither.

@domenic
Copy link
Member

domenic commented Jan 22, 2016

There are a couple TC39 members who are against it, which is enough to block progress despite any amount of community enthusiasm :(

@gilbert
Copy link
Author

gilbert commented Jan 22, 2016

@zenparsing I like it too. It exposes this for what it is: just another parameter. I updated the proposal readme with the new syntax.

@spion The this-bind operator is a functional concept – it allows you to decouple functions from data. I think no one objects to non-destructurable class methods because destructuring isn't that useful in OOP.

@zenparsing
Copy link
Member

@spion It's great to see the positive reactions. Regarding TC39, timing is also an issue, since the committee is quite busy at the moment trying to get other things moved through (e.g. async functions). And honestly, we've needed the time to work through all of the input and alternatives brought up in this repo. I'll try to get at least an informal feel from the committee next week though.

@Alxandr
Copy link

Alxandr commented Feb 2, 2016

I'll try to get at least an informal feel from the committee next week though.

Somewhat off topic, but where would "updates" (so to speak) be posted? Like, how do I know if this is moving forward, backwards, or not at all?

@robotlolita
Copy link

Given that:

x::foo(bar) === foo.call(x, bar)

A syntax introducing the thing that matches how it's used seems more reasonable to me.

So, given something like:

function this :: foo(arg1, arg2) {
  ...
}

something :: foo(arg1, arg2);

You have the same symmetry as regular function calls:

function foo(arg1, arg2) {
  ...
}

foo(arg1, arg2);

And since the concept of this is both reified in the language, and matches the way people'd use it, explaining it would be a lot simpler — even though backwards compatibility would allow people to define functions without giving an explicit this binding.

@johnsonjo4531
Copy link

@Alxandr I would check out where the proposals are progress wise on this page https://github.com/tc39/ecma262#ecmascript. The defintion of the stages for the proposals are given here https://tc39.github.io/process-document/. This proposal is in stage 0 which the stage 0 specs are on their own page here https://github.com/tc39/ecma262/blob/master/stage0.md.

@xooxdoo
Copy link

xooxdoo commented Apr 4, 2016

i agree with @robotlolita

@Swivelgames
Copy link

Swivelgames commented Oct 26, 2016

Can the same not be achieved using

function foobar() {
    const { foo, bar } = this;
} 

I'm quite excited at the prospect of the :: bind operator syntax. It seems much more promising than parameterizing this. If destructuring this is not currently possible given the current destructuring syntax, I think that should be looked at and proposed separately.

Naming this does not seem any more useful than simply using this, especially given that explicitly naming this and destructuring should be easily achieved using other means currently available with minimal effort. For what it's worth, I feel like a bind operator solves a more common use case.

@robotlolita
Copy link

@Swivelgames destructuring works with any expression on the RHS.

The idea of naming this is more to make it easier to explain the language to JS programmers than anything. Arrows cover most of the use cases where you'd want to bind this to some name to keep around without being shadowed in inner scopes, and you usually would only run into problems if you used JS as a prototype-based language, and constructed objects inline.

If you have:

const Foo = {
  value: x,
  foo() {
    const outerThis = this;
    return {
      bar() {
        return this.qux(outerThis.value);
      },
      qux(value) {
        return value + 1;
      }
    }
  }
}

Named this parameters would make it much simpler:

const Foo = {
  value: x,
  outer::foo() {
    return {
      bar() {
        return this.qux(outer.value);
      },
      qux(value) {
        return value + 1;
      }
    }
  }
}

@Swivelgames
Copy link

@robotlolita I understand that use case. Good point. However, my opinion remains the same that I believe this bind operator would be more beneficial. I still believe the benefits of the bind operator far outweigh the explicit name of this, especially given that previously written methods will be out of reach, among some of the other disadvantages. And the prospect of virtual method libraries, which I have several use-cases for. But, to each their own! :)

@robotlolita
Copy link

@Swivelgames they're not mutually exclusive proposals, but rather meant to complement each other.

@Jamesernator
Copy link

Jamesernator commented Feb 16, 2017

Just another syntax idea for explicit naming:

function foo(bar) for baz {
    ...
}

someBaz::foo(someBar)

With a more concrete example

function map(iteratee) for observable {
   return new Observable((observer) => {
       observable.forEach(item => {
           observer.next(iteratee(item))
       }).then(_ => observer.complete())
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests