AS3 : What is the context of 'this' in an anonymous function? - actionscript-3

In this example:
public function Roulette() {
new QuickLoad(url, function (o:*):void {trace(this);});
}
when QuickLoad instance does its stuff, it calls the anonymous function. One would think that this is Roulette. But no, it turns out to be the anonymous function's caller, which is QuickLoad.
This is weird to say the least, say how am I supposed to pass the "correct" this (i.e. Roulette instance) inside the anonymous function if I don't do it the normal way?

Just save the outer this instance under a different name so that it is preserved:
public function Roulette() {
var rouletteThis = this;
new QuickLoad(url, function (o:*):void {trace(rouletteThis);});
}

There is a way to call a function with an alternate this pointer, but since your function is called from within new QuickLoad(), you need to alter that call statement, and pass your this as Roulette into the constructor. Your new QuickLoad object is unaware of its surroundings, and even the caller of the constructor is unknown to it. Thus, you need to make it aware, pass a this pointer from Roulette() to QuickLoad(), AND call the function from QuickLoad with passing an alternate this pointer.
public function QuickLoad(url:String,caller:Object=null,callback:Function=null) {
// initialization code
if (callback!=null) {
if (caller!=null) callback.apply(caller,[o]);
else callback.apply(this,[o]);
}
}
...
public function Roulette() {
new QuickLoad(url, this, function (o:*):void {trace(this);});
}
Function::apply() manual.
You can also use call() method, if your argument array has fixed length. callback.call(caller,o);

Generally, in this context, this refers to an object. To quote a rather infamous acronym: INABIAF (It's not a bug, it's a feature), LOL. So, yes, the object instance QuickLoad that is calling the function is going to be what this looks at by default.
There is an exception I know of (out of many, I'm sure)...you can get anything...variable, function, object, whatever, via this["Name of Object"]. But that's an aside.
There ARE other workarounds, I'm sure, which may or may not be practical for your purposes. This is one way of passing a function, out of many, and it's the one I use the most.
Functions do not have instances. They're not objects. If you want to send a function as an argument to another function, you simply pass it, as follows in this rather weird example.
//This function accepts a function as an argument.
function bridgeOfQuestions(person:String, response:Function):void
{
if(person == "King Arthur")
{
response("What is the average airspeed velocity of an unladen swallow?");
}
else
{
response("What is your favorite color?");
}
}
//This is the function we're going to pass.
function askQuestion(question:String):void
{
trace(question);
}
//Here, we call bridgeOfQuestions and pass it the askQuestion function.
//NOTE: Leave off the parenthesis on the function being passed!
bridgeOfQuestions("Sir Lancelot", askQuestion);
bridgeOfQuestions("King Arthur", askQuestion);
EDIT: If it is just the name you're passing, a function is a function permanently. It doesn't change, unlike an object, and as I said, it doesn't have instances. Therefore, if you merely want to print out the name of the function, you'd only use trace("Roulette").

Related

How do i refer to a get function as an object

I'd like to reference a get function as a Function object rather than as the value that it returns.
Normally i would be able to simply refer to the function without parenthesizes like so:
private function getFoo():int {
return 0;
}
trace(getFoo); // traces function
But the whole point of get functions is that you can call the function without the parenthesizes, so i just get a return of 0 if i do this:
private function get foo():int {
return 0;
}
trace(foo); // traces 0
Is there be any way at all to grab a reference to the foo function object?
Your first example gets a reference to the function (as it traces Function).
There is no way to get a reference to a getter, as getters are not simple functions, but a representation of a (custom) property of that object. They are not meant to work as a standard ones and so they are not meant to be referenced.
I cannot imagine why would you want to get a reference to that getter? And also, getters are not meant to be used only because you can skip those two symbols ()..

How to compare NPVariant objects?

I am registering listeners from JS to NPAPI plugin.
In order not to register same listener multiple times I need a way to compare passed NPVariant object to those already in the list.
This is how I'm registering listeners from JS :
PluginObject.registerListener("event", listener);
and then in plugin source :
for (l=head; l!=NULL; l=l->next) {
// somehow compare the listeners
// l->listener holds NPVariant object
if (l->listener-> ??? == new_lle->listener-> ???)
{
found = 1;
DBG("listener is a duplicate, not adding.");
NPN_MemFree(new_lle->listener);
free(new_lle);
break;
}
}
when you're talking about a javascript function the NPVariant is just an NPObject.
typedef struct _NPVariant {
NPVariantType type;
union {
bool boolValue;
int32_t intValue;
double_t doubleValue;
NPString stringValue;
NPObject *objectValue;
} value;
} NPVariant;
compare the val.type and val.objectValue. This will usually work, but if it doesn't there isn't another way so you're still better off trying it. I guess one other possibility would be to create a javascript function to compare them, inject it with NPN_Evaluate and call it with the two objects.
I don't think you can rely on objectValue. For instance if you do the following:
foo={};
bar=foo;
x={};
x.f=foo; x.b=bar;
Now, if you call NPN_Enumerate and pass x as the NPObject, you get two identifiers. Calling GetProperty for each of these returns NPVariants, but the value of variant->value.objectValue will be different for each, and different again in subsequent calls to NPN_Enumerate.
taxilian: is there significant overhead in calling NPN_Invoke with the two NPObjects, just to test for equality? This also involves some calls to GetProperty and the creation of identifiers and calling the NPVARIANT macros to test the results, etc.. I am wondering just how much logic I should be injecting and evaluating in Javascript.. this code injection seems to come up as a solution again and again. Is it costly?

Function.call(someInstance,args) for methodes. Ignores first arg

In as3 there is a flexible way to change object instance, when calling it.
call or apply members of Function object can be called with specific first arg, and reference say us, that this first arg will be "this" pointer inside function. But i've found it wrong.
I'v write little test, listed below.
public class Test
{
private var name:String = "default";
public var test3:Function = test;
public var test2:Function = function()
{
trace(this.name);
}
public function Test(name:String)
{
this.name = name;
}
public function test():void
{
trace(this.name);
}
}
and tested it.
var tmp:Test = new Test("default");
tmp.test(); //out default
tmp.test.call(new Test("new")); //out default
tmp.test2(); //out default
tmp.test2.call(new Test("new2")); //out new2
tmp.test3(); //out default
tmp.test3.call(new Test("new3")); //out default
So, in anonymous function call we can get right output, but not in case of member function.
maybe it's becouse of ambiguous "this" pointer, that should reffer real object instance for correct work, maybe smth else. I dont now, and as3 reference didnt't describe smth about it.
Finally list of questions:
Why so? By me, it's very strange, and looks like undefined behaviour;
How i can achieve that functionality? How to deceive test function like anonymous one? Isn't it call methode target?
It isn't very important, but I'll be glad any good answer. Thanks!
P.S. sorry for my English.
//EDITED: added this statement to all "name" references. Nothing changes.
When invoking the [[Call]] property, the behavior is different for
different types of closures. A closure is an object that contains a
reference to a method, and the [[Call]] property acts differently
depending on whether it is a function, method, or class closure. A
function closure is one that is of a global method that isn't
associated with any instance of a class. A method closure contains an
instance method of a class, and will always remember its original
"this" value.
If the closure is a function closure, then the first argument passed
to [[Call]] is passed on to the method and gets used as the "this"
value. If the first argument is null or undefined, then the global
object will be used as the "this" value for the method.
If the closure is a method closure, then the first argument of
[[Call]] will be ignored, and the saved "this" value for the method
closure will be passed to the method as the first argument. A method
closure records what its original "this" value was and always uses
that instead of the first argument to [[Call]].
If the closure is a class closure, and there is 1 argument passed to
[[Call]] (in addition to the "this" argument), then the call is
treated as a type conversion, and the argument will be coerced to the
type represented by the closure.
http://learn.adobe.com/wiki/display/AVM2/2.4+Method+invocation+notes

ActionScript - Receiving Name of Calling Function or Constructor?

long shot: is it possible to get the name of a calling function or the constructor from the called function? is it possible to determine the previous function of the thread?
i would like to call some setter functions from my constructor and have my setter functions determine if it was the constructor that called them.
currently, i'm setting a boolean for this functionality, but perhaps there is another way?
public function Constructor(myNumber:Number)
{
this.myNumber = myNumber;
}
public function set myNumber(value:Number):void
{
myNumberProperty = value;
//if constructor called this, return;
//else do some other stuff;
}
Quote from liveDocs:
Unlike previous versions of ActionScript, ActionScript 3.0 has no arguments.caller property. To get a reference to the function that called the current function, you must pass a reference to that function as an argument. An example of this technique can be found in the example for arguments.callee.
It was in AS2.0... It unfortunately throws an error if done in AS3.0.
Technically, you should be able to do this by generating an error and getting its stack trace. The constructor will have to be on that stack trace.
try
{
throw new Error();
}
catch (e:Error)
{
// parse this for the constructor name
trace(e.getStackTrace());
}
That would be for detecting where a function call came from...
I would still go for your solution (setting the flag), as it's more oop and probably far faster in terms of performance.

Why can't I call super method from an in-place event handling function?

I have a overriden function in my class, that adds an event handler like so:
override public function hide():void {
...
tween.addEventListener(TweenEvent.MOTION_FINISH, function(evt:Event):void {
...
super.hide();
}, false, 0, true);
}
This does not work, Flash tells me: "1006: A super expression can be used only inside class instance methods." (it works if moved to a proper instance method).
So I would like to understand why can't I use call to super.hide(); from my in-place handler function?
I can refer to any instance variables and methods from there without problems, so I thought that that handler had access to proper context.
Please help me understand this.
it is, because this in an anonymous function points to [object global] ... have a go, and trace it ...
now an AS3 feature is, that you can access instance members from inside there, but that's a really strange feature ... this.myProp will not work, whereas myProp will ... this is some dark magic, that automatically creates a closure ... for some reason it works with instance members, but not with super ...
IMHO, you should not use anonymous functions anyway, only if it is for prototyping, or as parameters for Array methods as forEach, map, filter and the like ...
greetz
back2dos
I believe you can capture the method in a variable that gets stored in the anonymous method's closure. For instance:
override public function hide():void {
...
var f:Function=super.hide;
tween.addEventListener(TweenEvent.MOTION_FINISH, function(evt:Event):void {
...
f();
}, false, 0, true);
}
I can explain further if you are struggling with the concept of closure.