Hi I'm wondering if I can have a packageless () AS3 class call a private method on the main class in the file. For example:
package demo
{
public class MyDemoClass
{
var helper:FriendlyHelperClass = new FriendlyHelperClass(this)
}
private function methodToCall():void
{
...
}
}
public class FriendlyHelperClass
{
public function FriendlyHelperClass(demo:MyDemoClass)
{
demo.methodToCall()
}
}
The call to methodToCall() from FriendlyHelperClass will fail as it is a private member of the MyDemoClass. Is there any way to call the methodToCall() method from the FriendlyHelperClass without extending MyDemoClass.
Basically I'm looking for inner class functionality that Java has or some sort of C++ style friend class.
Short answer : no.
You can never access a private member from outside a class in ActionScript. What you could do is use a namespace instead of a private scope. This would allow to give access to some members to selected classes. This is the closest of a friend class that you will get in AS3.
I'm afraid that is not possible, but if you make the class dynamic, then you can edit it while the program is running, and possibly add some useful functions to it, to access the private functions. I haven't tried it though.
Dynamic classes
Without testing the code, and knowing what your full problem. you can try passing the functions you need into the embedded class as a callback. e.g.,
helper.methodToCallCallback = this.methodToCall;
then inside FriendlyHelperClass:
this.methodToCallCallback();
Related
I made small .fla file in Flash Professional, and I have added .as (ActionScript File) in Flash Professional, and I have added something like code below to .as (ActionScript file), but the error appears and I am trying to figure it out, but can't, so I decided to post it in here instead.
package
{
import flash.display.MovieClip;
public class Bag extends MovieClip
{
static var firstBag:String;
public static function set setFirstBag(value:String):void
{
firstBag = value;
}
public static function get getFirstBag():String
{
return firstBag;
}
}
}
and I called it like this:
button1.addEventListener(MouseEvent.CLICK, onClickFirstButton);
function onClickFirstButton(e:MouseEvent):void
{
Bag.setFirstBag("First slot in the bag has been filled up!");
}
But I have received this following error:
Call to a possibly undefined method setFirstBag through a reference
with static type Class.
What could I do wrong?
The .as file and .fla file are on the same folder.
if I changed the Bag class to static. The error will be like this:
The static attribute may be used only on definitions inside a class.
Your answer much appreciated!
Thank you!
You're useing get like it is a mettod, but thay are accessors for properties so intead of:
Bag.setFirstBag("First slot in the bag has been filled up!");
use
Bag.setFirstBag ="First slot in the bag has been filled up!";
A few additional thoughts...
While syntactically valid, the definition and naming of your getter and setter is confusing and atypical, which I think contributed to your confusion about the behavior. You've actually defined two separate properties, one is write-only ("setFirstBag") and one is read-only ("getFirstBag"). Usually you define a getter/setter as the same property (ex "firstBag"), and without any "get" or "set" in the property name, since that is what the getter/setter is defining for you. Example:
private static var _firstBag:String;
public static function get firstBag():String {
return _firstBag:
}
public static function set firstBag(value:String):void {
_firstBag = value;
}
// usage
Bag.firstBag = "stuff";
trace(Bag.firstBag); // "stuff"
Also, you may very well have a good reason to use a getter/setter here, or you might just prefer it, but from the code you posted you could just define a public static var to do the same thing. (If you did, refactoring into a getter/setter if you needed some side-effect logic would be trivial, since the public API remains the same.)
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).
I've learned one way to do that, but I want to improve my knowledge. For simplicity I'm not going to use import neither extends in the code below.
1
public class Main
{
public function Main()
{
new MyCustomObject(stage);
}
}
2
public class MyCustomObject
{
public var referenceStage:Stage = new Stage();
public function MyCustomObject(xxx:Stage)
{
this.referenceStage = xxx;
referenceStage.addChild(this);
}
}
I've learned it reading a tutorial over internet, but I want to know where I can find more samples on how to reference objects in AS3. For future codes, I want to add hitTest and the like.
Thanks !
The best place is the ActionScript 3 Reference from Adobe: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/index.html
Here is the specific section on objects: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Object.html
if you absolutely want to pass a stage reference through an argument to a constructor, you can do so about how you have it laid out (although get rid of the new Stage() call, which won't do anything).
that said, .stage is a property available to all display objects that are in the display list (meaning: the have been added via addChild or addChildAt).
you're probably getting that error trying to reference a .stage property of an object before it's been added to the display list. this is a common error, and can be handled by waiting to reference the .stage property until it has been added, usually using addEventListener(Event.ADDED_TO_STAGE...
so instead of
public class MyObject extends Sprite {
public function MyObject():void{
this.x = this.stage.stageWidth/2;
}
}
you'd use something like this
public class MyObject extends Sprite {
public function MyObject():void{
this.addEventListener(Event.ADDED_TO_STAGE, this.addedHandler, false, 0, true);
}
private function addedHandler(e:Event):void{
this.x = this.stage.stageWidth/2;
}
}
HTH
In your example, you don't need do call new Stage() in your CustomObject
public var referenceStage:Stage;
is enough
A hitting function may be found here http://troygilbert.com/2007/06/pixel-perfect-collision-detection-in-actionscript3/
Possible solutions are:
Instead of passing the stage object, you can also pass the main object and calling functions in the main object for the custom object
Maintain an array in the MainObject with which you want do collisions test.
Implementing an Interface (extend an object) with a function which do the hit test agains the array in the MainObject (for example went the EntreFrame Event is fired)
Custom Events are the solution for communicating with the main object loosely
Passing a reference to an object in the constructor is a classic OOP pattern
Possibly bad practice but I'm not well versed in software design anyway (I'm sure this question would have been asked before but I can't seem to find the right terminology)...Anyhow, it's just another curiosity of mine I'd like to have answered.
So I have worked in a way where I type a base class variable to type Object or Sprite or something similar so that in my subclasses, I can instantiate my custom classes into them and store it. And when I access it, I just cast that variable to ensure I can access the methods.
Take this example, so that you know what I'm talking about:
public class BaseClass
{
protected var the_holder_var:Object;
public function BaseClass()
{
//Whatever abstract implementation here...
}
}
Now, my subclasses of that base class usually use an interface but for simplicity sake, I'll just write it without it.
public class AnExtendedClass extends BaseClass
{
public function AnExtendedClass()
{
//Instantiate my own class into the base class variable
this.the_holder_var = new ACustomClassOfMine();
//Then I can use the 'hackish' getter function below to
//access the var's functions.
this.holder_var.somefunction()
}
private function get holder_var():ACustomClassOfMine
{
return this.the_holder_var as ACustomClassOfMine;
}
}
This works and I'm sure it will make some ppl cringe (I sometimes cringe at it too).
So now, my question, is there a way to recast/retype that base var in my extended subclass?
kinda like this:
public class ExtendedClass extends BaseClass
{
//Not possible I know, but as a reference to see what I'm asking about
//Just want to change the type....
override protected var the_holder_var:ACustomClassOfMine;
public function ExtendedClass()
{
//Then I can forget about having that hackish getter method.
this.the_holder_var = new ACustomClassOfMine();
this.the_holder_var.somefunction();
}
}
I was thinking of typing most of my base class vars that I use as holders as type * and retyping them as I extend the class. (I could use it here too but yeah...)
Thoughts? Comments? Ideas?
I actually think your code (apart from the hypothetical addition at the end) is pretty alright. The practise of adding accessors to solve the type issue you're dealing with is a solid one. I would advise to rename the accessor to show it is a cast, maybe get holderVarAsCustom():ACustomClassOfMine (I'm also not a big fan of the underscores, that's another language's convention), but that's personal preference. What I'd do to solve your last problem is just create a matching setter function:
private function set holderVarAsCustom(value:ACustomClassOfMine):void {
this.the_holder_var = value;
}
This way you can access the correctly typed holder var for both read and write operations with complete type safety:
holderVarAsCustom = new ACustomClassOfMine();
holderVarAsCustom.someFunction();
I would definately advise against dropping the type safety by including arrays and what not, that just makes it unstable.
I must admit that i'm a little confused as to why you want to do this, but here goes. Could you not utilise the fact that Array's can hold different data types. So something like this:
public class BaseClass
{
protected var customStorage:Array;
public function BaseClass()
{
//Whatever abstract implementation here...
}
}
You could then access it with an associative method and a property:
public class AnExtendedClass extends BaseClass
{
private static const myName:String = "myName";
public function AnExtendedClass()
{
//Instantiate my own class into the base class variable
customStorage[myName] = new ACustomClassOfMine();
objectIWant.somefunction()
}
private function get objectIWant():ACustomClassOfMine
{
return ACustomClassOfMine(customStorage[myName]);
}
}
Is that any better?
I would not try to tinker this behaviour, since you can't change the declared type of a variable once declared, no matter how hard you try.
What I do in such cases, I either cast the variable if I use it sparingly or the object it references may change, or I add another variable with the type I want and let the other variable point to the new one. Like this:
public class A {
protected var object:Object;
public function A() {
//Whatever abstract implementation here...
}
}
and
public class B extends A {
protected var other:MyClass;
public function B() {
super();
this.other = new MyClass();
this.object = this.other;
}
}
Having it this way, class A uses the object via the this.object reference, and class B can use the this.other or both. But both references point to the same object. The only issues with this are:
having two references for in the same class to the same object is ugly (so are untyped variables and casts)
if the object one of them may point can change during runtime, you must be really carefull to synchronize these changes
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?
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.
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.
I found this one in Realaxy -- http://realaxy.com/