Breaking up the <| operator between creating instances and extending

# Russell Leggett (14 years ago)

Given the recent go at finding alternative syntax for the <| operator, I thought about it and decided to split the functionality between creating "instances" using alternative prototypes, and the other side of the fence making reusable extended objects easier to make.

Its a little long so I threw it in a gist: gist.github.com/2056771

Summary:

In the case of creating what I would call an instance (not meant to create further instances) I have small, tight syntax:

//using : instead of <|, shorten Email.prototype to just Email
let email = Email:"russell.leggett at gmail.com";
if(email.isValid){
    email.sendMessage({
        subject: "Hello!",
        body: "you won't find this on a normal string, dude"
    });
}

and in the case of extension, rely on some class syntax getting approved:

class Email extends String {
    get isValid:function(){...}
    ...
}

There even an added bonus of a simple short-function syntax

let f = Function;
[1,2,3].map( f:(num){return num * 2;} );

where : is in place of <| and the 'function' keyword can get dropped on the RHS.

# Allen Wirfs-Brock (14 years ago)

On Mar 17, 2012, at 2:03 AM, Russell Leggett wrote:

Given the recent go at finding alternative syntax for the <| operator, I thought about it and decided to split the functionality between creating "instances" using alternative prototypes, and the other side of the fence making reusable extended objects easier to make.

Its a little long so I threw it in a gist: gist.github.com/2056771

I've already replied WRT : vs <| in another message so this is about the rest of the ideas in your gist.

Some of this feels like it is circulating back to things we already discussed, for example at www.mail-archive.com/[email protected]/msg10365.html

I also wanted to point out that there is another way to express object instantiation with arbitrary [[Prototype]]. It is the new <object> operator as described in esdiscuss/2011-September/016736

Essentially, let proto = { ... }; //some literally defined object let instance = proto <| { }; //instance is new object with no own properties who [[Prototype]] is proto

could be expressed as let instance = new proto; //instance is new object with no own properties who [[Prototype]] is proto

The only difference is that |new proto| would also apply an initialization function (proto's constructor property) on the new instance.

Other than that, the only real difference I see is that the "magic" you are applying regarding functions is different from that defined for <| but it is still treated as a special case. You magic is that if the LHS is a function you always use the value of its prototype property (BTW, what if it doesn't have one) as the [[Prototype]] value. so if you say: (functtion f1() {}) : function f2() {} the [[Prototype]] of f2 will be f1.prototype and f2 will not inherit at all from Function.prototype. This doesn't seem right.

If you just think about <| (or :) as an instantiation operator you still have to take into account what it means to have "function (,,,) {,,,}" on the RHS. The issue is that such a function express is actually instantiating two objects and they both need to get their [[Prototype]] values set to something reasonable. I think that my <| definition supplies a more reasonable (fewer new user surprises) then your : definition.

# Russell Leggett (14 years ago)

On Sat, Mar 17, 2012 at 1:09 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Mar 17, 2012, at 2:03 AM, Russell Leggett wrote:

Given the recent go at finding alternative syntax for the <| operator, I thought about it and decided to split the functionality between creating "instances" using alternative prototypes, and the other side of the fence making reusable extended objects easier to make.

Its a little long so I threw it in a gist: gist.github.com/2056771

I've already replied WRT : vs <| in another message so this is about the rest of the ideas in your gist.

Some of this feels like it is circulating back to things we already discussed, for example at www.mail-archive.com/[email protected]/msg10365.html

I also wanted to point out that there is another way to express object instantiation with arbitrary [[Prototype]]. It is the new <object> operator as described in esdiscuss/2011-September/016736

Essentially, let proto = { ... }; //some literally defined object let instance = proto <| { }; //instance is new object with no own properties who [[Prototype]] is proto

could be expressed as let instance = new proto; //instance is new object with no own properties who [[Prototype]] is proto

The only difference is that |new proto| would also apply an initialization function (proto's constructor property) on the new instance.

Yes, I remember this discussion, and I thought about it before posting, but I think it's orthogonal. |new proto| is about using objects like constructor functions + prototypes as "object exemplars", but what I'm trying to advocate is one of the biggest use cases which is using enhanced/altered versions of the default prototype (by extension, not mutation) combined with the literal to create a new instance.

This is the way that I was thinking about it:

{} same as Object:{}
[] same as Array:[]
"" same as String:""
function(){} same as Function:function(){}
...

So when I want to make a new enhanced String/Object/Array, I would just do

class Email extends String {
    get isValid:function(){...}
    ...
}

and then I can make a new one like

let email = Email:"russell.leggett at gmail.com";

This breaks it up very cleanly. I suppose this could be too much emphasis for a given use case, but I find it very easy to reason about. I mean, doesn't this really break things down into the use cases better? You want to make a special kind of Array? Use extends. You want to make a new one using literal syntax? Use : (or :: or :::).

Other than that, the only real difference I see is that the "magic" you are applying regarding functions is different from that defined for <| but it is still treated as a special case. You magic is that if the LHS is a function you always use the value of its prototype property (BTW, what if it doesn't have one) as the [[Prototype]] value. so if you say: (functtion f1() {}) : function f2() {} the [[Prototype]] of f2 will be f1.prototype and f2 will not inherit at all from Function.prototype. This doesn't seem right.

There is no special magic in : for functions, it is consistent across all. I'm just trying to break down the use cases a little better. I covered your example with a different form:

function sub(arg1,arg2) extends sup {
    super(arg1,arg2);
    //more stuff here
}

But I would also point out that if we get down to real world cases, we need to start thinking about real cases. Why am I extending one function from another function? Are we trying to add extra methods? Are we trying to take advantage of super? I find the proposal a little lean on real use cases for function other than the class pattern, which I think is better handled by actual class syntax. If it is to be able to make functions that are derived from an enhanced function, then I think it should follow the same pattern I gave above for Email.

class MyFunc extends Function {
    curry(...args){...}
}

//using my proposed short form from the gist
let test = MyFunc:(x,y,z){
    return x + y + z;
};

let curr1 = test.curry(1);
let curr2 = curr1.curry(2);
let total = curr2(3);
console.log(total); //6

If you just think about <| (or :) as an instantiation operator you still have to take into account what it means to have "function (,,,) {,,,}" on the RHS. The issue is that such a function express is actually instantiating two objects and they both need to get their [[Prototype]] values set to something reasonable. I think that my <| definition supplies a more reasonable (fewer new user surprises) then your : definition.

I think your solution makes it easier to reason about extending constructor functions using <|, but as I was saying in the gist, I think we should leave that to class. If I have a function on the RHS of :, what I really want is a new function (not class) of a certain type, potentially with different methods.