views:

434

answers:

4

Hi all! I am calling on different types classes from within a loop. The objects can be of different types so therefore I am using the getDefinitionByName method. here is a piece of my code:

for(var y = 0; y < mapH; y++)
            {
                brickHolder[y] = new Array();
                for(var x = 0; x < mapW; x++)
                {
                    var classRef = getDefinitionByName('com.objects.Brick2') as Class;
                    var brick:Brick2 = Brick2(new classRef());
                    brick.name = x+""+y;
                    brick.getBall(ball);
                    brick.getEngine(this);
                    brick.x = x * brick.bWidth + brick.bWidth;
                    brick.y = y * brick.bHeight + 100;
                    numberOfBricks += 1;
                    addChild(brick);

                }
            }

Only problem is I must cast this object into a specific variable:

var brick:Brick2 = Brick2(new classRef());

I thought about using a interface and casting it like this:

var brick:IBrick = IBrick(new classRef());

But I got an error when I tried to call on methods. The interface is blank; doesn't have any methods in it. I am not sure if that makes a difference. But the parent class inherits it and the subclasses inherit the parent class. Can I instead use the parent class?

var brick:ParentBrick2 = ParentBrick2(new classRef());

In a nutshell, what can I do to loosely cast these objects so I am able to use any subclass methods that get called?

A: 

The best way is to use an interface and define all of the common methods that you'll be using in the interface. That will ensure that all implementations have the right methods with the right signatures and provides type safety everywhere except the reflection where you get class by name.

A really bad way, which will work, is to type brick as "Object" or "*" which will allow you to call any method you want and will only give you an error at runtime instead of compile time if the method doesn't exist. This is a bad hack that you should avoid if possible.

You can also use duck-typing methodology where you type brick as "Object" but only call the methods if you confirm that they actually exist.

var brick:Object = new classRef();
if ("getBall" in brick)
    brick.getBall();

Doesn't give you any compile-time type safety, but will avoid runtime errors (assuming it's acceptable to just skip the missing methods).

Sam
well I tried object, I got an error. But like you said, I dont want to use that. I would rather stay object oriented. as for the second suggestion. its a great idea, but its not exactly what i am looking for. the parent class does the bulk of the work. If anything, I override the parent class methods to do things a little different.
numerical25
A: 

[UPDATE] after digging around it seems the virtual keyword is ignored by the compiler so this wont work. Yet another shortcoming of AS3 :(

I think Polymorphism is the concept you are after. I think you can do it in AS3 (virtual keyword exists).

http://msdn.microsoft.com/en-us/library/ms173152%28VS.80%29.aspx <-- C# examples but explains the idea well.

When a derived class overrides a virtual member, that member is called even when an instance of that class is being accessed as an instance of the base class

So if you make your base class functions virtual then you should still be able to call the new overridden functions of the subclasses even if the instance is of the base class type.

Allan
that is exactly what I am looking for. except I am getting errors even without calling any methods. As of right now, i have not added the keyword virtual to my functions yet. but do I need to when I am just trying to cast my subclass into the parent class varible... The base class is Brick(). the subclass is Brick2. I did this -- var classRef = getDefinitionByName('com.objects.Brick2') as Class; var brick:Brick = Brick(new classRef()); and I got a error. ReferenceError: Error #1065: Variable Brick2 is not defined.
numerical25
unfortunately after digging around the virtual keyword in AS3 is nothing more than a placeholder for now. The compiler ignores it :(.If you cast Brick2 to a variable of type Brick and call a overridden function, then it will call the Brick function and not the Brick2 function. Had virtual functions existed then it would have been possible to call the Brick2 overridden function on a Brick instance.
Allan
gotcha. So as of right now, its probably just there for something in the future. So AS3 doesnt necessarily have true polymorphism. Sure theres interfaces, buts there just to hold contract between classes. Theres really no plausible way to make loose type classes. from what I got so far. What I am afraid, I am going to have to do is create some type of factory that holds a series of case statements depending on the type of class provided.
numerical25
To think of it. Even that would not work. If I created a factory that return a requested class, I would have to specify the returning value. which would limit me to only returning one data type.
numerical25
yeah no true polymorphism :( I am also needing to do something similar. I guess perhaps you could return using an untyped class and just 'know' that you can cast it.. that might work but yeah not the best outcome
Allan
ok, I am reading this book called Advance AS3 design patterns. It says that all classes that implement an interface are no longer bound by its particular type. It also says that subclasses in as3 can be casted into a parents varible. if this is the case. why am I getting errors ?!? He is refering to a varible called item that has a data type IProduce. this is what he says ...
numerical25
"Now that item is declared as type IProduce, we can assign to item any instance of any class that implements IProduce. We're no longer locked into one specific class. If both Fruit and Vegetable implement IProduce then you can assign an instance of either class to item now that it's typed as IProduce."... He is saying this, but he is not mentioning the process of eventually casting the type into its own specific datatype , correct ?
numerical25
blah, so it does work!. It just doesnt work with getDefinitionByName(). which I think defeats the purpose of getDefinitionByName(). Theres no need in using it if you can only use 1 data type
numerical25
Better late than never, I was wrong about there being no polymorphism. I am not sure how I came to the incorrect conclusion but my comment about Brick2 etc is wrong, the desired result of Brick2 function being called on the base type happens. And the section of the book with the Interface is also proof. Sorry about that.
Allan
A: 

Yes, you should definitely be able to use the parent class, e.g.:

var c:Car = new Mercedes();

As for the interface case, you should only call functions defined by the interface. And having a blank interface doesn't make sense at all.

If I remember my AS3 quirks correctly, method and member name checking is done at runtime, and you should be able to call any function on an Object. So you might cast everything to Object as well:

var brick:Object = new classRef(); //or cast to Object
brick.name = x + "" + y;
brick.getBall(ball);

But use the parent type as in the car example. That's proper polymorphism.

aib
I tried that. It did not work. The base class is Brick(). the subclass is Brick2. I did this -- var classRef = getDefinitionByName('com.objects.Brick2') as Class; var brick:Brick = Brick(new classRef()); and I got a error. ReferenceError: Error #1065: Variable Brick2 is not defined.
numerical25
Yea, i understand it doesnt make much sense to not have any methods in the interface. but as of right now, I am trying to do anything to make my class loose type. so I can add any subclasses in the loop.
numerical25
Where do you refer to 'Brick2', though? The error message doesn't make sense. Did you try passing a `Class` around instead of using getDefByName()? Did you try making Brick2 public and/or having Brick2's definition visible at the time of the getDef...() call? (i.e. Can you say `var x = new Brick2();` inside the for loop?)
aib
yes, or better yet. if I cast Brick2(); into a varible that is type Brick2(), it works, but not if the recieving varible is Type Brick()
numerical25
haha, ok, so If initiate Brick2() directly to a varible of type Brick it works. It's just that if you use getDefinitionByName() to retrieve that class and then set it, that it doesnt work. which is I think silly because in way it defeats the purpose of using the getDefinitionByName() method. Anyone using it, 8/10 probably are it to call multiple types of classes. but if you already know that type, why use it when you can call it directly. dont get me wrong getDefinitionByName() does work. but you must cast it first into the method. In which your better off just doing it directly.
numerical25
I still think you should give `Class` a chance: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/Class.html
aib
Yea, that is a good idea. but its not dynamic, cause I cant use a string to pick out which class I want. I would have to create a factory to pick which class to get based on a string or number. in that case, I would be beter off just declaring the actual class themselfs.
numerical25
A: 

I've come to the conclusion that the best way to do it is to create a factory that gets the required class and use the parent class to catch the reference of what ever class your looking for. doing so you will still be able to inherit the subclass properties and methods and the parent class as well. This works the best I guess. I tried to catch the references of the class using an interface, but I got a an error thrown. So I am guessing you have to cast an interface varible before you can use its methods. I might be wrong

numerical25