views:

258

answers:

2

I'm looking for ideas on how to implement a Mixin/Trait style system in AS3.

I want to be able to compose a number of classes together into a single object. Of course this is not a language level feature of AS3, but I'm hoping that there is maybe some way to do this using prototype based techniques or maybe some bytecode hacking that I believe AsMock uses to implement it's functionality.

An existing Java example is Qi4J where the user define interfaces that the Qi4j framework implements based on metadata tags and coding by convention.

Has anyone any ideas on how to get the Mixin/Trait concept working within AS3?

+2  A: 

Zero solutions presented on this, so I looked into a few methods. There are ECMA script style mixins by adding methods defined on other objects to the base objects prototype. But this means that the advantages of static typing are gone.

I was looking for a solution that didn't sidestep the static type system. I knew that ASMock used bytecode injection to create proxy classes. I hacked around ASMock for the past few days and came up with a possible solution implemented by creating a class with composed classes (through bytecode injection).

From the users point of view this involves defining your object that uses mixins through many interfaces:

public interface Person extends RoomObject, Moveable

public interface RoomObject
{
    function joinRoom(room:Room):void
    function get room():Room
}

public interface Moveable
{
    function moveTo(location:Point):void
    function get location():Point 
}

Then you define classes to represent these interfaces:

public class MoveableImpl implements Moveable
{
    private var _location:Point = new Point() 
    public function get location():Point { return _location }

    public function move(location:Point):void
    {
        _location = location.clone()
    }
}

public class RoomObjectImpl implements RoomObject
{   
    private var _room:Room
    public function get room():Room { return _room }

    public function joinRoom(room:Room):void
    {
        _room = room
    }
}

In a normal situation where you want to compose classes you would write:

public class PersonImpl implements Person
{
    private var _roomObject:RoomObject = new RoomObjectImpl()

    private var _moveable:Moveable = new MoveableImpl()

    public function get room():Room { return _roomObject.room }

    public function joinRoom(room:Room):void { _roomObject.joinRoom(room) }

    public function get location():Point { return _moveable.location }

    public function move(location:Point):void { _moveable.move(location) }
}

This is easily written using code due to it's regular layout. And that is exactly what my solution does, by injecting the equivilant bytecode into a new class. With this bytecode injection system we can create a Person object like so:

public class Main
{
    private var mixinRepo:MixinRepository = new MixinRepository()

    public function Main()
    {
        with(mixinRepo)
        {
            defineMixin(RoomObject, RoomObjectImpl) // associate interfaces with concreate classes
            defineMixin(Moveable, MoveableImpl)
            defineBase(Person)
            prepare().completed.add(testMixins) // the injection is a async process, just liek in ASMock
        }
    }

    private function testMixins():void
    {
        var person:Person = mixinRepo.create(Person)
        var room:Room = new Room('room you can play in')

        person.joinRoom(room)
        trace('person.room:', person.room)

        person.move(new Point(1, 2))
        trace('person.location:', person.location)
    }
}

At the moment this system is a proof of concept and is therefore very basic and brittle. But it shows that it is possible to come close to a Scala mixin/traits style system to AS3. I've made a github project to hold the code if anyone is interested in running the solution and poking around at how it was done.

A more complete example is given on the project wiki.

Brian Heylin
I noticed that your links weren't working, so I've updated them.
Andrew Aylett
Nice, thanks Andrew ;)
Brian Heylin
+1  A: 

Look here, this works, mixes in methods and is simple.

http://github.com/specialunderwear/as3-mixin

o, and it works when you compile in as3 mode.

specialunderwear
Nice idea, I'll give it a test run on my next as3 project.
Brian Heylin
Unfortunately, doing it that way doesn't help the type-checker :(.
Andrew Aylett