How to properly override getters and setters in Haxe - actionscript-3

I'm kind of new to Haxe but I have a lot of experience in ActionScript 3. Right now I'm porting one of my frameworks from AS3 to openfl, but I'm kind of stuck with getters and setters.
Some of the framework components extends from openfl.display.DisplayObject (Sprite, to be exact) which already defines fields for width and height. But in my ComponentBase class I need to override these properties.
In AS3 I'm doing it like this:
private var _width:Number = 0;
override public function get width():Number {
return _width;
}
override public function set width(value:Number):void {
_width = value;
}
But it doesn't work in Haxe. If I do it like this
override function get_width():Float {
return _width;
}
It won't compile because it wants a physical field. But I also cannot redefine width and height values because they are already defined in base class.
You may ask why am I not using the values 'width' and 'height' defined in the base class. That's because sometimes I need to access those variables not thru the getter/setter accessors but directly. For example, I have a call to layout() method inside width and height setters, but I want to calculate it many times and call layout() only once.
Right now I decided to use Java-style getters and setters to make the job done, but it's not the best way. E.g.
public function setWidth(value:Float):Void {
_width = value;
}
So, the question is: is it possible to make Haxe getters and setters use some value which has the name different than they're supposed to access?

Sorry, it was me who was missing something. The way getters and setters are properly defined in Haxe
Now, after I've seen the example by Ben Morris here, I got the point.
So besides width and height properties I had some custom ones to override and they gave me "missing physical field errors"
I just had to specify a physical field for them and then use any properties in get_ / set_ accessors
E.g.
// physical field
public var top(get, set):Float;
var _customTop:Float = 100;
public function get_top():Float {
return _customTop; // now I can return what ever here
}
public function set_top(value:Float):Float{
return _customTop = value;
}
I don't know who has downvoted my question, but this is really crucial matter I've spent a lot of time trying to get the solution for. And it was really so easy.
Thanks to Ben Morris! If you had posted your comment as answer, I would accept it

Related

How to have protected set functions?

I'm working in ActionScript 3, but I'm guessing this is a universal concept.
I've recently stumbled upon the world of get and set functions, and I immediately tried to apply it to my code, since before I'd need to run an explicit set function so that two parameters would keep up to date with each other.
However, I only ever actually SET the variable in a subclass to where the variable is defined - so I'd like it to be protected. Unfortunately, the code seems to only work when the set function is public, and I have no clue. All the examples I could find online never used a set function except outside of the class it was defined in.
This isn't so much something that's going to be difficult to work around (I would just use an explicit set function) as something I want to understand to become a better programmer, and maybe help someone else who is in my position.
Here's my code which might make my point a bit clearer:
private var _iColumn:int;
private var _iRow:int;
public function get iColumn():int { return _iColumn; }
public function get iRow():int { return _iRow; }
protected function set iColumn(setValue:int):void {
_iColumn = setValue;
resetClickArea();
}
protected function set iRow(setValue:int):void {
_iRow = setValue;
resetClickArea();
}
public function TileElement(column:int, row:int)
{
iColumn = column; // Complains that property is read-only
iRow = row; // Complains that property is read-only
}
Both getter and setter need to have the same namespace (public, protected or private) so if the getter needs to be public your only option is to make the setter public as well or replace the setter by a protected function like setIRow or something.
Making both getter and setter protected would make valid code but of course you won't be able to access the the property from outside.
Most languages don't even have this nice feature of get and set keywords. You would be better off creating your own getter and setter functions getRow(); and setRow(r);. One other bonus is that you don't get too attached to this AS3 feature, and it would be easier to work within other languages like C++.

How to choose which child class to instantiate dynamically

My current project is in as3, but this is something I am curious about for other languages as well.
I'm attempting to use a factory object to create the appropriate object dynamically. My LevelFactory has a static method that returns a new instance of the level number provided to the method. In the code calling that method, I am able to dynamically create the buttons to call the levels like so:
for (var i:int = 1; i < 4; i++) {
var tempbutton:Sprite = createButton("Level " + i, 25, 25 +(60 * i), start(i));
_buttons.push(button);
}
This code just creates a simple button with the given arguments (ButtonText, x, y, function). It's working fine. The buttons are created, and clicking on one of them calls this method with the appropriate argument
private function start(level:int):Function {
return function(e:MouseEvent):void {
disableButtons();
newLevel = LevelFactory.createLevel(level);
addChild(newLevel);
}
}
This is all working fine; I'm just providing it for background context. The question I have is this: Is it possible to dynamically choose the type of object that my static function returns? Currently, I have am doing it as follows
public static function createLevel(level:int):Level {
var result:Level;
switch(level) {
case 1: result = new Level1(); break;
case 2: result = new Level2(); break;
//etc
}
return result;
}
I should note that all of these Level1, Level2, etc. classes extend my base level class. (Yay polymorphism!) What I would like to do is be able to do something along the lines of
public static function createLevel(level:int):Level {
var result:Level;
var levelType:String = "Level" + level;
return new levelType();
}
Obviously it's not going to work with a string like that, but is there any way to accomplish this in as3? What about other languages, such as Java or Python? Can you dynamically choose what type of child class to instantiate?
Update:
import Levels.*;
import flash.events.*;
import flash.utils.*;
public class LevelFactory
{
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.' + 'Level' + level) as Class;
var result:Level = new ref();
return result;
}
}
Update/Edit: getDefinitionByName seems to be what I'm looking for, but it has a problem. It seems that the compiler will strip unused imports, which means that unless I declare each subclass in the code ahead of time, this method will get a reference error. How can I get around the need to declare each class separately (which defeats the purpose of dynamic instantiation)?
Yes, you sure can, and it's very similar to the string thing that you've provided. The only thing that you are missing is the getDefinitionByName method: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#getDefinitionByName()
You can generate whatever class name you want, and what this method does is that it searches for that class in it's namespace, and if it finds it - it returns it as a class:
var ClassReference:Class = getDefinitionByName("flash.display.Sprite") as Class;
var instance:Object = new ClassReference();
This piece of code will instantiate a Sprite. This way you can instantiate your classes without all those switches and cases, especially when you have to make a hundred levels :)
Hope that helps! Cheers!
Edit:
In your case, the code should be:
var ref:Class = getDefinitionByName('com.path.Level' + index) as Class;
var level:Level = new ref(); // it will actually be Level1 Class
Since Andrey didn't quite finish helping me out, I am writing up a more complete answer to the question after much research.
getDefinitionByName definitely has the use I am looking for. However, unlike its use in Java, you HAVE to have a hard reference to the class you want instantiated somewhere in your code. Merely imported the class is not enough; the reason for this is that the compiler will strip the reference from any unused import to save space. So if you import the package of classes you want to choose dynamically but don't have a hard reference to them, the compiler will de-reference them. This will lead to a run-time error when the program cannot find the appropriate reference to your class.
Note that you don't actually have to do anything with the reference. You just have to declare a reference so that it can be found at run-time. So the following code will work to eliminate the switch-case statement and allow me to dynamically declare which class I am using at run-time.
{
import Levels.*;
import flash.events.*;
import flash.utils.*;
/**
*
* Returns the requested level using the createLevel class
* ...
* #author Joshua Zollinger
*/
public class LevelFactory
{
Level1, Level2, Level3, Level4, Level5, Level6, Level7;
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.Level' + level) as Class;
var result:Level = new ref(); // it will actually be the correct class
return result;
}}}
The obvious downside to this is that you still have to have a hard-coded reference to every class that can be instantiated like this. In this case, if I try to create a Level8 instance, it will through a run-time error because Level8 is not referenced. So every time I create a new level, I still have to go add a reference to it; I can't just use the reference dynamically.
There are supposedly ways around this that I have not tested yet, such as putting the code for the classes in a separate SWF and importing the SWF at run-time or using outside libraries that will have different functionality. If anyone has a solid way to get a truly dynamic reference that doesn't require a hard coded reference anywhere, I would love to hear about it.
Of course, it's still a lot cleaner this way; I don't have a extensive switch case statement to pack all the levels. And it's easier and faster to add a reference to the list than creating a new case in a switch. Plus it is closer to dynamic programming, which is usually a good thing.

Enumerating class properties

I'm trying to iterate through the properties of a custom class, however, the methods provided by Adobe appear to not work. I'm not receiving compile or run-time errors.
Class
package {
public dynamic class enum {
public var foo:Number = 123;
public function enum() {
this.setPropertyIsEnumerable("foo", true);
if (this.propertyIsEnumerable("foo") == false) {
trace("foo:" + foo + " is not enumerable.")
}
}
}
}
// outputs "foo:bar is not enumerable."
Implementaiton
var test:enum = new enum();
for (var property:String in test) {
trace(property);
}
// outputs nothing
I try to keep my code fast and flexible, so it's really frustrating when you must change the class to Dynamic just to be able to use for ... in on the properties. Jackson Dunstan's testing confirms that this can be 400x slower than static class properties, but those have to be explicitly referenced (impractical for property agnostic methods), or use reflection of the class (computationally expensive) to be accessible.
The only way I've found to sidestep the whole issue is to use dynamically declared variables... which is pointless since at that point using setPropertyIsEnumerable(prop, true) is superfluous; all dynamically created properties already are enumerable. Additionally, dynamic variables cannot be strongly datatyped, and performance goes out the window.
For example...
Class
package {
public dynamic class enum {
public var foo:String = "apple";
public function enum(){
this.dynamicVar = "orange";
this.dynamicProp = "banana";
this.setPropertyIsEnumerable("foo", true);
this.setPropertyIsEnumerable("dynamicProp", false);
}
}
}
Implementation
var test:enum = new enum();
for (var key:String in test) {
trace(key + ": " + test[key]); // dynamicVar: 1
}
// outputs "dynamicVar: orange"
Now that the class is dynamic, we see that only one of our 3 test properties are being iterated. There should be 2.
It almost feels like Adobe wants us to adopt bad programming habits. Words fail me...
Non-dynamic classes do not provide enumerable properties or methods.
As stated in the description of the link you provided.
Sets the availability of a dynamic property for loop operations.
I think you might want to refactor your code on this approach.
I have never had to loop over a classes properties like you are doing here.
If you want to track items dynamically you should use an associative array and track them that way not at the class level like you are doing.
And if you want strong data typing then use a vector.

AS3: How to work with properties of the classes on stage (display list) from class not in the display list?

Hi guys,
I have two objects on stage so I presume they are in the Display list as well (Progress_mc, Ship_mc). I have Calculator class which doesn't represent any visual shape or anything but as3 code so it isn't in the display list.
What is the best way to work with the properties of Progress_mc?
Example: Calculator_as has to receive Progress_mc.width any time width has been changed and after some calculation Calculator has to send some calculated results to Ship_mc.x.
I was thinking if I have to addChild(Calculator) on stage so I can have access to those MCs in Calculator.as but this class isn't a visual object so I am not sure this is the right way.
Or I have to do this (code below) in Calculator class and then try to access the properties but I this way wont work either because the properties wont be of the instances on stage:
private var prg:Progress_mc = new Progress_mc;
private var ship:Ship_mc = new Ship_mc;
Or I have to add them as children of Calculator and add Calculator on stage?
The other problem is that I can't just use setter and getter as static functions in Calculator because "width" property is a read-only and cannot be used in static function (error:?)
What is the best way to access those properties and manipulate them?
Thank you so much good people!
I'm assuming Calculator instance is sort of globally accessible. In that case, I think you have
public function setProgressMcWidth(width:Number):void {...}
in Calculator class. This function needs to be called whenever progressMc's width is updated. Later when calculator needs to pass some width to shipMc, it can dispatch an event such as
package {
public class CalculatorEvent extends Event {
private var _width:Number = width;
public function CalculatorEvent(type:String, width:Number)
{
super(type);
_width = width;
}
override public function clone():Event {
var ret:CalculatorEvent = new CalculatorEvent(type, _width);
return ret;
}
public function getWidth():Number {return _width;}
}
}
and have dispatch code in Calculator like:
dispatch(new CalculatorEvent("shipWidthCalculated", calculatedShipWidth));
Ship mc, in turn, would listen to calculator's event like:
calculator.addEventListener("shipWidthCalculated", handleShipWidthCalculated);
private function handleShipWidthCalculated(event:CalculatorEvent):void {
trace('calculator calculated my width to be: ' + event.getWidth);
}
But if the calculator instance isn't in the display list, it won't receive any events.

Library design quandary

Ok so I am writing an open source library. A section of this library deals with moving an entity in a two and three dimensional space so it will have functions that manipulate the rotation, position etc.
Now ideally I would like my library to work well with other libraries, in particular things like Papervision3D and other Flash 3D engines, but not forgotting basic image objects like a Sprite or Movieclip.
So this is my quandary. The functions that will manipulate the entity will also need to modify the values of the underlying model data (so either a Sprite, Papervision object etc). What is the best way to make my library flexible so that it can support multiple data models. Performance is also important aspect too.
Currently I am thinking of something like this:
//this is the public function that I expose in my library
public function rotate(val:Number,func:Function,objData:*):void
{
func(val,objData);
}
//example of a function that could be passed in
//this one will rotate a MovieClip
private function modelFunction1(rot:Number,objData:*):void
{
var myMov:MovieClip = objData as MovieClip;
myMov.rotation = rot;
}
//second example of a function that could be pass in
//this one will rotate a point
private function modelFunction2(rot:Number,objData:*):void
{
//yes I know this piece of code makes no sense :P
var p:Point = objData as Point;
p.x = Math.cos(rot);
p.y = Math.sin(rot);
}
so then it could be used like:
rotate(4,modelFunction2,myPoint)
//or
rotate(4,modelFunction1,mySprite);
I should add that in reality I, as the client code, won't be able to directly call the rotate function. Instead the rotate function that I want to pass in would need to be stored somewhere as a class member and then be called by the rotate function. Its just less code for me to write it out like above.
This to me seems quite flexible although the performance implications of casting and passing functions concerns me (but might be ok). Can anyone else suggest an alternative or is what I have the most logical solution. Thanks :)
I suggest the adapter pattern.
In your case you could define interfaces which offer type safe definitions for what your library expects instead of having function arguments.
then you need to write adapter classes which implement your librarys interfaces and wrap for instance a papervision object and delegate the function calls to your interface methods to the papervision object.
interface IRotatatable {
function rotate(deg : Number) : void
}
class YourLibraryClass {
public function rotate(r : IRotatatable, val : Number):void {
r.rotate(val)
}
}
class P3DAdapter implements IRotatable {
public function P3DAdapter(p3d : SomePaperVisionObject) {
_p3d = p3d;
}
public function rotate(r :Number):void {
p3d.rot = r;
}
}
function someClientCode():void {
var adapter : IRotatable = new P3DAdapter(p3d)
new SomeLibraryClass().rotate(adapter, val));
}