Responder callback methods - actionscript-3

I need to create a Responder object, the constructor documentation says:
Parameters
result:Function — The function invoked if the call to the
server succeeds and returns a result.
status:Function (default = null) — The function invoked if the server returns an error.
What is the parameter of the status function? it says the signature is function(default = null), but it doesn't actually explain what is default.
What type is default?
What might it contain?

Here function(default = null) means that the default value for the second parameter is null rather than the signature if the status handler.
As for the signature of the status handler it depends on your client<->server protocol. For example look at the MessageResponder class that inherits the Responder that are used in the flex remoting. It has the strongly typing serialization of AMF directly to the IMessage:
public function MessageResponder(agent:MessageAgent, message:IMessage,
channel:Channel = null)
{
super(result, status);
...
}
...
final public function result(message:IMessage):void {...}
final public function status(message:IMessage):void {...}
In general you can pass the functions with the single Object argument:
public function status(message:Object):void {}
public function result(message:Object):void {}

Related

No match found for function signature when NullHandling set to INTERNAL

I'm trying to implement an user defined function for Apache Drill.
The function takes float arguments (decimals do not work) and they have to be nullable in order to return zeroes.
However, when I use NullHandling.Internal and set the parameters as nullable types, the function can be no longer invoked.
SELECT tetsting_udf(1.23,4.56);
VALIDATION ERROR: (...): No match found for function signature TESTING_UDF(<DECIMAL>, <DECIMAL>)
SELECT tetsting_udf(cast(1.23 as float), cast(4.56 as float));
VALIDATION ERROR: (...): No match found for function signature TESTING_UDF(<FLOAT>, <FLOAT>)
When Float8Holders and NullHandling.NULL_IF_NULL is used, both calls above are working.
What I'm doing wrong?
#FunctionTemplate(
name = "testing_udf",
scope = FunctionTemplate.FunctionScope.SIMPLE,
nulls = FunctionTemplate.NullHandling.INTERNAL
)
public class TestingFunction implements DrillSimpleFunc {
#Param
NullableFloat8Holder numberA;
#Param
NullableFloat8Holder numberB;
#Output
Float8Holder out;
public void setup() {
}
public void eval() {
// Whatever
}
}
For the case when FunctionTemplate.NullHandling.INTERNAL is specified, UDFs implementations with all combinations of nullability should be specified. For your case, you should specify UDFs which accepts (Float8Holder and Float8Holder), (NullableFloat8Holder and NullableFloat8Holder), (Float8Holder and NullableFloat8Holder), (NullableFloat8Holder and Float8Holder).

Is it not possible to get the arguments array from a static method?

I'm trying to get the reserved keyword arguments array from inside a static method and I'm getting this error:
1042: The this keyword can not be used in static methods. It can only
be used in instance methods, function closures, and global code.
Here is my code:
public static function doSomething(message:String, ...Arguments):void {
var object:Object = this.arguments.caller;
}
If I take the this keyword out then I get the following error:
1120: Access of undefined property arguments.
this is reserved to reference the current instance of a class which unfortunately doesn't exist inside a static function (since static function is not tied to an instance).
You could try using the new rest keyword if you want to pass in an unknown number of arguments:
ActionScript 3.0 includes a new ...(rest) keyword that is recommended instead of the arguments class.
However if you want it just to get the caller function:
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.
public function test() {
doSomething("Hello", arguments.callee);
}
public static function doSomething(message:String, caller:Function):void {
var object:Object = caller;
}
You could get the arguments of a static method. From the documentation:
Within a function's body, you can access its arguments object by using the local arguments variable.
You do not need the this keyword, this references to the Class instance instead to the function itself:
public static function doSomething():void {
return arguments;
}
Next you can access to the arguments calling the static method:
var arguments:Object = MyClass.doSomething();
trace( arguments.callee );
But remember, like #MartinKonecny said, in AS3 is better use the ...rest keyword or pass a function reference as an argument.
The arguments object is available in static functions but is not available when using the ...rest parameter.
Use of this parameter makes the arguments object unavailable. Although
the ... (rest) parameter gives you the same functionality as the
arguments array and arguments.length property, it does not provide
functionality similar to that provided by arguments.callee. Make sure
you do not need to use arguments.callee before using the ... (rest)
parameter.
Take out the ...rest parameter and the arguments object appears.
Also, the this keyword is not always necessary.
method.apply(this, args);
may throw an error in a static function but the parameter is optional so this also works:
method.apply(null, args);
More on the rest keyword.

AS3 variable declared as a null function

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().

Can I safely pass null to Function.apply in place of thisArg argument?

To make public API of SWF more reliable, I usually wrap callbacks in closure with try/catch block:
private function addCallback(functionName:String, closure:Function):void {
ExternalInterface.addCallback(functionName, wrapEventHandler(closure));
}
private function wrapEventHandler(closure:Function):Function {
var self:Main = this;
return function(...arguments):* {
try {
return closure.apply(self, arguments);
} catch (error:Error) {
// Print error report here
}
}
}
When exception occurs in 'closure', error report will be printed.
I noticed that it works fine even when using 'null' instead of 'self':
closure.apply(null, arguments);
Is it safe to use 'null' in this case?
Callback I register with ExternalInterface aren't static functions; they use Main's class fields.
It works just fine with null, NaN and self. I couldn't find any problems with using NaN/null.
Passing the this argument to apply() is optional, and the parameter default value is NaN.
Parameters
thisArg:* (default = NaN) — The object to which the function is
applied.
Likewise with, call():
You can pass the value null for the thisObject parameter to invoke a
function as a regular function and not as a method of an object.
For example, the following function invocations are equivalent:
Math.sin(Math.PI / 4)
Math.sin.call(null, Math.PI / 4)

calling super() from an actionscript constructor with varargs

If a constructor takes its parameters as a vararg (...) it seems to be impossible to create a subclass that will just pass on that vararg to the superclass.
There is a related question with fix for this same situation for normal functions: Wrapping a Vararg Method in ActionScipt but I cannot get that to work with a super call.
base class:
public class Bla
{
public function Bla(...rest)
{
trace(rest[0]); // trace the first parameter
}
}
subclass:
public class Blie extends Bla
{
public function Blie(...rest)
{
// this is not working, it will
// pass an array containing all
// parameters as the first parameters
super(rest);
}
}
if I now call
var b1 = new Bla('d', 'e');
var b2 = new Blie('a', 'b', 'c');
I get the output
d
a,b,c
And I want it to print out:
d
a
Aside from actually moving the handling of the parameters to the subclass or shifting it off to a separate initializer method, does anyone know how to get the super call right?
There's unfortunately no way to call the super constructor with ... args. If you remove the super() call, it will be called by the compiler (with no arguments). arguments is also not accessible from constructors.
If you can change the method signatures, you modify the arguments to accept an Array rather than ... args. Otherwise, as you mentioned, you could move it into an initializer method.
You may use a statement like this:
override public function doSomething(arg1:Object, ...args):void {
switch(args.length) {
case 0: super.doSomething(arg1); return;
case 1: super.doSomething(arg1, args[0]); return;
case 2: super.doSomething(arg1, args[0], args[1]); return;
}
}