AngelScript mixin classes - preview

Started by
19 comments, last by WitchLord 11 years, 7 months ago
I'm starting to implement the support for mixin classes in AngelScript that I had mentioned earlier. I thought I would describe in more detail how I'm planning for it to work in the language. Though I already have things mapped out, there is still time to comment and provide suggestions as I'm still early on in the development.

Basically a mixin class is macro or template that provides an implementation that can be inherited, but cannot be instanciated by itself. A class can inherit from multiple mixins, which fulfills the same purpose as multiple inheritance in C++, i.e. code reuse, but don't add the complexities of multiple base classes to the runtime, i.e. multiple distinct virtual function tables, and object pointers that change depending on which base class that is represented.

When inheriting from a mixin, the class will receive the properties and methods from the mixin that doesn't conflict already existing properties and methods in the class (e.g. explicitly declared, or inherited from another class/mixin). The mixin class methods are compiled in the context of the derived class, so they will see and be able to use properties declared in the derived class even if they are not declared in the mixin class itself. This also allows the derived class to override the type of a property declared in a mixin (assuming the code that accesses the property is compatible).



// Declare a mixin class
mixin class MyMixin1
{
void increase() { property++; }
int property;
}

mixin class MyMixin2
{
void decrease() { property--; }
void setName(string name) { this.name = name; }
int property;
}

// Declare a class that inherits from a mixin
class MyClass : MyMixin1, MyMixin2
{
// Will receive property and increase() from MyMixin1
// Will receive decrease and setName() from MyMixin2

string name;
}

MyMixin1 a; // Not OK. A mixin class cannot be instanciated
MyClass b;

void main()
{
MyMixin2 @c = cast<MyMixin2>(b); // Not OK. A mixin class isn't a real type
}



A mixin class will also be able to implement interfaces, and perhaps even other classes. When a class inherits from a mixin like that the derived class will also implement the interfaces, just as if it had implemented them explicitly. (This part will probably not be implemented in the first iteration, planned for version 2.25.0).

To begin with a mixin class will not be able to implement constructors and/or destructors. If a specific initialization/uninitialization should be done for properties in the mixin class, the implementation of that has to be done with ordinary methods that are explicitly called by the class that inherits the mixin class. It would be better if the constructor/destructor could be used, but I haven't quite figured out how to merge the implementation into the final constructor/destructor that will be built for the class that inherits the mixin.



Let me know what you think of this, and if you have any suggestions for modifications or further additions to make the feature even better.


Regards.
Andreas

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
A possible approach to property initialization would be to allow default values to be specified in the declaration:


mixin class MyMixin
{
int property = 0;
}


I feel like that might require substantial changes to the library, though.

What would happen in this situation?


mixin class Mix1
{
const int property;
}
mixin class Mix2
{
void increase()
{
property++;
}

int property;
}
class MyClass : Mix1, Mix2
{
}


Looking great so far. I'm looking forward to making use of them. Will mixin classes be able to be registered from C++, or just the scripts?
inline initialization of class properties is a different feature that already on my to-do list. Once that is implemented it will work for properties in ordinary classes as well as for properties in mixin classes.

As for the scenario, it will be a compiler error, because the first property to be introduced in the class is from Mix1, so when the increase() method from the Mix2 class is compiled it will find that the property is read-only. Of course, a const property is not allowed to begin with, but you get the idea :). I'll try to make the error messages for cases like this as clear as possible so the user can resolve the conflicts.

The mixins won't be registerable, but the application can add an extra script section with the mixin declaration to modules, which is pretty much the same thing.

Regards,
Andreas

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


A mixin class will also be able to implement interfaces, and perhaps even other classes.


i am very excited about this feature.

will this be possible?

class Base1
{
int a;
}
class Base2
{
int b;
}
mixin class Mixin1 : Base1
{
int c;
}
class Child : Base2, Mixin1
{
int d;
}
Child child; // child has a,b,c,d

not much use if casting doesnt work, but still it is interesting.
No, that won't work, because it would mean multiple inheritance. It would basically be translated to the following:


class Base1 { int a; }
class Base2 { int b; }
class Child : Base2, Base1
{
int d;
int c;
}

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

Hi Andreas,

It's great news! Mixins are great for making a reusable code, I loved them in Ruby. You asked for some questions / ideas so here they come:

1. Will it be possible to inherit from one mixin in another? For example:

[source lang="cpp"]mixin class Behaviour
{
int state;

void normal_behaviour()
{
state = NORMAL;
}
}

mixin class ExtendedBehaviour: Behaviour
{
void extended_behaviour()
{
state = EXTENDED;
}
}[/source]

then use it like this:

[source lang="java"]class NpcA: Behaviour;
class NpcB: ExtendedBehaviour;[/source]
2. I'm concerned about the syntax - I loved Ruby's "include" syntax for using mixins:

[source lang="ruby"]class Vehicle
include Engine
include Behaviour
include Destructible[/source]
in AngelScript we use typical inheritance list so it becomes less readable and also becomes mixed with normal parent classes and you cant easily tell which is mixin and which is the real parent class.

What do you think about Ruby syntax (include / extend, but extend could work just as it does for inheritance now in AS so Class: Parent)

Thats it for now, thanks a lot for starting working on mixins!

Where are we and when are we and who are we?
How many people in how many places at how many times?

1. Will it be possible to inherit from one mixin in another?


Yes, this will be possible. Though probably not in this first release.


2. I'm concerned about the syntax - I loved Ruby's "include" syntax for using mixins:


Java does something similar. They use "extends" for inheritances and "implements" for interfaces.

If the lack of the keyword becomes a problem in AngelScript I can certainly include it at an optional syntax. I agree that the keyword makes the code more readable, but I don't think it has to be obligatory to inform the keyword as there isn't any ambiguity without it.

I'll add this to the to-do list for a potential future enhancement.



Thanks for the feedback.

Regards,
Andreas

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

And about constructors / destructors, would something like that be possible:

[source lang="cpp"]mixin class MixinA
{
void init() { # initialize mixinA }
}

mixin class MixinB
{
void init() { # initialize mixinB }
}

class MyClass: MixinA, MixinB
{
MyClass()
{
MixinA::init();
MixinB::init();
}
}[/source]
to initialize things that mixins need in a class constructor? I'm not sure about namespace and if it won't conflict with each other, as after all mixin methods are incorporated in class, so there will be 2 init() methods inherited from mixins, leading to a name conflict?

Where are we and when are we and who are we?
How many people in how many places at how many times?
It won't work, as both methods have the same signature MyClass will end up receiving only the init() from MixinA, the other one will be discarded as a duplicate.

Initially the only way to resolve this is to use unique method names, e.g. initMixinA(), initMixinB(), etc.

However, I'll keep this scenario in mind and try to think of a better solution.

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

mixin seem to be doing all interface does and more.

Is interface going to be deprecated?

This topic is closed to new replies.

Advertisement