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++.
Related
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
So, I have successfully grabbed a value out of an XML document and set it into a separate class called "AddCommas." The trace functions have shown me that it sets properly.
For more details, my objective is to take the language indicator ("fr" for french or "en" for english), set it inside the appropriate class and into a variable I will use. Now, I am using this variable to be used in an if statement; which will help me format a number properly (commas, decimals, spaces) per the clients request.
However, my problem is when I try to get the value to use it. It always comes back as Null. I have placed traces all over my program trying to pinpoint when this happens, but I cannot find it. Here's the code...
The pull from the XML file and into the set (this works fine, but I am adding it for your benefit in case I missed something)
public var commaHold = new AddCommas();
localLanguage = xmlObj.localLanguage;
trace("localLanguage + " + localLanguage);
commaHold.setLanguage(localLanguage); // Set Language
//More code follows...
This is the set function istelf...
public function setLanguage(localLanguage:String){
langHold = localLanguage;
trace("Set Language = " + langHold); //This always shows a successful set
}
Now am I wrong in thinking that in AS3, once langHold in my AddCommas class has been set I should be able to use it without calling a get within the function I am using the If Statement in, right? Such as this?
var language = langHold;
if (language == "en"){
trace("Language is = " + language); // More code follows afterwards and as of now, this shows NULL
Now, I have attempted plenty of Get functions to add the language variable in the call itself to this function and it's always the same. Am I missing some fundamentals here?
Thank you very much for your time.
If you expect a string comparison you need to use quotes, unless en is a String variable since langHold is a String, like:
if (language == "en"){
Consider modifying the set function to use the as3 keyword like:
private var _language:String;
public function set language(value:String):void {
_language = value;
//do other stuff here if necessary, put a breakpoint on the line above
}
public function get language():String{
return _language;
//put a breakpoint on the line above
}
You should be able to see when any instance of your class has the property changed. The only other issue I can think of is it is not the same instance of the class and therefore doesn't share the property value you set earlier. In the debugger you can check the "hashCode" or "address" it shows for this to see if it changes when it hits the breakpoints.
Here's a sample Singleton structure in AS3 (this all goes in one file):
package com.shaunhusain.singletonExample
{
public class SingletonExample
{
private static var instance:SingletonExample;
public static function getIntance():SingletonExample
{
if( instance == null ) instance = new SingletonExample( new SingletonEnforcer() );
return instance;
}
/**
*
* #param se Blocks creation of new managers instead use static method getInstance
*/
public function SingletonExample(se:SingletonEnforcer)
{
}
}
}
internal class SingletonEnforcer {public function SingletonEnforcer(){}}
using this single shared instance from any other class would look something like this:
private var singletonInstance:SingletonExample = SingletonExample.getInstance();
ShaunHusain's theory of using a Singleton was the perfect solution I needed. However, his code gave me a bizarre 1061 error and my format and code appeared to be error free. Regardless, I looked up another way to use a Singleton as follows that worked perfectly for me. Honestly, Shaun's code should work for anyone and I have no idea why it wasn't. I am perfectly willing to admit that it was probably a typo on my end that I just did not see.
I ended up embedding the Set and Get within the Singletons class and used it as an intermediary to hold the information I needed. It worked perfectly.
package chart {
import chart.*;
//
public class StaticInstance {
private static var instance:StaticInstance;
private static var allowInstantiation:Boolean;
private var language:String;
public static function getInstance():StaticInstance {
if (instance == null) {
allowInstantiation = true;
instance = new StaticInstance();
allowInstantiation = false;
}
return instance;
}
public function StaticInstance():void {
if (!allowInstantiation) {
throw new Error("Error: Instantiation failed: Use StaticInsance.getInstance() instead of new.");
}
}
public function setLanguage(_language:String):void{
language = _language;
trace("language set = " + language);
}
public function getLanguage():String{
return language;
}
}
}
This code allowed me to hold the data and call upon it again from two different classes. It's a very hack job instead of just being able to pass on the variable from function to function, but in my case we didn't create this file, we are modifying it and attempting to do things beyond the original scope of the project.
Thanks again for your help Shaun! I hope this helps other people!
I am using a s:TextInput in Flex 4.5. It shows it's prompt text if the underlying text value is null or empty String. Does anybody know if I can make either don't show the prompt on empty String or even show a different prompt?
I already found a way by extending the TextInput class and overriding some of the methods but I am still hoping anyone here knows an easier way ;-)
Ok, so based on the comments, here it is:
You store the current prompt value in a private variable, like so:
private var _inputPrompt:String = "";
Then you create a getter, so the value is accessible from outside of this class:
public function get inputPrompt():String
{
return _inputPrompt;
}
Now you can bind inputPrompt anywhere you need it, however, the problem is the getter won't be recalled once the private value changes. You can fix this very easily: Create an update method, for example like so:
public function updateInputPrompt(value:String):void
{
_inputPrompt = value;
}
Ok, nothing fancy so far. I'm guessing this is the point where you are right now. In order to "force" the getter to be recalled, you have to bind it to an event, like so:
[Bindable(event="inputPromptUpdated")]
public function get inputPrompt():String
{
return _inputPrompt;
}
Finally, you can simply dispatch this event when the value is update (i.e. in the updateInputPrompt method):
public function updateInputPrompt(value:String):void
{
_inputPrompt = value;
dispatchEvent("inputPromptUpdated"); // For binding
}
This way, the getter will be recalled every time you dispatch that event.
Hope this helps. Have a great day, and a great weekend!
Firstly can some one please explain what is meant by Object and Function in a profiling environment.
Secondly, why does the Object and Function count increase when I repeatedly set the text property of a textfield:
override public function setLanguage(id:String):void
{
if (id == "en")
{
ui.title.text = _data.text.title.en;
ui.title.direction = Direction.LTR;
}
else if (id == "ae")
{
ui.title.text = _data.text.title.en;
ui.title.direction = Direction.RTL;
}
}
From Laurent:
Internally, TextField::text is most likely a getter/setter (since it needs to set a flag to update the text field display, also possibly update the HTML content, etc.) so when you set it you are effectively calling a function.
This means that TextField.text is implemented as a property getter and setter, so if you had to code it, you would see something like
private var _text:String="";
public function get text():String {
return _text;
}
public function set text(value:String):void {
_text=value;
}
Your Object count increases every time you reference (looking for a better word, don't kill me about this :P) an object (I trust you know what objects are), and your Function count increases every time you invoke a function.
So when you do something like
myTextField.text="Hello World";
you are referencing object myTextField and invoking its function set text(String);, causing your counts to increase by 1 each.
Internally, TextField::text is most likely a getter/setter (since it needs to set a flag to update the text field display, also possibly update the HTML content, etc.) so when you set it you are effectively calling a function.
What is it you don't understand about the difference between a Function and an Object? Could you be more specific?
i am using get and setters in my as3 code to edit values of an other class (because those variables are shared) i dont like to put stage.sharedVar.isScrabble in my code every time to change a variable so i used get/set functions
see below
private function get isScrabble(){return stage.sharedVar.isScrabble;}
private function set isScrabble(val){stage.sharedVar.isScrabble = val;}
private function get superGrid(){return stage.sharedVar.superGrid}
private function set superGrid(val){stage.sharedVar.superGrid = val;}
private function get gridSize(){return stage.sharedVar.gridSize}
private function set gridSize(val){stage.sharedVar.gridSize = val}
private function get blokDefaultWidth(){return stage.sharedVar.blokDefaultWidth}
private function set blokDefaultWidth(val){stage.sharedVar.blokDefaultWidth = val}
private function get blokDefaultHeight(){return stage.sharedVar.blokDefaultHeight}
private function set blokDefaultHeight(val){stage.sharedVar.blokDefaultHeight = val}
as you van see it has a lot of duplicate code every time the "return stage.sharedVar." and the "stage.sharedVar."+ the value + " = val" is constantly comming back.
i was wondering is there a other way of creating these get/sets?
something like?:
private function get variable1(){getValue("hisOwnFunctionName")}
private function set variable1(val){setValue("hisOwnFunctionName")}
and so on??
thanks,
Matthy
If I understand your question, you just want to get and set multiple properties on an Object. Depending on your situation you could try:
private function setProperty(name:Object,value:Object):void {
stage.sharedVar[name]=value;
}
private function getProperty(name:Object):Object {
return stage.sharedVar[name];
}
private function example():void {
setProperty("foo","bar");
trace(getProperty("foo")); //prints: bar
}
These functions will let you set and access the properties you want, and you wont have to keep changing the functions. It does mean that if you change superGrid to be something else, you can't just change the function, you have to change everywhere you use the get and setProperty. But it does mean that you don't have to keep writing new functions.
Hope this helps.
If you're in flex builder, download the web standard toolkit from http://download.eclipse.org/releases/galileo/ and use "snippets" to write these for you.
Otherwise, if you really need to do this within the program at run-time, you can make a wrapper proxy class to do all kinds of things: http://ltslashgt.com/2008/01/24/proxy-class-as3/