AS3 arguments - actionscript-3

Why do you think the code below does not work?
What would you change/add to make it work?
Any help is appreciated..
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function, ...args):void
{
bb(f, args);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:Array = null;
function bb(f:Function, ...args):void
{
func = f;
argum = args;
exec();
}
function exec()
{
func.apply(null, argum);
}
I get an ArgumentError (Error #1063):
Argument count mismatch on test_fla::MainTimeline/TraceIt(). Expected 2, got 1.
..so, the passed parameter (argum) fails to provide all passed arguments..
..Please keep the function structure (traffic) intact.. I need a solution using the same functions in the same order.. I have to pass the args to a variable and use them in the exec() method above..
regards

Ok, here is the solution.. after breaking my head : )
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function=null, ...args):void
{
var newArgs:Array = args as Array;
newArgs.unshift(f);
bb.apply(null, newArgs);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:*;
function bb(f:Function=null, ...args):void
{
func = f;
argum = args as Array;
exec();
}
function exec():void
{
if (func == null) { return; }
func.apply(this, argum);
}
This way, you can pass arguments as variables to a different function and execute them..
Thanks to everyone taking the time to help...

When TraceIt() eventually gets called, it's being called with 1 Array parameter, not a String and int parameters.
You could change TraceIt() to:
function TraceIt(args:Array)
{
trace(args[0], args[1]);
}
Or you could change exec() to:
function exec()
{
func.apply(null, argum[0].toString().split(","));
}
...as it appears when you pass "test", 1, you end up with array whose first value is "test,1". This solution doesn't work beyond the trivial case, though.

Change your bb function to look like this:
function bb(f:Function, args:Array):void
{
func = f;
argum = args;
exec();
}
As you have it now, it accepts a variable number of arguments, but you are passing in an array(of the arguments) from aa.

Related

Referencing extra argument passed to function in JavaScript

I have a function that looks like this:
abc = function (func) {
let object = {};
return function() {
let arg = ???
if (*something*) {
object[arg] = func.apply(this, arg);
}
else {
return object[arg];
}
}
};
My problem is, how do I refer to arg if arg is an extra argument passed to abc?
Thank you!

Typescript infer return type from passed functions return type

I might be trying to achieve the impossible but here goes.
I want to define a function ( function A ) which will return the same type as a new function passed into the parameter of function A.
e.g.
export function test<T> ( arg:Function ):T {
return arg;
}
function a():string {
return 'a';
}
function b():number {
return 0;
}
let aVal:string = test(a);
let bVal:number = test(b);
Obviously this will allow me to strongly type my responses for some compile time errors.
Does anyone have any ideas or know if I'm just dreaming.
** Note: Code slapped together for demo **
Cheers
How about this?
function test<T>(arg: () => T): T {
return arg();
}
function a(): string {
return 'a';
}
function b(): number {
return 0;
}
let aVal: string = test(a);
let bVal: number = test(b);
Instead of using the Function interface we defined arg as a function that takes no arguments and returns something of type T. The actual type T then can be defined by the function that's passed in.

Can you override functions in AS3?

I am new to ActionScripting but I have done some Java. I was told they are kinda similar. I am coding my swf file with some AS3 integrated.
function init():void{
// do something
}
function init(var string:String):String{
// do something else
}
is this not allowed in AS? If not, is there another way of handling it besides?
Thanks in advance.
Yes, you can override functions. But the example you gave is not overriding - it's overloading. For overriding a function, you basically just create a function with the same signature and everything in a subclass and add the word "override" right before it.
You can't directly overload a function though. If you want a variable number of parameters, you have to use optional parameters instead. Like this:
function init(str:String = null):String
{
if (str == null)
{
// do one thing
return null;
}
else
{
// do another thing
return "someString";
}
}
And that's about the best you're going to be able to do in AS3. The inability to overload functions, at least strictly speaking, is a fairly common complaint and obvious shortcoming of the language.
Do you mean method overloading? Actionscript, sadly, does not support this.
To get around it, you can use default parameters, or just make your parameters a bit less constraining. This answer has some details on that.
You could try this:
function init(var string:String = "Default value"):String{
// do something
}
Actionscript does not support method overloading. However, based on the answer to this question you have other options.
If you just want to be able to accept any type, you can use * to
allow any type:
function someFunction( xx:*, yy:*, flag:Boolean = true )
{
if (xx is Number) {
...do stuff...
} else if (xx is String) {
...do stuff...
} else {
...do stuff...
}
}
If you have a large number of various parameters where order is
unimportant, use an options object:
function someFunction( options:Object )
{
if (options.foo) doFoo();
if (options.bar) doBar();
baz = options.baz || 15;
...etc...
}
If you have a variable number of parameters, you can use the ...
(rest) parameter:
function someFunction( ... args)
{
switch (args.length)
{
case 2:
arr = args[0];
someBool = args[1];
xx = arr[0];
yy = arr[1];
break;
case 3:
xx = args[0];
yy = args[1];
someBool = args[2];
break;
default:
throw ...whatever...
}
...do more stuff...
}
For cases where you need to call a common function to a number of
classes, you should specify the interface common to each class:
function foo( bar:IBazable, flag:Boolean )
{
...do stuff...
baz = bar.baz()
...do more stuff...
}

Utilities.jsonStringify and object methods

I haven't found a way yet to properly handle methods in objects when calling Utilities.jsonStringify(). Basically, I cannot use my object after I retrieve it from the CacheService and apply Utilities.jsonParse() to it.
Does anyone have a hint ?
Thanks in advance.
Marc
json does not include functions when stringifying/parsing. You have to use something homebrewn like:
function func2String(obj) {
var res={};
for (x in obj) {
var value=obj[x];
res[x]=(typeof(value)=='function')?value.toString():value;
}
return res;
}
function string2Func (obj) {
var res={};
for (x in obj) {
var value=obj[x];
if(typeof(value)!='string') {
res[x]=value;
}
else {
res[x]=(value.substring(0,9)=='\nfunction')?eval('('+value+')'):value;
}
}
return res;
}
usage:
var obj=string2Func (Utilities.jsonParse(q.diff));
var str=Utilities.jsonStringify(func2String(diff));
Of course the unpacked funcs lost all their closures.

Graniteds - ejb.Tide - Identity.hasRole() function - invalid arguments

I have this block of actionscript code which is executed when a login is appempted. I an trying to reload a set of roles for a the user. I've added a result handler to the hasRole() method
[Observer("loginAttempted")]
public function loginAttempted():void {
identity.isLoggedIn(isLoggedInResult);
trace(identity.loggedIn+" "+identity.username);
var perms:Array = Permission.constants;
var i:int
trace("Load permissions");
for(i=0;i<perms.length;i++)
{
var p:Permission = perms[i];
var res = identity.hasRole(p.name,permissionResult);
if(res == true)
{
p.allowed = res;
}
trace(i+" "+p.name +" "+p.allowed+" "+res);
}
}
private function permissionResult(event:TideResultEvent):void {
trace("permissionResult "+event.result);
}
but i keep getting this error. Based on the graniteds docs the function should only take a single argument.
[Fault] exception, information=ArgumentError: Error #1063:
Argument count mismatch on Main/permissionResult(). Expected 1, got 2.
at TideRoleResponder/result()[C:\workspace\graniteds\as3\framework\org\granite\tide\ejb\Identity.as:201]
at org.granite.tide::Tide/result()[C:\workspace\graniteds\as3\framework\org\granite\tide\Tide.as:1831]
at org.granite.tide.rpc::ComponentResponder/result()[C:\workspace\graniteds\as3\framework\org\granite\tide\rpc\ComponentResponder.as:65]
at mx.rpc::AsyncToken/http://www.adobe.com/2006/flex/mx/internal::applyResult()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AsyncToken.as:199]
at mx.rpc.events::ResultEvent/http://www.adobe.com/2006/flex/mx/internal::callTokenResponders()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\events\ResultEvent.as:172]
at mx.rpc::AbstractOperation/http://www.adobe.com/2006/flex/mx/internal::dispatchRpcEvent()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AbstractOperation.as:199]
at org.granite.tide.rpc::TideOperation/http://www.adobe.com/2006/flex/mx/internal::dispatchRpcEvent()[C:\workspace\graniteds\as3\framework\org\granite\tide\rpc\TideOperation.as:73]
at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::resultHandler()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AbstractInvoker.as:263]
at mx.rpc::Responder/result()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\Responder.as:46]
at mx.rpc::AsyncRequest/acknowledge()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\rpc\AsyncRequest.as:74]
at NetConnectionMessageResponder/resultHandler()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\messaging\channels\NetConnectionChannel.as:524]
at mx.messaging::MessageResponder/result()[C:\autobuild\3.5.0\frameworks\projects\rpc\src\mx\messaging\MessageResponder.as:199]
We are using the ifAnyGranted function on the identity to do something similar, and our result handler has 2 arguments: the TideResultEvent, and a String containing the role. Try changing the signature of the permissionResult function to:
private function permissionResult(event:TideResultEvent, role:String):void