Exemplar forms (was Your search - "|>" - did not match any documents)
I agree having two types of examplers is sensible.
For examples sake let fExemplar be an exemplar constructed with new <Function> and les oExemplar be the other one.
Now, I'm worried about "magically" making
fExemplar <| oExemplar
work, would oExemplar have fExemplar or fExemplar.prototype in it's [[Prototype]]? How do I tell the prototype of operator to treat fExemplar as a function and not an exemplar.
same issues apply to oExemplar <| fExemplar. If you do any magic to make inheritance work across exemplar types then I would need a way to tell the prototype of operator that they are just objects & functions, not exemplars.
however we can already make the two work together like such
fExemplar.prototype <| oExemplar
and
var sub = oExemplar.constructor <| fExemplar sub.prototype = Object.create(oExemplar); sub.prototype.constructor = fExemplar
The fact that the latter is verbose and a pain doesnt matter, because thats old style exemplars inheriting from new style exemplars.
However having new style exemplars in inheriting from old style exemplars is less painful.
Yes we have the issue of the exemplars not being equal but I dont want you to add magic to prototype of to fix that.
However it is reasonable to suggest a new operator for exemplar inheritance that does do magic
[snip]
I want to compose objects:
var result = cookUpTheBehavior(goodies, stuff) <| initializeTheState(args);
You want something else, then. Just because you want B does not mean A is useless or less useful or not JavaScripty.
With a decent Object.extend() we'd have a clean way to build objects without having to look up Crockford's web pages every time we try a different variation.
Object.extend is on the agenda. It's not the same as <|. Two different tools for two or more different jobs.
I want these two tools to work together! I want a standard property cloner and a composition operation that creates objects from a behavior object and data object. Wouldn't that be nice?
I agree with this - at least in the sense that I think it might be an appropriate time to take a higher level perspective of all the aspects of JavaScript object definition and reuse. That seems to be a lot of what is being discussed now from class literals to the <| operator to new <Object>
to traits. I understand the value of decomposing these ideas down into orthogonal part which can be used independently and combined to create a variety of useful abstractions. However, I think that creating something cohesive is really important, and in the end we will want to provide a clear path for the common cases.
I find it a problem that there is a standard pattern in JavaScript for creating "classes" but there isn't a real name for it. We have constructor functions and prototypes. Even the Rhino book is forced to say, "For lack of a better term, I will use the word "class" informally in this chapter." Then if you want to extend one of these things, you'll have to basically resort to a library or some recipe of your own. It's black magic. And worse, all the built-ins use the pattern, so we're basically going to have it around forever.
I understand that this is sort of what <| is for, and it is potentially what class literals are for, I guess my point is just that I think it should be a high priority for es.next to result in some definitive way of saying:
- create a thing Foo, including its constructor and at the very least methods (including get/set methods)
- create a Bar that extends Foo, including its constructor...
This is what Coffeescript provides with class and extend. I get the feeling that using class would be too loaded. If class is going to be used it sounds like people would like more than to have sugar for the existing pattern, they would like more and they don't want to harm future proposals. I think this is fair so I would say take the word "class" off the table. This is the reason I had previously proposed <| as more of a generic extension operator. It's already doing a lot of magic when it comes to functions and arrays.
I'm not sure exactly what the answer is, I'll try to think of something better to propose, I just feel like hashing out the individual pieces like <| and .{ and Object.extend etc. are all discussions that are worse off for not discussing how they should all work together.
- Russ
Let me take a crack at tying to tie together all the pieces we have been talking about.
To start, I want to introduce a new term that I will use to describe an program construct that defines the common characteristics that are shared by a probably open ended set of similar objects. I want to avoid common terms like "class" and "prototype" for such entities because they carry preconception baggage that I want to avoid for now. Instead, I'm going to use the term "exemplar". While there has been some limited usage of the term "exemplar" in computer science, it doesn't have any broadly accepted meaning or carry significant connotations. You have to get to the fourth page of a google search for "exemplar" before you find anything that is even vaguely related to CS.
In JS today, we essentially have two forms of exemplars. One looks like this:
function Foo(a,b) { this.x = a; this.y = b; } Foo.prototype.method = function () {...};
and makes it easy to parameterize the per instance state of new objects but it is awkward to specify the shared behavior of instance objects described by the exemplar. The other form of exemplar looks like this:
var Bar = { x: 0, y: 0, method() {...} }
and makes it easy to specify the shared behavior of instances but it is awkward to parameterize the per instance state of new objects described by the exemplar.
Are these two forms of exemplars really that different? There may be reasons to prefer one form of expression over the other in various situations, but can we find a way to generally use and think about them interchangeably?
One current difference is in how you create new instances of the exemplars. With the function form you say: var newObj = new Foo(1,2);
You can't currently do that with the literal form. In fact, Bar in the above example arguably isn't really the name of the exemplar but rather the name of an instance of the exemplar. The new <Object> proposal addresses
this difference by permitting us to say:
var newObj2 = new Bar();
It also address the per instance parameterization issue by giving meaning to:
var Bar = { x: 0, y: 0, method() {...}, constructor (a,b) { this.x = a; this.y = b; } }
so we can say:
var newObj2 = new Bar(1,2);
This means that from an instance creation point of view the two forms of exemplars are pretty much on equal footing.
.{ can be used to make it less awkward to specify shared instance behavior for the function form of exemplar (although perhaps not less awkward enough for some of us).
<| and super can be used with both exemplar forms to specify inheritance:
var SubFoo = Foo <| function (a,b,c) { super.constructor(a,b); this.z = c; };
var SubBar = Bar <| { z: 0, constructor (a,b,c) { super.constructor(a,b); this.z = c; } }
Another issue in unify the two exemplar forms is what happens if they are mix. Such as:
var SubFooLit = Foo <| { z: 0, constructor (a,b,c) { super.constructor(a,b); this.z = c; } }
and
var SubBarFunc = Bar <| function (a,b,c) { super.constructor(a,b); this.z = c; };
I think I can formulate reasonable rules for <| that make both of these also work.
The final remaining issue is instanceof and I also think we can also make this work with cross inheritance between the two styles of exemplars: we need to automatically generate a "prototype" property for "constructor" methods defined in object literals that back references the resulting object.
If we did these things we would pretty much have a common story of objects, defined using exemplars, instantiated using new, and supporting inheritance expressed in terms of exemplars. There are two equally valid alternative styles of exemplars, but they are fully interoperable with each other so it is really a matter of style or circumstance as to which you might choose to use. Other compositional forms can be defined in terms of higher-order functions and should be applicable to either exemplar formulation.
We might even choose to define an additional interoperable exemplar form that combines the best characteristics of the two existing forms.
This is a more complicated tory then simply having a traditional class model such as Dart is using. However, we have an existing language with existing featuures with a wide range of usages patterns so whatever we do with "classes" we still have to accommodate what currently exists in JS. We are never going to have as simple a story as a do-over language such as Dart. But I do think we can craft a understandable story where all the pieces fit together relatively nicely.
To expand on inheritance operator, I would treat es:h classes as declarative sugar for exemplars. Therefore it would make sense to have the extends keyword work on exemplars.
We could use oExemplar extends fExemplar and have that make inheritance work "as expected"
On Oct 14, 2011 8:38 AM, "Jake Verbaten" <raynos2 at gmail.com> wrote:
I agree having two types of examplers is sensible.
For examples sake let fExemplar be an exemplar constructed with new <Function> and les oExemplar be the other one.
Now, I'm worried about "magically" making
fExemplar <| oExemplar
work, would oExemplar have fExemplar or fExemplar.prototype in it's [[Prototype]]? How do I tell the prototype of operator to treat fExemplar as a function and not an exemplar.
same issues apply to oExemplar <| fExemplar. If you do any magic to make inheritance work across exemplar types then I would need a way to tell the prototype of operator that they are just objects & functions, not exemplars.
however we can already make the two work together like such
fExemplar.prototype <| oExemplar
and
var sub = oExemplar.constructor <| fExemplar sub.prototype = Object.create(oExemplar); sub.prototype.constructor = fExemplar
The fact that the latter is verbose and a pain doesnt matter, because thats old style exemplars inheriting from new style exemplars.
However having new style exemplars in inheriting from old style exemplars is less painful.
Yes we have the issue of the exemplars not being equal but I dont want you to add magic to prototype of to fix that.
However it is reasonable to suggest a new operator for exemplar inheritance that does do magic
[snip] >>> >>> >> I want to compose objects: >>> >> var result =
cookUpTheBehavior(goodies, s...
On Thu, Oct 13, 2011 at 4:14 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
Let me take a crack at tying to tie together all the pieces we have been talking about.
Allen, I really appreciate your synthesis, thanks. I am able to follow some of it because of my recent Q/A with the group. I think many more people would be able to follow it if the approximate semantics of new features where readily accessible. Maybe just an parenthetical explanation and a link to the strawman page (these are pretty daunting however).
<lots of interesting text elided>
This is a more complicated tory then simply having a traditional class model such as Dart is using. However, we have an existing language with existing featuures with a wide range of usages patterns so whatever we do with "classes" we still have to accommodate what currently exists in JS. We are never going to have as simple a story as a do-over language such as Dart. But I do think we can craft a understandable story where all the pieces fit together relatively nicely.
I really like this perspective, with two caveats:
-
To achieve the goal of "Keep the language pleasant for casual developers.", the correspondence between JS and traditional class models needs to be real, clear, and communicated well. Points of disconnect need to be ironed out. The danger of saying "class" and meaning something different are great but the dangers of saying Grawlix include no one caring about the meaning.
-
Your proposal is dominated by declarative syntax for objects, in contrast to practice which uses functions to construct objects. Of course it is possible that your new features would obsolete that practice, but I doubt it. By design the declarative syntax creates limits on objects that are simple to overcome with direct manipulation.
jjb
On Fri, Oct 14, 2011 at 5:54 PM, John J Barton <johnjbarton at johnjbarton.com>wrote:
On Thu, Oct 13, 2011 at 4:14 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
Let me take a crack at tying to tie together all the pieces we have been talking about.
Allen, I really appreciate your synthesis, thanks. I am able to follow some of it because of my recent Q/A with the group. I think many more people would be able to follow it if the approximate semantics of new features where readily accessible. Maybe just an parenthetical explanation and a link to the strawman page (these are pretty daunting however).
I believe the following links may aid in explaining some of the content
- ES:Harmony Object Literals syntaxharmony:object_literals
- Axel's prototypes as classes articlewww.2ality.com/2011/06/prototypes-as-classes.html
<lots of interesting text elided>
This is a more complicated tory then simply having a traditional class model such as Dart is using. However, we have an existing language with existing featuures with a wide range of usages patterns so whatever we do with "classes" we still have to accommodate what currently exists in JS. We are never going to have as simple a story as a do-over language such as Dart. But I do think we can craft a understandable story where all the pieces fit together relatively nicely.
I really like this perspective, with two caveats:
To achieve the goal of "Keep the language pleasant for casual developers.", the correspondence between JS and traditional class models needs to be real, clear, and communicated well. Points of disconnect need to be ironed out. The danger of saying "class" and meaning something different are great but the dangers of saying Grawlix include no one caring about the meaning.
Your proposal is dominated by declarative syntax for objects, in contrast to practice which uses functions to construct objects. Of course it is possible that your new features would obsolete that practice, but I doubt it. By design the declarative syntax creates limits on objects that are simple to overcome with direct manipulation.
I believe the use of declarative syntax is to get semantics across in a terse well specified manner. All of his declarative syntax has existing alternatives available we can use currently using methods. I don't think any of the declarative syntax has limits.
On Oct 14, 2011, at 12:38 AM, Jake Verbaten wrote:
I agree having two types of examplers is sensible.
For examples sake let fExemplar be an exemplar constructed with new <Function> and les oExemplar be the other one.
Now, I'm worried about "magically" making
fExemplar <| oExemplar
work, would oExemplar have fExemplar or fExemplar.prototype in it's [[Prototype]]? How do I tell the prototype of operator to treat fExemplar as a function and not an exemplar.
same issues apply to oExemplar <| fExemplar. If you do any magic to make inheritance work across exemplar types then I would need a way to tell the prototype of operator that they are just objects & functions, not exemplars.
We've already started down this path in the <| proposal where it treats: var subclass = Function <| {prototype: sup <| {/methods/} } <| function() {/.../}; differently from: var protoExtendedFunction = Function.prototype <| {/methods/} <| function() {/.../}
The subclass expression overrides the [[Prototype]] of both the subclass and subclass.prototype object. The other expression just overrides the [[Prototype]] of the function object and protoextendedFunction.prototype still have Object.prototype as its [[Prototype]]
however we can already make the two work together like such
fExemplar.prototype <| oExemplar
and
var sub = oExemplar.constructor <| fExemplar sub.prototype = Object.create(oExemplar); sub.prototype.constructor = fExemplar
The fact that the latter is verbose and a pain doesnt matter, because thats old style exemplars inheriting from new style exemplars.
var oSubf = fExemplar.prototype <| { /an oExemplar }; var fSubo = oExemplar.constructor <| function () {/ a fExempar */};
is all that is needed to do the cross-over without any additional changes to <|.
The reason I mentioned the possibility of extending the current definition to make the explicit property qualification unnecessary is that in past discussions about mixing prototypal and class inheritance patterns there were concerns raised about the verbosity of having to say .prototype and .constructor.
There is also a issue of wanting to be able to to do exemplar refinement without having to know if your are dealing a fExemplar or a oExemplar. Consider, a function such as:
function addMyDebugMethods(exmplr) { return exmplr <| {/* a bunch of methods */}; }
You might like to be able to call it with both a fExemplar and oExemplar.
I don't know if I really like pushing that far. It might be better to keep it simpler. But I think it is plausible that we could make this work.
One thing that worries me about the fsubo example is that oExemplar.constructor.prototype does not exist. How is that circular relation ship between .constructor and .prototype magically fixed?
the other issue of fixing <| for oExemplar <| fExemplar (and vica versa) is does it break oObject <| fExemplar, where oObject looks like an exemplar but isnt used as one.
If you can make it just work without leaking then that would be great
On Oct 14, 2011 7:09 PM, "Allen Wirfs-Brock" <allen at wirfs-brock.com> wrote:
On Oct 14, 2011, at 12:38 AM, Jake Verbaten wrote: > I agree having two
types of examplers is sensi... We've already started down this path in the <| proposal where it treats: var subclass = Function <| {prototype: sup <| {/methods/} } <| function() {/.../}; differently from: var protoExtendedFunction = Function.prototype <| {/methods/} <| function() {/.../}
The subclass expression overrides the [[Prototype]] of both the subclass and subclass.prototype object. The other expression just overrides the [[Prototype]] of the function object and protoextendedFunction.prototype still have Object.prototype as its [[Prototype]]
however we can already make the two work together like such > >
fExemplar.prototype <| oExemplar... var oSubf = fExemplar.prototype <| { /an oExemplar }; var fSubo = oExemplar.constructor <| function () {/ a fExempar */};
is all that is needed to do the cross-over without any additional changes to <|.
The reason I mentioned the possibility of extending the current definition to make the explicit property qualification unnecessary is that in past discussions about mixing prototypal and class inheritance patterns there were concerns raised about the verbosity of having to say .prototype and .constructor.
There is also a issue of wanting to be able to to do exemplar refinement without having to know if your are dealing a fExemplar or a oExemplar. Consider, a function such as:
function addMyDebugMethods(exmplr) { return exmplr <| {/* a bunch of methods */}; }
You might like to be able to call it with both a fExemplar and oExemplar.
I don't know if I really like pushing that far. It might be better to keep it simpler. But I think it is plausible that we could make this work.
On Oct 14, 2011, at 11:24 AM, Jake Verbaten wrote:
One thing that worries me about the fsubo example is that oExemplar.constructor.prototype does not exist. How is that circular relation ship between .constructor and .prototype magically fixed?
This is something I alluded to in my original message in the context of instanceof. For a oExemplar like this:
var Exmplr = { constructor () {/.../} }
we would want to automatically generate a "prototype" property such that Exmplr.constructor.prototype === Exmplr is true.
the other issue of fixing <| for oExemplar <| fExemplar (and vica versa) is does it break oObject <| fExemplar, where oObject looks like an exemplar but isnt used as one.
I would define "looks like a oExemplar" as has a "constructor" own property. If it looks like a oExemplar and is used on the LHS of <| then it is a oExemplar.
On Oct 13, 2011, at 1:05 PM, Russell Leggett wrote:
Let me take a crack at tying to tie together all the pieces we have been talking about.
To start, I want to introduce a new term that I will use to describe an program construct that defines the common characteristics that are shared by a probably open ended set of similar objects. I want to avoid common terms like "class" and "prototype" for such entities because they carry preconception baggage that I want to avoid for now. Instead, I'm going to use the term "exemplar". While there has been some limited usage of the term "exemplar" in computer science, it doesn't have any broadly accepted meaning or carry significant connotations. You have to get to the fourth page of a google search for "exemplar" before you find anything that is even vaguely related to CS.
In JS today, we essentially have two forms of exemplars. One looks like this:
function Foo(a,b) { this.x = a; this.y = b; } Foo.prototype.method = function () {...};
and makes it easy to parameterize the per instance state of new objects but it is awkward to specify the shared behavior of instance objects described by the exemplar. The other form of exemplar looks like this:
var Bar = { x: 0, y: 0, method() {...} }
and makes it easy to specify the shared behavior of instances but it is awkward to parameterize the per instance state of new objects described by the exemplar.
Are these two forms of exemplars really that different? There may be reasons to prefer one form of expression over the other in various situations, but can we find a way to generally use and think about them interchangeably?
One current difference is in how you create new instances of the exemplars. With the function form you say: var newObj = new Foo(1,2);
You can't currently do that with the literal form. In fact, Bar in the above example arguably isn't really the name of the exemplar but rather the name of an instance of the exemplar. The new <Object> proposal addresses this difference by permitting us to say:
var newObj2 = new Bar();
It also address the per instance parameterization issue by giving meaning to:
var Bar = { x: 0, y: 0, method() {...}, constructor (a,b) { this.x = a; this.y = b; } }
so we can say:
var newObj2 = new Bar(1,2);
This means that from an instance creation point of view the two forms of exemplars are pretty much on equal footing.
.{ can be used to make it less awkward to specify shared instance behavior for the function form of exemplar (although perhaps not less awkward enough for some of us).
<| and super can be used with both exemplar forms to specify inheritance:
var SubFoo = Foo <| function (a,b,c) { super.constructor(a,b); this.z = c; };
var SubBar = Bar <| { z: 0, constructor (a,b,c) { super.constructor(a,b); this.z = c; } }
Another issue in unify the two exemplar forms is what happens if they are mix. Such as:
var SubFooLit = Foo <| { z: 0, constructor (a,b,c) { super.constructor(a,b); this.z = c; } }
and
var SubBarFunc = Bar <| function (a,b,c) { super.constructor(a,b); this.z = c; };
I think I can formulate reasonable rules for <| that make both of these also work.
The final remaining issue is instanceof and I also think we can also make this work with cross inheritance between the two styles of exemplars: we need to automatically generate a "prototype" property for "constructor" methods defined in object literals that back references the resulting object.
If we did these things we would pretty much have a common story of objects, defined using exemplars, instantiated using new, and supporting inheritance expressed in terms of exemplars. There are two equally valid alternative styles of exemplars, but they are fully interoperable with each other so it is really a matter of style or circumstance as to which you might choose to use. Other compositional forms can be defined in terms of higher-order functions and should be applicable to either exemplar formulation.
We might even choose to define an additional interoperable exemplar form that combines the best characteristics of the two existing forms.
This is a more complicated tory then simply having a traditional class model such as Dart is using. However, we have an existing language with existing featuures with a wide range of usages patterns so whatever we do with "classes" we still have to accommodate what currently exists in JS. We are never going to have as simple a story as a do-over language such as Dart. But I do think we can craft a understandable story where all the pieces fit together relatively nicely.