Block scoped prototype extensions

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Block scoped prototype extensions

Boris Cherny
Hey guys,

What would it take to get block scoped prototype extensions into JavaScript? I’m curious to get some thoughts before I write a proposal.

The use case is similar to Scala’s block scoped implicits. In my application code I want Array.prototype.indexOf to return an Option<number>, rather than number | -1. If I patch Array’s prototype directly, it will break other libraries in my project. It would be nice to have a way to extend the prototype for just a block, or just a file.

Would a combination of block-scoped imports (maybe dynamic imports, to patch the prototype) and some sort of onExitBlock hook (to unpatch the prototype) be enough to implement this? Has anyone else thought about this sort of feature?

Boris
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Block scoped prototype extensions

kdex
One way to solve this might currently include extending `Array` and
overriding`indexOf` in a derived class to reflect the `Option` behavior you're
after.

On Wednesday, July 5, 2017 8:10:05 PM CEST Boris Cherny wrote:

> Hey guys,
>
> What would it take to get block scoped prototype extensions into JavaScript?
> I’m curious to get some thoughts before I write a proposal.
>
> The use case is similar to Scala’s block scoped implicits. In my application
> code I want Array.prototype.indexOf to return an Option<number>, rather
> than number | -1. If I patch Array’s prototype directly, it will break
> other libraries in my project. It would be nice to have a way to extend the
> prototype for just a block, or just a file.
>
> Would a combination of block-scoped imports (maybe dynamic imports, to patch
> the prototype) and some sort of onExitBlock hook (to unpatch the prototype)
> be enough to implement this? Has anyone else thought about this sort of
> feature?
>
> Boris
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Block scoped prototype extensions

Boris Cherny
In reply to this post by Boris Cherny
I tried that approach, but it doesn’t work when creating objects via literal notation ([], {}). A bit clumsy to have to write “new Array(1,2,3)", or “Array(1,2,3)” every time.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Block scoped prototype extensions

Logan Smyth
In reply to this post by kdex
This seems like a difficult thing to do because the prototype chain is only objects, so mutating them for the context of a single scope isn't easily done. A few cases come to mind as extremely confusing:

* If you override the prototype in a scope then pass the object to another function inside the block, does it stay overridden when passed? What if you _want_ to pass it as a normal array? Does that mean it needs to change the prototype back to default when calling the function, then change it back to your override again after?
* What if something captures a reference to the object and then the block ends? Does every usage of that object in the captured scope then need to re-mutate the object then change it back again? If not, this means using this behavior in callbacks and such isn't possible.

This approach encourages a huge amount of mutation, and it seems like it would be incredibly confusing for average users to have objects changing behavior out from under them.

On Wed, Jul 5, 2017 at 11:24 AM, kdex <[hidden email]> wrote:
One way to solve this might currently include extending `Array` and
overriding`indexOf` in a derived class to reflect the `Option` behavior you're
after.

On Wednesday, July 5, 2017 8:10:05 PM CEST Boris Cherny wrote:
> Hey guys,
>
> What would it take to get block scoped prototype extensions into JavaScript?
> I’m curious to get some thoughts before I write a proposal.
>
> The use case is similar to Scala’s block scoped implicits. In my application
> code I want Array.prototype.indexOf to return an Option<number>, rather
> than number | -1. If I patch Array’s prototype directly, it will break
> other libraries in my project. It would be nice to have a way to extend the
> prototype for just a block, or just a file.
>
> Would a combination of block-scoped imports (maybe dynamic imports, to patch
> the prototype) and some sort of onExitBlock hook (to unpatch the prototype)
> be enough to implement this? Has anyone else thought about this sort of
> feature?
>
> Boris
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Block scoped prototype extensions

kdex
In reply to this post by Boris Cherny
Overriding literals with a derived class is an entirely different problem. :)

On Wednesday, July 5, 2017 8:42:39 PM CEST Boris Cherny wrote:
> I tried that approach, but it doesn’t work when creating objects via literal
> notation ([], {}). A bit clumsy to have to write “new Array(1,2,3)", or
> “Array(1,2,3)” every time. _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Block scoped prototype extensions

kdex
… which I would be very happy to discuss, nonetheless.
It's indeed a little painful to work with derived built-ins if you can't use
literals.

Could we maybe have a syntax that, for its current block, declares how to
interpret literals? Maybe something along the lines of:

```js
class MyArray extends Array {};
Array as MyArray;
const array = [1, 2, 3];
assert(array instanceof MyArray);
```

On Wednesday, July 5, 2017 8:47:53 PM CEST kdex wrote:
> Overriding literals with a derived class is an entirely different problem.
> :)
> On Wednesday, July 5, 2017 8:42:39 PM CEST Boris Cherny wrote:
> > I tried that approach, but it doesn’t work when creating objects via
> > literal notation ([], {}). A bit clumsy to have to write “new
> > Array(1,2,3)", or “Array(1,2,3)” every time.
> > _______________________________________________ es-discuss mailing list
> > [hidden email]
> > https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Block scoped prototype extensions

Michael Haufe-2

On Wed, Jul 5, 2017 at 2:03 PM, kdex <[hidden email]> wrote:
… which I would be very happy to discuss, nonetheless.
It's indeed a little painful to work with derived built-ins if you can't use
literals.

Could we maybe have a syntax that, for its current block, declares how to
interpret literals? Maybe something along the lines of:

```js
class MyArray extends Array {};
Array as MyArray;
const array = [1, 2, 3];
assert(array instanceof MyArray);
```

On Wednesday, July 5, 2017 8:47:53 PM CEST kdex wrote:
> Overriding literals with a derived class is an entirely different problem.
> :)
> On Wednesday, July 5, 2017 8:42:39 PM CEST Boris Cherny wrote:
> > I tried that approach, but it doesn’t work when creating objects via
> > literal notation ([], {}). A bit clumsy to have to write “new
> > Array(1,2,3)", or “Array(1,2,3)” every time.
> > _______________________________________________ es-discuss mailing list
> > [hidden email]
> > https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Block scoped prototype extensions

Augusto Moura
In reply to this post by Boris Cherny
You can wrap into a util function like that:
``` .javascript
function customIndexOf() {
  return 'quack'
}

function withCustomIndexOf(fun) {
  const oldIndexOf = Array.prototype.indexOf
  Array.prototype.indexOf = customIndexOf
  fun()
  Array.prototype.indexOf = oldIndexOf
}

withCustomIndexOf(() => {
  console.log([123].indexOf()) // quack
})

console.log([123].indexOf()) // -1
```

Note, it will only work with sync code, async code (callbacks, promises) will ~probably~ be called after the reset of the prototype function
--
Augusto Moura

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Block scoped prototype extensions

T.J. Crowder-2
In reply to this post by Boris Cherny
On Wed, Jul 5, 2017 at 7:10 PM, Boris Cherny <[hidden email]> wrote:
> The use case is similar to Scala’s block scoped implicits. In my
> application code I want Array.prototype.indexOf to return an
> Option<number>, rather than number | -1.

Why does it have to be called `indexOf`? Why not `fooIndexOf`, where `foo` is a short app-specific prefix? Changing the meaning of `indexOf` seems like changing black to white and running the risk of getting killed at the next zebra crossing.

On Wed, Jul 5, 2017 at 7:42 PM, Boris Cherny <[hidden email]> wrote:
> I tried that approach, but it doesn’t work when creating objects
> via literal notation ([], {}). A bit clumsy to have to write
> “new Array(1,2,3)", or “Array(1,2,3)” every time.

Surely not too bad if you provide yourself a short array-creation wrapper, like `a`?

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Block scoped prototype extensions

Erik Arvidsson

We tried to do this in the early Harmony era. We never managed to get this to work without unacceptable performance and semantic issues. If you dig around the archives looking for scoped object extensions or method extensions you can see the discussion that was had.

It seems like wiki.ecmascript.org is no longer available. The proposal was up there. Maybe someone has a mirror of it somewhere?

Erik


On Wed, Jul 5, 2017, 13:24 T.J. Crowder <[hidden email]> wrote:
On Wed, Jul 5, 2017 at 7:10 PM, Boris Cherny <[hidden email]> wrote:
> The use case is similar to Scala’s block scoped implicits. In my
> application code I want Array.prototype.indexOf to return an
> Option<number>, rather than number | -1.

Why does it have to be called `indexOf`? Why not `fooIndexOf`, where `foo` is a short app-specific prefix? Changing the meaning of `indexOf` seems like changing black to white and running the risk of getting killed at the next zebra crossing.

On Wed, Jul 5, 2017 at 7:42 PM, Boris Cherny <[hidden email]> wrote:
> I tried that approach, but it doesn’t work when creating objects
> via literal notation ([], {}). A bit clumsy to have to write
> “new Array(1,2,3)", or “Array(1,2,3)” every time.

Surely not too bad if you provide yourself a short array-creation wrapper, like `a`?

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Block scoped prototype extensions

Jordan Harband

On Wed, Jul 5, 2017 at 6:33 PM, Erik Arvidsson <[hidden email]> wrote:

We tried to do this in the early Harmony era. We never managed to get this to work without unacceptable performance and semantic issues. If you dig around the archives looking for scoped object extensions or method extensions you can see the discussion that was had.

It seems like wiki.ecmascript.org is no longer available. The proposal was up there. Maybe someone has a mirror of it somewhere?

Erik


On Wed, Jul 5, 2017, 13:24 T.J. Crowder <[hidden email]> wrote:
On Wed, Jul 5, 2017 at 7:10 PM, Boris Cherny <[hidden email]> wrote:
> The use case is similar to Scala’s block scoped implicits. In my
> application code I want Array.prototype.indexOf to return an
> Option<number>, rather than number | -1.

Why does it have to be called `indexOf`? Why not `fooIndexOf`, where `foo` is a short app-specific prefix? Changing the meaning of `indexOf` seems like changing black to white and running the risk of getting killed at the next zebra crossing.

On Wed, Jul 5, 2017 at 7:42 PM, Boris Cherny <[hidden email]> wrote:
> I tried that approach, but it doesn’t work when creating objects
> via literal notation ([], {}). A bit clumsy to have to write
> “new Array(1,2,3)", or “Array(1,2,3)” every time.

Surely not too bad if you provide yourself a short array-creation wrapper, like `a`?

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Loading...