[Harmony proxies] Discussion on the "declarative object" experiment

# David Bruant (14 years ago)

I'd like to share my experience on a recent experiment. First off, I'd like to apologize for the name; "declarative object" doesn't really capture it and may be confusing. Second of all, what I have created doesn't really solve any use case (I'll discuss it), but offers at most some syntactic sugar. Code can be found here : DavidBruant/DeclO

One idea is to have an object "o". This object can accept any property name (get trap only in my case). Accessing a property will generate an object on-the-fly which itself can accept any property name and generate an object, etc. At the end, the object can be used as a constructor to do something. Example:

var a = new o.azerty.are.the.first.letters.of.my.keyboard(); var b = new o.David.Bruant.writes.JavaScript();

The point could be to build something based on the property names (stored in the propNames variable and added with the push l.8). Of course, a constructor taking a string array could be as useful. That's the reason why I said earlier it doesn't solve any use case. The syntax sugar is the only added value I can think of. The exact use of the string array is to be defined in the constructTrap function. The pattern is here.

Anyway, the main thing I want to share is a reflection on shared handlers. At l.13, all proxies created on-the-fly use the same handler object (I have purposefully not inlined it in l.10). Thinking about shared handlers, I have realized that a proxy internal state is "stored in" its method handlers and the way they interact with each other, so this has to be taken into account when considering sharing a handler among several proxies. In order to share the same handler, some proxies must share the same functions (even dynamically). Each function having a unique scope, it means that these proxies must share their traps scopes. So, either the state of several proxies is shared (like in my case where they share "propNames" on purpose) or the shared scope could be reduced to a WeakMap which in turn can store a per-instance "state". Both solutions aren't mutually exclusive.

# Dmitry A. Soshnikov (14 years ago)

On 12.04.2011 20:41, David Bruant wrote:

Hi,

I'd like to share my experience on a recent experiment. First off, I'd like to apologize for the name; "declarative object" doesn't really capture it and may be confusing. Second of all, what I have created doesn't really solve any use case (I'll discuss it), but offers at most some syntactic sugar. Code can be found here : DavidBruant/DeclO

One idea is to have an object "o". This object can accept any property name (get trap only in my case). Accessing a property will generate an object on-the-fly which itself can accept any property name and generate an object, etc. At the end, the object can be used as a constructor to do something. Example:

var a = new o.azerty.are.the.first.letters.of.my.keyboard(); var b = new o.David.Bruant.writes.JavaScript();

The point could be to build something based on the property names (stored in the propNames variable and added with the push l.8). Of course, a constructor taking a string array could be as useful. That's the reason why I said earlier it doesn't solve any use case. The syntax sugar is the only added value I can think of. The exact use of the string array is to be defined in the constructTrap function. The pattern is here.

Yes, the pattern is interesting, though, really, which practical use-case will it have? Currently a one possible I see -- a query to database with building the query itself. Sort of:

where .name("Dmitry") .surname("Soshnikov") .active(true)

etc (though, it should be callable in contrast with yours implementation). But, it also arguable whether it's so useful.

However, your letter made me think on proposing existential operator, which is a syntactic sugar to avoid long testing whether a property exists and only after that to apply it. This already is again used in CoffeeScript, so I'll show the examples:

let street = user.address?.street

which desugars e.g. into:

street = (typeof user.address != "undefined" && user.address != null) ? user.address.street : undefined;

The same with functions (which is even more convenient that just with properties):

let value = entity.getBounds?().direction?.x

which desugars into:

let x = (typeof entity.getBounds == "function") ? (typeof entity.getBounds().direction != "undefined" && entity.getBounds().direction != null) ? entity.getBounds().direction.x : undefined undefined;

(I specially avoid optimization with saving intermediate results -- just to keep clarity)

I think it's useful thing and I already used in several times.

Dmitry.

# David Bruant (14 years ago)

Le 13/04/2011 09:02, Dmitry A. Soshnikov a écrit :

On 12.04.2011 20:41, David Bruant wrote:

Hi,

I'd like to share my experience on a recent experiment. First off, I'd like to apologize for the name; "declarative object" doesn't really capture it and may be confusing. Second of all, what I have created doesn't really solve any use case (I'll discuss it), but offers at most some syntactic sugar. Code can be found here : DavidBruant/DeclO

One idea is to have an object "o". This object can accept any property name (get trap only in my case). Accessing a property will generate an object on-the-fly which itself can accept any property name and generate an object, etc. At the end, the object can be used as a constructor to do something. Example:

var a = new o.azerty.are.the.first.letters.of.my.keyboard(); var b = new o.David.Bruant.writes.JavaScript();

The point could be to build something based on the property names (stored in the propNames variable and added with the push l.8). Of course, a constructor taking a string array could be as useful. That's the reason why I said earlier it doesn't solve any use case. The syntax sugar is the only added value I can think of. The exact use of the string array is to be defined in the constructTrap function. The pattern is here.

Yes, the pattern is interesting, though, really, which practical use-case will it have?

I warned from the beginning that I didn't see any :-p More seriously, the main point of sharing my experiment was the discussion on shared handlers for several proxies.

Currently a one possible I see -- a query to database with building the query itself. Sort of:

where .name("Dmitry") .surname("Soshnikov") .active(true)

I have tried to think of a lot of use cases. This one, for instance, doesn't even requires proxies (As I understand it). As long as you know the number and names of the all properties (I assume you do by knowing which database table you're querying), ES5 accessor properties could be used. This goes with the restriction that it's likely to be far more memory consumming, but the pattern could be applied the same way. Now that I think about it, I realize that for getters/setters, the exact same object could be used (may depend on the use case). Same for my pattern, I use Proxy.createFunction for each intermediary (l.10), but I could factorize it and return the same proxy each time since traps don't change at all.

Also, I'd like to note that if each of your property is a function call, you don't even need accessor properties. That's what jQuery already does by returning "this".

etc (though, it should be callable in contrast with yours implementation). But, it also arguable whether it's so useful.

I have no strong opinion on callable or not. It was just an idea that the pattern would better be used as a constructor. The main point of the pattern lies on the use of the get trap in "firstHandler" and "middleHandler". It could be improved by a different call/construct trap (and the use of arguments for these).

However, your letter made me think on proposing existential operator, which is a syntactic sugar to avoid long testing whether a property exists and only after that to apply it. This already is again used in CoffeeScript, so I'll show the examples:

let street = user.address?.street

which desugars e.g. into:

street = (typeof user.address != "undefined" && user.address != null) ? user.address.street : undefined;

Shouldn't it desugar to "(typeof user.address == "object" && user.address != null)?" ?

# David Bruant (14 years ago)

Le 12/04/2011 18:41, David Bruant a écrit :

Hi,

I'd like to share my experience on a recent experiment. First off, I'd like to apologize for the name; "declarative object" doesn't really capture it and may be confusing. Second of all, what I have created doesn't really solve any use case (I'll discuss it), but offers at most some syntactic sugar. Code can be found here : DavidBruant/DeclO

One idea is to have an object "o". This object can accept any property name (get trap only in my case). Accessing a property will generate an object on-the-fly which itself can accept any property name and generate an object, etc. At the end, the object can be used as a constructor to do something. Example:

var a = new o.azerty.are.the.first.letters.of.my.keyboard(); var b = new o.David.Bruant.writes.JavaScript();

The point could be to build something based on the property names (stored in the propNames variable and added with the push l.8). Of course, a constructor taking a string array could be as useful. That's the reason why I said earlier it doesn't solve any use case. The syntax sugar is the only added value I can think of. The exact use of the string array is to be defined in the constructTrap function. The pattern is here.

Anyway, the main thing I want to share is a reflection on shared handlers. At l.13, all proxies created on-the-fly use the same handler object (I have purposefully not inlined it in l.10). Thinking about shared handlers, I have realized that a proxy internal state is "stored in" its method handlers and the way they interact with each other, so this has to be taken into account when considering sharing a handler among several proxies. In order to share the same handler, some proxies must share the same functions (even dynamically). Each function having a unique scope, it means that these proxies must share their traps scopes. So, either the state of several proxies is shared (like in my case where they share "propNames" on purpose) or the shared scope could be reduced to a WeakMap which in turn can store a per-instance "state". Both solutions aren't mutually exclusive.

Also, I'd like to note that for forwarding proxies, there is no way to share the handler since the target is in the scope of the functions. Unless the target is shared or as said before, the target is a value of an entry in a shared WeakMap.

# Dmitry A. Soshnikov (14 years ago)

On 13.04.2011 12:08, David Bruant wrote:

Le 13/04/2011 09:02, Dmitry A. Soshnikov a écrit :

On 12.04.2011 20:41, David Bruant wrote:

Hi,

I'd like to share my experience on a recent experiment. First off, I'd like to apologize for the name; "declarative object" doesn't really capture it and may be confusing. Second of all, what I have created doesn't really solve any use case (I'll discuss it), but offers at most some syntactic sugar. Code can be found here : DavidBruant/DeclO

One idea is to have an object "o". This object can accept any property name (get trap only in my case). Accessing a property will generate an object on-the-fly which itself can accept any property name and generate an object, etc. At the end, the object can be used as a constructor to do something. Example:

var a = new o.azerty.are.the.first.letters.of.my.keyboard(); var b = new o.David.Bruant.writes.JavaScript();

The point could be to build something based on the property names (stored in the propNames variable and added with the push l.8). Of course, a constructor taking a string array could be as useful. That's the reason why I said earlier it doesn't solve any use case. The syntax sugar is the only added value I can think of. The exact use of the string array is to be defined in the constructTrap function. The pattern is here.

Yes, the pattern is interesting, though, really, which practical use-case will it have? I warned from the beginning that I didn't see any :-p More seriously, the main point of sharing my experiment was the discussion on shared handlers for several proxies.

Currently a one possible I see -- a query to database with building the query itself. Sort of:

where .name("Dmitry") .surname("Soshnikov") .active(true) I have tried to think of a lot of use cases. This one, for instance, doesn't even requires proxies (As I understand it). As long as you know the number and names of the all properties (I assume you do by knowing which database table you're querying), ES5 accessor properties could be used. This goes with the restriction that it's likely to be far more memory consumming, but the pattern could be applied the same way. Now that I think about it, I realize that for getters/setters, the exact same object could be used (may depend on the use case). Same for my pattern, I use Proxy.createFunction for each intermediary (l.10), but I could factorize it and return the same proxy each time since traps don't change at all.

Also, I'd like to note that if each of your property is a function call, you don't even need accessor properties. That's what jQuery already does by returning "this".

etc (though, it should be callable in contrast with yours implementation). But, it also arguable whether it's so useful. I have no strong opinion on callable or not. It was just an idea that the pattern would better be used as a constructor. The main point of the pattern lies on the use of the get trap in "firstHandler" and "middleHandler". It could be improved by a different call/construct trap (and the use of arguments for these).

Yeah, right, that's why I also mentioned that it's arguable whether the pattern is useful to apply to this particular issue. It wast just a guess.

Regarding shared handlers, if exactly this is the point, we have also think which practical things can we have.

However, your letter made me think on proposing existential operator, which is a syntactic sugar to avoid long testing whether a property exists and only after that to apply it. This already is again used in CoffeeScript, so I'll show the examples:

let street = user.address?.street

which desugars e.g. into:

street = (typeof user.address != "undefined" && user.address != null) ? user.address.street : undefined; Shouldn't it desugar to "(typeof user.address == "object" && user.address != null)?" ?

Yeah, it's also just an example, any (but the most efficient) desugared variant can be used.

Dmitry.

# David Bruant (14 years ago)

Le 13/04/2011 10:18, Dmitry A. Soshnikov a écrit :

On 13.04.2011 12:08, David Bruant wrote:

Le 13/04/2011 09:02, Dmitry A. Soshnikov a écrit :

Yes, the pattern is interesting, though, really, which practical use-case will it have? I warned from the beginning that I didn't see any :-p More seriously, the main point of sharing my experiment was the discussion on shared handlers for several proxies.

(...)

(...)

Regarding shared handlers, if exactly this is the point, we have also think which practical things can we have.

The straightforward benefit I see for shared handlers is to avoid one handler instanciation per proxy instanciation. The downside is the brainfuck it produces in terms of scope definition and code organisation (I've worked hard to make my code easy to read. I find it hard nonetheless).

Do you have other practical things in mind?

# Dmitry A. Soshnikov (14 years ago)

On 13.04.2011 12:32, David Bruant wrote:

Le 13/04/2011 10:18, Dmitry A. Soshnikov a écrit :

On 13.04.2011 12:08, David Bruant wrote:

Le 13/04/2011 09:02, Dmitry A. Soshnikov a écrit :

Yes, the pattern is interesting, though, really, which practical use-case will it have? I warned from the beginning that I didn't see any :-p More seriously, the main point of sharing my experiment was the discussion on shared handlers for several proxies.

(...)

(...)

Regarding shared handlers, if exactly this is the point, we have also think which practical things can we have. The straightforward benefit I see for shared handlers is to avoid one handler instanciation per proxy instanciation.

So only an optimization? I guess there can be other useful things in shared state per proxies. Though, a shared state by itself isn't directly related with shared handler (though, and not excludes it).

The downside is the brainfuck it produces in terms of scope definition and code organisation (I've worked hard to make my code easy to read. I find it hard nonetheless).

Do you have other practical things in mind?

Nope, not yet.

Dmitry.