AS3 variable declared as a null function - actionscript-3

I have encountered an AS3 function that is declared as a null variable, as in:
public var edgeWeights:Function = null;
I am not sure how to use this function to change null to another value (e.g., a number like 2 or 3). I thought something like cs.edgeWeights = 2 might work, but that creates a compile error, as does cs.edgeWeights(2);
I believe these are anonymous functions in AS3 and I did do some research on them, but could not find a resolution to this situation.

public var edgeWeights:Function = null;
This notation means declaring variable edgeWeights of type Function. In Actionscript Function is an object and can be set to null.
To use it you need to set this variable to some function. For example:
edgeWeights = function(a:int,b:int):int { return a+b } or edgeWeights = Math.sin.
What function you should set there depends on your particular case.

If you assume that the Class that declares edgeWeights is Widget:
protected var widget:Widget;
protected function createWidget():void {
widget = new Widget();
widget.edgeWeights = widgetCallback;
}
//signature would need to match what the Widget
//actually expects this callback to do
protected function widgetCallback():void {
trace('hi from widget callback');
}
Note that it's probably bad practice to have a public callback variable and not provide a default implementation, so if you have access to the source code, you should probably fix that.

Given any function:
public function someFunction()
{
...
}
You can create a "pointer" with this: this.edgeWeights = someFunction; (yes, without ())
Later you just use: this.edgeWeights(); and you'll be calling someFunction().

Related

Pass Variables As Reference AS3

I have a function which has arguments that will modify multiple variables that are global. And I want the arguments to be reference arguments, so they can modify multiple global variables with the same lines of code that are modifying the arguments.
example(psuedocode):
function random(a:number, b:number, c:number):void{
a = RNG(20);
b = RNG(25);
c = RNG(30);
}
there will be two different variables passed in through a, b and c, these are global, but a, b and c are not. The goal is to not have to have identical lines of code for both separate sets of variables to set the RNG numbers.
Edit: So I suppose more explanation is in order I will probably just try to research making a wrapper or other object to add all the variables to, but I just didn't know what type of object to make and how to make it. I admit I was just being a little bit lazy in a little bit too complex creative way.
I have two sets of global variables that I want to pass into this function and set them equal to the same range of RNG as the corresponding ones in each set. The way I'm trying to do this without repeating "a = RNG(20);" twice for each one is by passing the global variables into the function as arguments, but the arguments are the variables that are having the RNG set to them. The only way this can work is if the variables are passed to the function as reference so that setting the RNG to the arguments will change the global variables.
There are two types of data in AS3:
Plain data: Boolean, String, Number, int, uint — always passed as values.
Objects: Object, Array and literally everything else — always passed as a pointer/reference rather than through copy/clone.
There's no trick, like in C/C++ there is, to pass some plain variable as a pointer to let a method modify the original and only value.
That said, there are two ways around.
Solution №1: you can pass variables indirectly, in pairs like container → variable name.
function doIt(A:Object, a:String):void
{
A[a] = RNG(20);
}
Solution №2: devise a custom wrapper class to cross the border between plain and object data.
Implementation:
package
{
public class Oint
{
public var data:int;
// Class constructor.
public function Oint(value:int = 0)
{
data = value;
}
// There's always nice to have a interface methods,
// rather than member or getter/setter, because
// you can actually link to read/write methods.
public function read():int
{
return data;
}
public function write(value:int):void
{
data = value;
}
// With this you can use Oint variables in math expressions.
public function valueOf():Object
{
return data;
}
// With this you can trace Oint variables and see their values.
public function toString():String
{
return data.toString();
}
}
}
Usage:
function random(a:Oint, b:Oint, c:Oint):void
{
a.data = RNG(20);
b.data = RNG(25);
c.data = RNG(30);
}

Actionscript : Variable not found from another class' function

I tried doing
trace(classname.functionname.variablename);
//or
trace(classname.functionname().variablename);
Didn't work.. any idea, to get from the classname.as the variable, that's inside a function?
Btw i tried making the function static, still didn't work
Any idea?
There's no way, as those variables that are defined inside a function only live as long as the function is executed, and disappear once there's a return or end of function body. In order to get whatever value you want from a function, make a class variable outside the function, assign it the value you want within that function, and address it from elsewhere.
class test {
public static var foo:Number;
function bar():void {
// ... some code
foo=baz*2.54;
// ... more code
}
}
class elsewhere {
...
trace(test.foo);
...
}
the variables created inside a function are only available in the scope of that function.
if the variables are class member variables (declared public on a class);
public class x {
public var varName:String="";
}
you will be able to access them as
classInstanceRef.varName
needless to say you will need to instantiate from that class an instance.
Unless your variable is declared static on the class
public static varName:String="";
and in that case you can access it using
className.varName;

Bindable getter function of singleton instance never being called in a data binding expression

I have a singleton class that looks something roughly like this (only with more bindable public properties):
public class Session extends EventDispatcher
{
private var _Id:String;
private static const _instance:Session = new Session( SingletonLock );
private static const SESSID_CHANGED:String = 'SessionIdChanged';
public function Session( lock:Class ){
//SingletonLock is an empty class not available outside this file
if( lock != SingletonLock ){
throw new Error("Don't instantiate Session. Use Session.instance");
}
_Id = "";
}
public static function get instance():Session{
return _instance;
}
// Changes a blob object (from the server xml for sessions) to a session object
public function updateFromXMLObj(s:ObjectProxy):void
{
_instance.Id = s.Id;
}
[Bindable(event=SESSID_CHANGED)]
public function get Id():String{
return _Id;
}
public function set Id(new_id:String):void{
if(this._Id != new_id){
this._Id = new_id;
this.dispatchEvent(new Event(SESSID_CHANGED));
}
}
public function registerOnSessionChange(listener:Function):void{
addEventListener(SESSID_CHANGED,listener);
}
public function unregisterOnSessionChange(listener:Function):void{
removeEventListener(SESSID_CHANGED,listener);
}
}
The idea is that in some mxml code, I have a databinding expression like the following:
<mx:HTTPService id="homeReq" url="{URLs.homepath(Session.instance.Id)}" ... />
where I want the url for homeReq to be updated when the sessionId changes. In addition, other parts of the code (written in Actionscript) need to be able to register their listeners for when the sessionId changes, so they call registerOnSessionChange and unregisterOnSessionChange to manage those listeners.
The abnormal behavior I'm discovering is that the event listeners registered through registerOnSessionChange are indeed being called when the session Id changes, but the MXML data binding expression is not updating. I've tried all combinations of dispatching the event during the capture phase, and making it not cancelable, but to no avail. My understanding of [Bindable (event= ...)] is that the MXML should update the url string when the event specified is dispatched, so what am I doing wrong or misunderstanding?
Note: I realize there are lots of different ways of doing the singleton pattern in Actionscript, but unless the way I am doing it is actually causing my problem somehow, I'd appreciate not getting sidetracked by discussing alternatives.
I think that {URLs.homepath(Session.instance.Id)} this is not binding to a variable instead is executing a method of an object, have you tried to do something like this:
[Bindable]
private var _url:*
Then setting the initial value to _url at init or complete:
_url = {URLs.homepath(Session.instance.Id)};
Linking to the binded variable in the MXML
<mx:HTTPService id="homeReq" url="{_url}" ... />
Then updating the _url variable should automatically update the HTTPService url...
Make an MXML form containing a combobox for course number of 5th semester. On selecting the coruse, display the course name and max marks for the selected course.
Data Binding: <mx:Binding>

Pass arguments to "new" operator through an array in ActionScript 3

How can I achieve the following for any number of elements in the arg array? If it was a function, I'd use Function.apply(), but I can't figure out how to do it with the new operator.
var arg:Array = [1,2];
new MyClass( arg[0], arg[1] );
If you set up your class to accept a list of arguments using ... args you can pass in as many as you like. Then in the constructor you will access them just like a normal array.
class MyClass
{
public function MyClass(... args):void
{
//args is an Array containing all the properties sent to the constructor
trace(args.length);
}
}
Dont pass each element of the array, just pass the array.
var arg:Array = [1,2];
new MyClass(arg);
Then inside of your class, loop through the array.
It is unfortunately not possible, because there is no way to directly access the constructor method of a Class object.
Note: If you'd be using a Function object to make up your class (prototype inheritance), then it would be possible, but i figure, this is not an option for you.
You could work around the problem with a little (ugly) helper method, on which you can read about here: http://jacksondunstan.com/articles/398
As stated in the comments is is not possible to apply settings on the constructor, but you could use this trick to set properties on a new instance of a class (which should be public)
public function setProps(o:Object, props:Object):* {
for (var n:String in props) {
o[n] = props[n];
}
return o;
}
.. use it like this
var args:Object = {x:1, y:2};
var instance:MyClass = setProps( new MyClass(), args ) );
source:
http://gskinner.com/blog/archives/2010/05/quick_way_to_se.html

Default caller value for AS3 method

Is there a way of setting the default value of a method scope parameter to be the caller?
In AS3 you can set default values for method parameters like so:
function myFuntion(param1:String="hello",param2:int=3) {
And you can pass a reference to an object by saying:
//method of Class1
function myFuntion(obj:Object) { } //do something with obj
//in Class2
var class1:Class1 = new Class1();
class1.myFunction(this);
So the question, is there a keyword that can be used like:
//method of Class1
function myFuntion(obj:Object = CALLER) { } //do something with obj
//in Class2
var class1:Class1 = new Class1();
class1.myFunction();
The only default function parameter value that is accepted for the type Object is 'null'.
function myFunction(obj:Object = null):void {};
var class1:Class1 = new Class1();
class1.myFunction();
No, there isn't a way to what you ask, and that is a good thing for encapsulation and code readability. You should be forced to deliberately pass this so that it is clear to anyone reading Class2.as what your function is being given references to.
In general, you should ask yourself "why?" anytime you have a function parameter of type Object (that's pretty general!). I'm not saying there is never a good reason for it--for error reporting purposes, for example--but all too often it's the sign of poor OOP design (e.g. using an Object because you're too lazy to make a proper data structure class for what you're passing, or to circumvent typechecking)