Advertisement

Usability / design questions

Started by June 01, 2012 05:26 AM
4 comments, last by cellulose 12 years, 6 months ago
Got angelscript up and running with my engine today. Rather happy with it for the most part [size=1]and will donate graciously when I bootstrap myself out of poverty. But I'll voice a few questions to the developer or anyone else who cares to answer them, regarding usability of the language. Consider these first impressions?


- Multiple member objects declared on a single line.

Shape circle, square;
fails, expecting a semicolon. I'm curious what the reasoning behind disallowing this is.


- Compound assignments on property accessors.

I saw your justification for disallowing these in another thread, but I submit that having an option to enable them (signifying an understanding of the consequences) would be immensely useful to myself and others. C++ does far naughtier things with implicit code at times.


- Casting value types to booleans.

I understand why reference types cannot be allowed to cast to booleans (checking null-ness), but why this restriction should apply to value types baffles me a little. I'm mostly bothered about this due to the problem below, which has caused me to register many of my engine's reference-types as value-types. Though I also rather like being able to keep terse syntax like

if (Keyboard.x && keyboard.y.pressed()) {}
//as compared to
if (Keyboard.x.down && keyboard.y.pressed()) {}



- Reference types and C++ smart pointers.

Don't consider this one a criticism of the language; I understand very well that this is a nightmarish design challenge. (I've read your remarks in another thread about the matter.) But some thoughts:

I have a reference-counted pointer type in my program and many objects that hold such pointers to inner classes containing their actual data. Hence, a "Shape", for instance, can be cheaply passed around, its contents shared, and can be null. While this is the very notion of a reference type, it didn't jive very well with Angelscript, forcing me to register it as a value type. This is a shame because it behaves *exactly* like a reference type in C++, even being capable of null-ness.

//Rough idea of my C++ class
class Shape
{
class Data
{
//Data members are here in a private class
};

//The actual methods are in the reference-like class
Method();
OtherMethod();

RefCountedPtr<Data> data;
}


The principal issues arise from the fact that the "Shape" instance is itself a reference. It's capable of being "null" separate from the angelscript handle to it being null, and the native side of the engine may have another copy, meaning a separate reference count would need to be used for keeping track of the trivial Shape object itself. The latter is manageable, but the former really isn't.

[color=#a9a9a9](Based on the fact that the Shape class happens to be one word in size not counting its vptr it would be possible to hack an extremely ugly solution by way of manual object splicing, copious shell functions and some other abominations but I'll just let the impracticality of this approach be its own evidence.)

I don't know the first thing about the inner architecture of Angelscript, but it occurs to me that if such a class could be treated like a value-type internally (with regard to copying, assignment, other handling in the script engine), but act like a reference type in code and implement a few special behaviors for its handle-ness (null-check, retain, release) it would facilitate graceful handling of both smart pointers and the rather more exotic setup I use. I understand this would likely break support for certain containers, though.

...I also understand it might be prohibitively, ridiculously impractical depending on how reference-type handling works in the script engine. Don't consider it a suggestion, let alone a demand. More like an idea. Let me cast my value types to booleans and I'll be happy as a clam. smile.png
I'm bit short on time at moment, so the answers will be short. Please don't interpret it as rudeness ;)

- Multiple member objects declared on a single line.

The only reason is that this support simply hasn't been implemented yet. It's not something I've priotized over the time.

- Compound assignments on property accessors.

You're right. I'll consider adding this optional support though an engine property in a future release.

- Casting value types to booleans.

The reasoning behind this is that far too often do beginners make mistakes with implicit conversions to boolean in other languages, and since scripting is in a large part targetted at beginners I decided to not include the conversion at all.

Still, it is another thing that I can add optional support for through an engine property.

- Reference types and C++ smart pointers.

Some references that might help you obtain what you want:

- CScriptHandle add-on. This is basically a value type that looks like a reference type to the script writer. Maybe you can use it as basis for registering the Shape type. I had a very specific reason for creating the CScriptHandle add-on though, so I'm not sure it will completely fullfill your needs.

- Automatic wrappers for smart pointers. This is set of templates that SiCrane wrote to aid in the registration of smart pointers. They work with the std::shared_ptr, but perhaps you can adapt it to work with your class instead.

One of my goals with AngelScript is to make it flexible enough to suit as many as possible. It does take a lot of effort though to make it work with many different ways of implementing C++ classes. I will study your case further when I get time to see what improvements that can be made to the library.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
Ah! So ASHANDLE can be more than just this "generic handle type"? That may be worth mentioning in the docs! And thanks for the prompt response.

I've added the flag and a comparison behavior with the variable parameter type. So Shape is now registered like so...

//Shape type
AS_CLASS("Shape", sizeof(Shape),
asOBJ_VALUE | asOBJ_APP_CLASS_CDAK | asOBJ_ASHANDLE);
{
//Constructors/destructors
AS_CONSTRUCT("Shape", "void f()",
asFUNCTION(ShapeConD));
AS_CONSTRUCT("Shape", "void f(const Material &in)",
asFUNCTION(ShapeConM));
AS_CONSTRUCT("Shape", "void f(const Shape &in)",
asFUNCTION(ShapeCopy));
AS_DESTRUCT("Shape",
asFUNCTION(ShapeDest));
//Handle behaviors
shapeTypeID = engine->GetObjectTypeByName("Shape")->GetTypeId();
AS_METHOD("Shape", "bool opEquals(?&in)",
asFUNCTION(ShapeEquals), PGC_METHOD_OBJFIRST);
//Compare / assign
AS_METH("Shape", "bool opEquals(const Shape &in)",
asMETHOD(Shape, operator==));
AS_METH("Shape", "Shape &opAssign(const Shape &in)",
asMETHOD(Shape, operator=));
//Numerous other methods follow...


But I get an error with the following bit of angelscript:



class Chaser
{
Point pos;
Point vel;
Shape shape;

Chaser()
{
shape = Shape(LIGHTGRAY); //Error here
shape.buildCircle(0.0f, 0.0f, .05f, 16);
}

//other methods snipped
};


I may be misunderstanding how native-registered reference types operate in Angelscript..? Is it not possible to use an ASHANDLE as a non-handle value as can be done with script classes?


EDIT: this works fine:

class Chaser
{
Point pos;
Point vel;
Shape@ shape;

Chaser()
{
@shape = @Shape(LIGHTGRAY);
shape.buildCircle(0.0f, 0.0f, .05f, 16);
}

//other methods snipped
};


EDIT: and perplexingly, so does this...

class Chaser
{
Point pos;
Point vel;
Shape shape;

Chaser()
{
@shape = Shape(LIGHTGRAY);
shape.buildCircle(0.0f, 0.0f, .05f, 16);
}

//other methods snipped
};


At that point, though, I think it might be easy enough to explain the whole "@" thing to my scriptwriters... Tell me if I've done something horribly wrong. :)
I noticed while experimenting that when "null" is passed to my variable parameter type function (implemented so I could use "if (myShape is null)" semantics), its pointer-value is non-NULL, possibly junk, while its typeID is 0. Not a huge issue but slightly unintuitive and probably worth a note in that section of the docs.

I've been enjoying the work on setting up my script system greatly. Thanks, Andreas, for your diligent work on this excellent piece of free software.

Ah! So ASHANDLE can be more than just this "generic handle type"? That may be worth mentioning in the docs! And thanks for the prompt response.


Well, I said it might work. :) When I implemented ASHANDLE I hadn't thought of using it for anything else than the generic handle type. But it seems to work for your purpose as well so I'll document this.


shape = Shape(LIGHTGRAY); //Error here


This attempts to perform a value assignment, which for the ASHANDLE type is disabled, because the opAssign method is used for the simulated handle assignment.


@shape = Shape(LIGHTGRAY);
@shape = @Shape(LIGHTGRAY);


Both of these mean the same thing. As the lvalue is explicitly defined as a handle with @, AngelScript implicitly converts the rvalue to a handle too, even though you didn't inform the @ in the first case.

As shape is an ASHANDLE, the above expression calls the opAssign method to perform the 'handle assignment'.


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

[background=rgb(250, 251, 252)]I noticed while experimenting that when "null" is passed to my variable parameter type function (implemented so I could use "if (myShape is null)" semantics), its pointer-value is non-NULL, possibly junk, while its typeID is 0. Not a huge issue but slightly unintuitive and probably worth a note in that section of the docs.[/background]

[/font]
[/quote]

As the variable argument type ? can receive both handles and values, the ref argument in the case of a null handle will be a pointer to a null handle, i.e. *(void**)ref == 0.

I'll improve the documentation to explain this.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks for the help and er, general awesome-dev responsiveness. :)

This topic is closed to new replies.

Advertisement