underscore icon indicating copy to clipboard operation
underscore copied to clipboard

_.bind nontrivial constructor fix (?)

Open jgonggrijp opened this issue 4 years ago • 4 comments

A quick summary of what led up to this diff:

  • #2197 was a complaint about _.bind performing worse than native Function.prototype.bind, due to it basically being slice.call(arguments) + native bind (at least at the time).
  • #2199 "fixed" this by completely removing native bind out of the equation (but didn't update the comment, which has continued to claim a fallback to native bind until this very day).
  • #2214 reported that this was a breaking change: _.bind previously worked with nontrivial constructors such as Date in environments that supported native bind, but not anymore. This has been the status quo since June 2015.
  • In the discussion that followed, this was considered the most favorable solution: check for availability of native bind only at the time of definition of _.bind.
  • I took the above solution, updated it to the current situation and added a regression test.

I'm not actually sure this should be merged. Is using a bound function as a constructor important to support? On the other hand, #2199 was probably the wrong solution to the wrong problem in the first place, so maybe this detour should never have been made.

jgonggrijp avatar May 06 '20 00:05 jgonggrijp

I'm not actually sure this should be merged. Is using a bound function as a constructor important to support?

It is not important to support. Within a constructor function, this should be the instance you’re constructing.

I feel like we should rely on native bind here if there are performance improvements it gives us, and not worry about it otherwise.

jashkenas avatar May 06 '20 03:05 jashkenas

Here's the thing though. executeBound already has a fallthrough case for being called as a constructor (i.e. with new), in which case it doesn't keep the this binding but does keep the argument bindings:

https://github.com/jashkenas/underscore/blob/4334c126b3e71e4aeb8912d05d72139d24f7d0f1/modules/index.js#L770-L778

And it works for simple constructors, but not for fancy stuff like Date. Native bind has this sophistication too, but it does work for fancy constructors as well. So where to take this:

  • Support some constructors but not others (current situation)?
  • Support all constructors (this PR)?
  • Support no constructors at all (another breaking change)?

jgonggrijp avatar May 06 '20 11:05 jgonggrijp

So where to take this:

  • Support some constructors but not others (current situation)?
  • Support all constructors (this PR)?
  • Support no constructors at all (another breaking change)?

I don’t believe that it’s terribly important — these sorts of tickets are originally driven by test-case, nit-picked development, not real-world use cases ... But, if it doesn’t cost us much (in bound function call speed, and in file size) to support all constructors with this PR, I think it’s fine and good to merge it!

jashkenas avatar May 06 '20 15:05 jashkenas

Time for another benchmark, then.

jgonggrijp avatar May 06 '20 16:05 jgonggrijp