Robotlegs wiring up dependencies that belong to a base class - actionscript-3

I'm using robot legs, I've got a bunch of ServiceResponses that extends a base class and have a dependency on a Parser, IParser. I need to wire in a parser specific to the subclass. Here's an example:
ModuleConfigResponse extends SimpleServiceResponse and implements IServiceResponse.
The initial part is easy to wire in the context, here's an example:
injector.mapClass(IServiceResponse, ModuleConfigResponse);
injector.mapClass(IServiceResponse, SimpleServiceResponse, "roomconfig");
..etc
Each Response uses a parser that is used by the baseclass:
injector.mapValue(IParser, ModuleConfigParser, "moduleconfig");
injector.mapValue(IParser, RoomConfigParser, "roomconfig");
The question is how to tie these together. The base class could have:
[Inject]
public var parser : IParser
But I can't define the type ahead of time. Im wondering if there a nice way of wiring this in the context. For the moment I've decided to wire this up by instanciating responses in a ResponseFactory instead so that I pay pass the parser manually in the constructor.
injector.mapValue(IParser, ModuleConfigParser, "moduleconfig");

I realised that not everything can be mapped in the context, RL trapped me into this way of thinking. But I've realised that its far better to map a factory to produce these objects which have very specific dependencies, than littler the codebase with marker interfaces or strings :)

one solution is to have the following in your base class:
protected var _parser : IParser
Then for instance in ModuleConfigResponse
[Inject(name='moduleconfig')]
public function set parser( value : IParser ) : void{
_parser = value;
}
But TBH, using named injections is STRONGLY discouraged, you might as well use a marker interface:
public interface IModuleConfigParser extends IParser{}
the base class stays the same, but ModuleConfigResponse would then use:
[Inject]
public function set parser( value : IModuleConfigParser ) : void{
_parser = value;
}

Related

When using the 'Class' datatype, how can I specify the type so I only accept subclass of a specific class?

I've got a method that accepts a parameter of type Class, and I want to only accept classes that extend SuperClass. Right now, all I can figure out to do is this, which does a run-time check on an instance:
public function careless(SomeClass:Class):void {
var instance:SomeClass = new SomeClass();
if (instance as SuperClass) {
// great, i guess
} else {
// damn, wish i'd have known this at compile time
}
}
Is there any way to do something like this, so I can be assured that a Class instance extends some super class?
public function careful(SomeClass:[Class extends SuperClass]):void {
var instance:SuperClass = new SomeClass();
// all is good
}
If you are going to instantiate it anyway, why not accept an object instead which allows you to type it to :SuperClass?
careless(SomeClass);
//vs.
careless(new SomeClass);
Not too much of a problem there as far as your code goes.
There are a few differences though:
The object has to be created, because an object is required. If your function does not instantiate the class under some circumstances, this can be a problem. Additional logic to pass either an object or null can bloat the function call.
If you cannot call the constructor outside that function, it won't
work either.
All that is solved by the factory pattern. Pass a factory as the parameter that produces SuperClass objects.
function careful(factory:SuperClassFactory)
Your requirements:
I want to only accept classes that extend SuperClass
and
I need to pass in a Class so that it can be instantiated many times
by other objects later
Can be met by passing in an instance of the class you need, and using the Object.constructor() method.
public function careful(someInstance:SuperClass):void {
//you probably want to store classRef in a member variable
var classRef: Class = someInstance.constructor();
//the following is guaranteed to cast correctly,
//since someInstance will always be a descendant of SuperClass
var myInst:SuperClass = new classRef() as SuperClass;
}
More reading here.
You can't do that in ActionScript 3. In languages like C# you can do something like (forgive me if the syntax is off):
public void Careless<T>() where T : SuperClass
But AS3 does not have 'generics'. Unfortunately the only way I know how to do what you want is the way you have already done.
A pattern that might be more suitable for your use case might be something like:
class SuperClass
{
public static function careless():void
{
var instance:SuperClass = new SuperClass();
// ...
}
}
The only way to have static type checking in ActionScript 3 is to provide an instance of a class.
It is possible but it's expensive. You can use on a Class (not instance) the:
flash.utils.describeType
You then get an XML with a bunch of information including inheritance for that class. Like I said it's an expensive process and probably creating an instance and checking it will be in most cases faster.

How Actionscript 3 Classes Work

I need a little help understanding how classes work in Actionscript 3. I understand you start with "package" and why and then go to import any necessary libraries, as well as then naming the class and stating if it's public/private and extends anything.
After that is what I don't understand. It seems you write "(public) function class name()
I don't understand why you do this and what goes in the curly brackets.
I've probably missed a bit of earlier reading because I've done a little reading but I can't seem to get it.
Could someone try explain it to me? Thanks.
ActionScript 3 Classes
The package statement.
Okay, so firstly like you mentioned, a class must be wrapped by a package1. This gives us the first block, where you need to define the class.
package
{
// Your class here.
}
The package statement reflects the location of the class relative to the .fla2. For example, if you have a folder "classes" within the same directory as the project .fla, then classes within that folder will need a package statement that reflects that:
package classes
{
// Your class here.
}
Defining the class.
Within a package statement, you may insert one class. Do not confuse this with the package itself, which can contain many classes - each class just needs to have its own file with the same package statement.
A class definition is made up of up to 5 parts:
The namespace. A class can be internal or public. An internal class can only be seen by classes within the same package, whereas public classes can be seen from anywhere in the project.
The class name.
A base class (optional). If a base class is defined, then your new class will act as an extension to that class, inheriting all of the qualities of the base class.
An interface to implement (optional). Interfaces are an advanced topic thus I suggest you forget about these for now until your AS3 and OOP have evolved.
If you wanted to create a class called "Person" within the package classes, then we would end up with:
package classes
{
public class Person
{
// Class qualities here.
}
}
Properties.
Classes can contain properties. Properties are defined using the var keyword. They may belong to one of a number of namespaces (including your own) and are used to hold values that belong to your class. Properties are most commonly found clustered together at the top of your class.
Our Person class may enjoy the properties height and weight:
package classes
{
public class Person
{
// Properties.
public var height:Number = 1.70;
public var weight:Number = 67.5;
}
}
These properties can be accessed via any instance of Person that you create. Each instance will have its own set of these properties.
Class constructors (I believe this is what you're asking about).
Constructors are used to hold logic that should be run as soon as an instance of your class is created. The class constructor has the same name as the class itself. It must be public and it does not return anything. Constructors can accept arguments, which are typically used to pass in references to dependencies for that class or required values.
package classes
{
public class Person
{
// Properties.
public var height:Number = 1.70;
public var weight:Number = 67.5;
// Constructor.
public function Person(height:Number, weight:Number)
{
this.height = height;
this.weight = weight;
}
}
}
Methods.
Methods are used to hold logic that can be run when calling that method. Methods often return values and can accept arguments. Methods can belong to any namespace that you would expect properties to be able to belong to.
We may want to be able to easily determine the BMI of each instance of Person that we create, so we should create a method for that:
package classes
{
public class Person
{
// Properties.
public var height:Number = 170;
public var weight:Number = 65.5;
// Constructor.
public function Person(height:Number, weight:Number)
{
this.height = height;
this.weight = weight;
}
// Determine my BMI and return the result.
public function getBMI():Number
{
return weight / (height * height);
}
}
}
Instances.
Now that we've defined our new class, we can create instances of this class using the new keyword. This can be done from anywhere that can access the Person class, which in this case is anywhere in the project because we've made the class public.
Though the class is public, accessing it from anywhere outside of the package it belongs in will require the use of an import statement. This statement will need to be used within any class that belongs to a different package. The import statement follows the same name used for the package and includes the name of the class you want to include on the end:
import classes.Person;
Once you've imported Person, you can create instances of it and assign them to a variable with different height and weight values:
var marty:Person = new Person(71, 1.76);
var bruce:Person = new Person(96.4, 1.72);
We can then obtain the BMI for each person using their getBMI() method:
trace(marty.getBMI()); // 22.9
trace(bruce.getBMI()); // 32.6
1 You can place classes outside of a package which can be referred to in the same .as file.
2 You can add more source paths, and packages can be relative to that.
The function that have the same name as class is a constructor. In curly brackets is basically part of code that will execute instantly when object will be created. Try to search info about constructors, they exist I think in every object oriented programming language (I may be wrong), so you have a lot of resources.
You can also read about this concept on Wikipedia.
The function that is named the same as the class is the constructor. It's optional, so you can leave it out if you don't need it. A default constructor will be added, which essentially does nothing.
The constructor lets you write code that executes immediately after an instance of the class is created (ie when another bit of code runs new ClassName(). You would typically use it to initialise some variables that are used by the class. Defining a constructor also lets you handle constructor arguments, which other code can pass when they use the new operator.

How can I create a subclass that takes in different parameters for the same function name?

So I have made this simple interface:
package{
public interface GraphADT{
function addNode(newNode:Node):Boolean;
}
}
I have also created a simple class Graph:
package{
public class Graph implements GraphADT{
protected var nodes:LinkedList;
public function Graph(){
nodes = new LinkedList();
}
public function addNode (newNode:Node):Boolean{
return nodes.add(newNode);
}
}
last but not least I have created another simple class AdjacancyListGraph:
package{
public class AdjacancyListGraph extends Graph{
public function AdjacancyListGraph(){
super();
}
override public function addNode(newNode:AwareNode):Boolean{
return nodes.add(newNode);
}
}
Having this setup here is giving me errors, namely:
1144: Interface method addNode in namespace GraphADT is implemented with an incompatible signature in class AdjacancyListGraph.
Upon closer inspection it was apparent that AS3 doesn't like the different parameter types from the different Graph classes newNode:Node from Graph , and newNode:AwareNode from AdjacancyListGraph
However I don't understand why that would be a problem since AwareNode is a subClass of Node.
Is there any way I can make my code work, while keeping the integrity of the code?
Simple answer:
If you don't really, really need your 'addNode()' function to accept only an AwareNode, you can just change the parameter type to Node. Since AwareNode extends Node, you can pass in an AwareNode without problems. You could check for type correctness within the function body :
subclass... {
override public function addNode (node:Node ) : Boolean {
if (node is AwareNode) return nodes.add(node);
return false;
}
}
Longer answer:
I agree with #32bitkid that your are getting an error, because the parameter type defined for addNode() in your interface differs from the type in your subclass.
However, the main problem at hand is that ActionScript generally does not allow function overloading (having more than one method of the same name, but with different parameters or return values), because each function is treated like a generic class member - the same way a variable is. You might call a function like this:
myClass.addNode (node);
but you might also call it like this:
myClass["addNode"](node);
Each member is stored by name - and you can always use that name to access it. Unfortunately, this means that you are only allowed to use each function name once within a class, regardless of how many parameters of which type it takes - nothing comes without a price: You gain flexibility in one regard, you lose some comfort in another.
Hence, you are only allowed to override methods with the exact same signature - it's a way to make you stick to what you decided upon when you wrote the base class. While you could obviously argue that this is a bad idea, and that it makes more sense to use overloading or allow different signatures in subclasses, there are some advantages to the way that AS handles functions, which will eventually help you solve your problem: You can use a type-checking function, or even pass one on as a parameter!
Consider this:
class... {
protected function check (node:Node) : Boolean {
return node is Node;
}
public function addNode (node:Node) : Boolean {
if (check(node)) return nodes.add(node);
return false;
}
}
In this example, you could override check (node:Node):
subclass... {
override protected function check (node:Node) : Boolean {
return node is AwareNode;
}
}
and achieve the exact same effect you desired, without breaking the interface contract - except, in your example, the compiler would throw an error if you passed in the wrong type, while in this one, the mistake would only be visible at runtime (a false return value).
You can also make this even more dynamic:
class... {
public function addNode (node:Node, check : Function ) : Boolean {
if (check(node)) return nodes.add(node);
return false;
}
}
Note that this addNode function accepts a Function as a parameter, and that we call that function instead of a class method:
var f:Function = function (node:Node) : Boolean {
return node is AwareNode;
}
addNode (node, f);
This would allow you to become very flexible with your implementation - you can even do plausibility checks in the anonymous function, such as verifying the node's content. And you wouldn't even have to extend your class, unless you were going to add other functionality than just type correctness.
Having an interface will also allow you to create implementations that don't inherit from the original base class - you can write a whole different class hierarchy, it only has to implement the interface, and all your previous code will remain valid.
I guess the question is really this: What are you trying to accomplish?
As to why you are getting an error, consider this:
public class AnotherNode extends Node { }
and then:
var alGraph:AdjacancyListGraph = new AdjacancyListGraph();
alGraph.addNode(new AnotherNode());
// Wont work. AnotherNode isn't compatable with the signature
// for addNode(node:AwareNode)
// but what about the contract?
var igraphADT:GraphADT = GraphADT(alGraph);
igraphADT.addNode(new AnotherNode()); // WTF?
According to the interface this should be fine. But your implemenation says otherwise, your implemenation says that it will only accept a AwareNode. There is an obvious mismatch. If you are going to have an interface, a contract that your object should follow, then you might as well follow it. Otherwise, whats the point of the interface in the first place.
I submit that architecture messed up somewhere if you are trying to do this. Even if the language were to support it, I would say that its a "Bad Idea™"
There's an easier way, then suggested above, but less safe:
public class Parent {
public function get foo():Function { return this._foo; }
protected var _foo:Function = function(node:Node):void { ... }}
public class Child extends Parent {
public function Child() {
super();
this._foo = function(node:AnotherNode):void { ... }}}
Of course _foo needs not be declared in place, the syntax used is for shortness and demonstration purposes only.
You will loose the ability of the compiler to check types, but the runtime type matching will still apply.
Yet another way to go about it - don't declare methods in the classes they specialize on, rather make them static, then you will not inherit them automatically:
public class Parent {
public static function foo(parent:Parent, node:Node):Function { ... }}
public class Child extends Parent {
public static function foo(parent:Child, node:Node):Function { ... }}
Note that in second case protected fields are accessible inside the static method, so you can achieve certain encapsulation. Besides, if you have a lot of Parent or Child instances, you will save on individual instance memory footprint (as static methods therefore static there exists only one copy of them, but instance methods would be copied for each instance). The disadvantage is that you won't be able to use interfaces (can be actually an improvement... depends on your personal preferences).

AS3 internal and custom namespaces

I have the following packages:
spark
spark.engine
Within spark I have a class SeCore; and within spark.engine I have SeStepper and SeKeyboard.
What I'm trying to achieve is have SeCore as being the only class that can create an instance of SeStepper or SeKeyboard. This can be achieved by moving SeCore into the spark.engine package and making the other two classes internal, but I'd like to have SeCore in the spark package if possible.
I've tried making my own namespace to handle this, like so:
package spark.engine
{
import spark.namespaces.spark_core;
use namespace spark_core;
spark_core class SeStepper extends SeObject
{
//
}
}
However I get the error:
1116: A user-defined namespace attribute can only be used at the top
level of a class definition.
Are there any other approaches I can take to achieve what I'm after?
99% of the time, marking anything as 'internal' is a bad idea. It's better to have a naming convention for 'off-limits' classes and members, and allow developers to go there at their own risk. Marking things as 'internal' or 'private' is something that should only be done rarely, and with great forethought.
However, you could enforce this behavior at run time by using a read-only property in SeCore and checking its value from SeStepper and SeKeyboard.
Following is pseudocode, haven't used AS3 in a while.
In SeCore
private var _createAuthorized = false;
public function get CreateAuthorized():boolean {return _createAuthorized;}
private function createSeStepper(){
_createAuthorized = true;
var obj = new SeStepper(this)
_createAuthorized = false;
return obj;
}
in SeStepper
public function SeStepper(core:SeCore){
if (!core.CreateAuthorized) throw new Error("Only SeCore can do this");
}
I can't agree with the answer, i mean making things public is way to invite hackers. I can execute any public functions in any flash running on my computer in any context i want, i can even override their execution in memory since they are easy to find, whereas doing something like that with private/internal functions is almost impossible.

OOP Proper use of interfaces in AS3

I'm designing a framework and in the process I have come across an interesting but most likely basic problem. I have a base class called CoreEngine and two other classes that extend it: CoreEngine1 and CoreEngine2. I created an interface that each of these classes would implement to increase the flexibility of my project. However, I have a problem... The definition of my methods in the interface do not match the definition in each inherited class! Each class must implement the following method:
function get avatar():AvatarBase;
The problem is that CoreEngine1 and CoreEngine2 expect a different type of avatar:
CoreEngine1
function get avatar():AvatarScaling
CoreEngine2
function get avatar():AvatarPlatform
As you can see, the return type for avatar in CoreEngine1 and CoreEngine2 do NOT match the type as specified in the interface. I was hoping that since both AvatarScaling and AvatarPlatform inherit AvatarBase that I wouldn't have a problem compiling. However, this is not the case. According to Adobe's documentation, the types MUST match the interface. I am trying to follow one of the core concepts of object oriented programming to extend the flexibility of my framework: "Program to an interface rather than an implementation". The first thing that comes to my mind is that the return type of the accessor method should be of an interface type (Maybe I just answered my own question).
I'm certain this is a common problem others have run into before. Architecturally, what do you think is the best way to solve this problem? Thanks in advance!
Regards,
Will
This is a limitation of how interfaces work and are declared.
If there's inheritance that can happen with the return types, as you've described with AvatarBase and subclasses, then I think the right approach is to make the return type the lowest common denominator and just handle the resulting object on the other end. So, if you're dealing with a CoreEngine1 object, you know you can cast the result from AvatarBase to AvatarScaling. Alternately, if you don't know the object type that you are calling get avatar() on, then you can type check the returned value. The type check would then only be needed if you're looking to call a method that exists on AvatarScaling but not on AvatarBase. I don't think returning an interface type will buy you much in this case because the only things that interface can implement would be things that all forms of Avatar share, which wouldn't be any different than methods in AvatarBase.
Like HotN and Dinko mentioned, it would be best to allow get avatar() to return AvatarBase allways and then cast the returned object as the concrete subclass.
Using Dinko's example:
public /* abstract */ class CoreEngine
{
public /* abstract */ function get avatar():AvatarBase {}
}
public function CoreEngine1 extends CoreEngine
{
override public function get avatar():AvatarBase { return new AvatarScaling(); }
}
public function CoreEngine2 extends CoreEngine
{
override public function get avatar():AvatarBase { return new AvatarPlatform(); }
}
public /* abstract */ class AvatarBase {}
public class AvatarScaling extends AvatarBase
{
public function someAvatarScalingMethod():void {}
}
public class AvatarPlatform extends AvatarBase
{
public function someAvatarPlatformMethod():void {}
}
To use a method from AvatarScaling, cast the returned object:
var c1:CoreEngine1 = new CoreEngine1();
var avatarScaling:AvatarScaling = AvatarScaling(c1.avatar());
avatarScaling.someAvatarScalingMethod();
hth
I think you answered your own question... the return type would still be AvatarBase, you need to follow the signature that you specified in the interface... but you can technically return ANY descendent of AvatarBase in that function. So doing something like
return new AvatarScaling();
in CoreEngine1 would be perfectly acceptable.
Of course in your calling function you will get back an AvatarBase instance, and you will have to know what this is in order to cast to a specific subclass.
CoreEngine1 ce1 = new CoreEngine1();
AvatarScaling avatar = ce1.avatar() as AvatarScaling;