squirrel
squirrel copied to clipboard
feature idea: object initialization
This is a speculative idea. I haven't thought it through completely.
I would like to see a functionality like struct or object initialization (I think that's what it's called.) Essentially an instance would have a {} operator which would let you set values on it as in table creation.
For example:
local myinst = MyClass() { X=1,Y=2 };
//as a possibly unfortunate side effect, this is oddity might be allowed:
myinst { X=3 };
Here, you could view a {
at this point in the grammar as a .setvalues( {
method which takes a table, but naturally we'd want to avoid the overhead of creating a new table just to immediately stuff the values in another instance.
All of the above could be applied to tables as well, sensibly, but you would probably want to support { X=1,Foo<-2 } in that case, and you can no longer conceptualize it as a .setvalues( {
. Moreover, it's just plain weird to do this on tables. But I could see someone defending it as useful.
I put some thought to something like this in the past. I got stuck by the fact that {} already has several semantics in Squirrel. I was playing with "name { x = 1 , y = 2 }" and I remember it was causing some ambiguities. Maybe "name() { x = 1, y = 2 }" would be simpler. However, it's not completely clear to me how that would compile(probably a series of "set"). Or if the values are set before or after the constructor is invoked, that also implies it only works on classes.
I don't think I have any doubt that the values should be set after the constructor is invoked--that's how it would work in c#. That is communicated clearly by seeing it written as name() {} such that the constructor parens are first, then the curly braces. I think a series of "set" operations are precisely what most people will expect it to be--not just a matter of convenience or simplicity in the compiler, but exactly what's wanted in fact. So I suppose I should write it differently than I did before:
local myinst = MyClass() {X=1,Y=2};
-> local myinst = MyClass(); myinst.x = 1; myinst.y = 1;
.
I hadn't thought of making it an actual part of the construction grammar. That would be simpler and cleaner than what I originally pictured.
So I implemented something, it literally took 15 mins :) so I don't guarantee perfection but it kind of does what we talked about. For a quick test just replace FunctionCallArgs() with the follwing code. Let's see if we like it
void FunctionCallArgs()
{
SQInteger nargs = 1;//this
while(_token != _SC(')')) {
Expression();
MoveIfCurrentTargetIsLocal();
nargs++;
if(_token == _SC(',')){
Lex();
if(_token == ')') Error(_SC("expression expected, found ')'"));
}
}
Lex();
for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
SQInteger stackbase = _fs->PopTarget();
SQInteger closure = _fs->PopTarget();
_fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
SQInteger retval = _fs->TopTarget();
if (_token == '{')
{
SQInteger nkeys = 0;
Lex();
while (_token != '}') {
switch (_token) {
case _SC('['):
Lex(); CommaExpr(); Expect(_SC(']'));
Expect(_SC('=')); Expression();
break;
default:
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
Expect(_SC('=')); Expression();
break;
}
if (_token == ',') Lex();
nkeys++;
SQInteger val = _fs->PopTarget();
SQInteger key = _fs->PopTarget();
_fs->AddInstruction(_OP_SET, 0xFF, retval, key, val);
}
Lex();
}
}
thanks! first test:
local sprite2 = Sprite() { Image = smile, X = 160, Y = 10+yadd++ };
I'll start using it and kick it occasionally and see if I can smoke out any problems. I'm not scripting too much yet, still working on my engine.
It seems commas aren't required
class Foo { x=0;y=0; }
print(Foo() { x=1 y=1 }.y); //compiles OK and prints 1
I think commas should be required.
I agree that commas should be required. 😄 There's less room for typos to cause bugs that way. 🐞
Well, this might be a change for a major release(4.0) I'm quite sure this would break a lot of stuff in our codebase. Often ppl omit the comma when declaring tables with a newline between fields. I don't have strong feelings about it. It never seemed to cause problems in the last 13 years. FYI, also arrays and function calls have optional commas :scream_cat: .
Since it's so consistent otherwise in older features, I surely want this new feature to follow the standard. Forget I mentioned it.
Oh, I see! 👓 Right, I'd still like commas to be required (not a huge problem, but it has tripped me up before). However, if they're required in one place, they should be required everywhere. 🌐 And yeah, it's a good idea to wait until a major release to change anything so we don't break existing applications. 🔨 👍