
var foo = { Prototype = bar, baz = 42 };
with extra syntax for the Prototype, and foo.Prototype with GetPrototype(foo), so that every member of the proplist is the same without any exception. The question is, what syntax?
var foo = bar <- { baz = 42 };
var foo = new bar { baz = 42 };
var foo = SetPrototype({ baz = 42 }, bar);
var foo = { baz = 42 } extends bar;
var foo = { bar; baz = 42 };
var foo = { extends bar; baz = 42 };
var foo = { baz = 42 } : bar;
var foo = bar : { baz = 42 };
var foo : bar { baz = 42 };
def foo : bar { baz = 42 };
var foo = new bar; foo.baz = 42;
var foo = CreateProplist(bar); foo.baz = 42;
or something else? Does anybody know of another language with prototype inheritance which has an object literal syntax which can specify the prototype?

I wonder why you didn't propose the most obvious possibility: var foo = bar { baz = 42 };

var foo = bar { ... }
is imho too close to var foo = bar; { ... }
. It'd work, but I fear the error message in code like this would be frustrating: if (foo + bar < baz
{
bla = CreateObject(Clonk);
blub = 42;
}
GameOver();
It'd complain that it expected a ), but found an identifier instead on line 6, which isn't where the real error is. I already don't like the fact that a { at the beginning of a statement has a different meaning than at the beginning of an expression. If there where something useful you could do with a proplist without storing or passing it somewhere, everybody would notice that {}.foo = bar; doesn't work like ({}.foo = bar);. Making the { do a third thing after an expression is just too much.

var bar = { Width = 10 };
var foo = { Prototype = bar };
This should work right?
Log("%d",foo.Width); //logs 10
foo.Width = 15;
Log("%d",foo.Width); //logs 15
But if Actions within the ActMap are attemptred to be modified in the same manner (someClonk.ActMap.Scale.Speed = 10), IIRC an error is logged that a read-only property is attempted to be modified. So the above doesn't work for nested properties.


if (ActMap == this.Prototype.ActMap)
ActMap = { Prototype = this.Prototype.ActMap };
ActMap[action] = { Prototype = ActMap[action], Speed = n };
if (this.Action == ActMap[action].Prototype)
this.Action = ActMap[action];
This is freaking incomprehensible! IMO it should be as simple as this, a one-liner:
ActMap[action].Speed = n;
The user shouldn't have to worry about where the values in his proplist come from - from actual values in the proplist or from the prototype of the proplist. The concept of read-only proplists only complicates things for the user, instead if an element of a proplist is assigned with a value which comes from the prototype of that proplist, the element should be copied from the prototype to the actual proplist automatically (internally) and then the value of the element changed.
In the above case, this.ActMap should look like this after the operation:
{ action= { Speed = n} }
Replacing only the changes made to the ActMap from the Prototype (definition, in this case).

func Manipulator(proplist p) { p.foo = bar; }
func Baz() { Manipulator(CreateObject(Clonk).ActMap.Walk); }
It is totally unexpected for an expression like foo.bar.baz to change foo, which it would have to do to make the language consistent under your proposal. It would really only improve the situation with the ActMaps, and the problem there is really with the ActMap design. In retrospect, I really should have redesigned that piece after we broke backwards-compatibility. The problems essentially come from me trying to make GetAction() continue to return strings while at the same time making SetAction(GetAction()) restart the action currently running. GetAction() should instead return the proplist, SetAction take proplists, and scripts that interpret action names should instead interpret some property of the action. (I'm not yet sure what to do with NextAction and friends.) This way, changed actions wouldn't be required to be reachable via .ActMap.ActionName, and could just be stored wherever.
In the meantime, we should probably add some way to loop over all properties of a proplist and write a MakeActMapWritable(). Objects which need to change their actions could then call that in their Construction functions.
I must side with Newton here - if we have read-only proplists, auto-prototyping makes a lot of sense (that's going from reference semantics to value semantics, isn't it?). That we don't have an obvious syntax for how to call your "
Manipulator
" with a write-able prop list is a separate problem. I'm almost tempted to call for "->" meaning "auto-prototype this" ;)

As far as I know, ActMaps are the only case where this is a problem. With a better Action design, the scaling code would just do SetAction(new WalkAction { Speed = 9000 }) and nobody would complain. Hm, thinking about it again, it probably could already do this.Action = { Prototype = this.Action, Speed = 9000 };

I'm thinking of stuff like menus, overlays, vertices, SolidMasks, etc.

In any case, I refuse to make "foo.bar" alone modify foo in a way that is visible to script. I think that leaves the option of doing such things when the child proplist is created. I'm not sure, but I think doing that in the engine would create situations at least as surprising as the ActMap case. Which leaves the MakeActMapWritable() utility function that can be called by objects that need it.
I think that is also the right answers for things like menus: If you create a new menu inheriting from a template, you want to recreate the menu structure, but not things like the pointers to decorative images. For example, if the scenario exchanges the menu decoration at dawn and dusk, open menus should also change the decoration. For that, the menu structure can't contain proplists inheriting from the old decoration, it must leave the properties free so that they do not obscure the properties containing the new decoration.
You have to know which properties contain proplists that "belong" to the new proplist itself, and which are merely used as pointers to other stuff. The engine doesn't know that, in general. Perhaps CreateObject should create a new ActMap for the new object, but I think most objects wouldn't use it, we need the script infrastructure for MakeActMapWritable() in any case, so I think CreateObject shouldn't.

var foo = { baz = 42 } extends bar;
var foo = bar : { baz = 42 };
Even though I have to admit I never really used that feature until now - so I can't really say what I missed/expected when I needed it :)
I like the "
Oh yeah: And could we make the instantiating-thing overloadable? Idea being that we could make
work as expected by pointing the instantiation to an engine function introducing the "magic". Could just be a string that proplists automatically cache the function for. Extra points if we allow to pass parameters to it ;)
new bar { baz = 42 }
" thing the most. The arrow doesn't convey the right message for me, postfixes and everything inside the braces make it too easy to miss that you're dealing with a prototype. And I don't want anything that you can't use as an expression.Oh yeah: And could we make the instantiating-thing overloadable? Idea being that we could make
var obj = new Clonk { x = 200, y = 300 };
work as expected by pointing the instantiation to an engine function introducing the "magic". Could just be a string that proplists automatically cache the function for. Extra points if we allow to pass parameters to it ;)

> The arrow doesn't convey the right message for me
Well, the new proplist does point to the prototype proplist, in the direction the arrow indicates.
> postfixes and everything inside the braces make it too easy to miss that you're dealing with a prototype. And I don't want anything that you can't use as an expression.
Yeah.
>And could we make the instantiating-thing overloadable?
We could. I think that's for after function pointers and proplists as this. I'm alternating between writing those and fixing release blockers at the moment.
(By the way, today I realized that in definition calls, this doesn't return the definition, despite the fact that it would have been an one-line-change as soon as I made definitions proplists. And even earlier it could have just returned the id of the definition. I hope we can still change that and won't have to keep the old behavior around.)

We really need both "create a new instance, potentially with engine magic" and "create a new prototype". The former could be a two-stop process of the latter followed by a function call, though the necessary engine magic to make that work for objects doesn't taste good. (Creating a C4Object instance, moving the properties over, replacing all references to the proplist to references to the object. Or making the whole engine work with the new "passive" objects. Maybe Status=0 already does, but I have doubts.) "new" is used for the former in too many other languages to use use it for the latter.
So we need some other syntax. I'm somewhat tempted to simply use SetPrototype, because the only user of raw proplists with Prototypes are the Actions, which do not need a constructor with side-effects. But I also want to introduce a new set of prototypes for the effects, so we need a syntax that works at the top level of scripts. And those probably should in turn have a common prototype with some effect-specific functions in it, but they shouldn't be effects themselves, so the "new" syntax that calls a constructor is probably not the right choice.
"class foo: bar { ... }"? That'd save us the "static const", and nested function literals are a long way off in any case, so we don't really need a syntax that works as an expression.

var foo = extend bar { baz = 42 };
var foo = new proplist : bar { baz = 42 };
I kinda like the "extend" one. Enough that I'll probably implement it unless somebody argues for an alternative.


Draw(new AlgoEllipsis { x=10, y=10 } );
instead of the current
Draw({ Algo=MAPALGO_Ellipsis, x=10, y=10 } );
I like the "extend" approach, but I don't like the word "extend" so much. I would somehow expect it to do an #appendto.

>> Enough that I'll probably implement it unless somebody argues for an alternative.
> I like the "extend" approach, but I don't like the word "extend" so much. I would somehow expect it to do an #appendto.
Feel free to argue for an alternative. (I don't like "new proplist : bar {}" because it looks too much like "new proplist {}".)

Wouldn't
var foo = bar { baz=42};
work as well?
Having a keyword means we need less look-ahead in the parser.
The more look-ahead you have, the more complicated a parser becomes. The less complex a parser is, the easier a language (generally) is to understand (because not only the parser, but also a human has to think about less possible alternatives while reading the code).

extend looks fine, imho. Is there a reason against new bar {} though? It doesn't do what it does in other languages?


var twonky = new Clonk {name="Twonky"};
Both "twonky" and "Clonk" are proplists etc.

new Foo
in C4Script is about the same as new Foo
in C++, whereas extend Foo
is the equivalent of class Bar: public Foo
. In particular, new Clonk will eventually replace CreateObject(Clonk), while extend Clonk will just create a C4PropList, not a C4Object.

> var foo = bar <- { baz = 42 };
This is almost what's been proposed for Javascript, except that they're using | instead of -: var foo = bar <| { baz = 42 }; Not sure whether we should copy this - as a mere proposal it hasn't the advantages reusing syntax from other languages normally has. It's especially not an argument against using the new keyword, since Javascript has already used up that one for something else.
Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill