If I set up a function that accepts a callback:
function loadSomething(path:String, callback:Function):void;
And that callback should accept a given type, for example a String to represent some loaded information:
function onLoaded(response:String):void;
// Load some data into onLoaded.
loadSomething("test.php", onLoaded);
Is it possible to assess the function that will be used for callback and ensure that it has both a given amount of arguments and that the argument accepts the correct type? e.g.
function broken(arg:Sprite):void;
// This should throw an error.
loadSomething("test.php", broken);
I don't think you should bother doing this kind of check as it would create an uncessary overhead. You can simply throw the exception when you do the callback:
try {
doCallback(response);
} catch(e:*) {
trace('Incompatible callback');
}
If you really want to do the check, you might be able to do it using reflection. Just call describeType(callback) from flash.utils and parse the XML.
One simple thing you can do is to check the number of acceptable arguments by calling length property on method closure like:
function some ( val1 : int, val2 : int ) : void { return; }
trace(some.length); // traces 2
Other much more complex method maybe is to use AS3Commons bytecode library. You can experiment with dynamic proxies.
Related
I want to check that if a member function of a particular name exists on a object, if it does call the member function or make a reference of that member function.
Here I don't have type of the object, i.e. the object maybe does not implement any interface but has a member function cancel().
I used this method (reflection) to check if the member function exists, i.e. if (object::class.members.any { it.name == "cancel" }) and when this statement returns true I am sure that the method does exist but compiler is still unsure that the 'cancel' method exist in the object or not
fun canceller(object: Any): KFunction<Any>?
{
var canceller: KFunction<Any>? = null
// check if object has member function 'cancel'
if (object::class.members.any { it.name == "cancel" })
{
// make reference of that member function and return it
canceller = object::cancel //cancel is still not recognized as a member function and gives an error that "Unresolved reference: cancel"
// or just call it now
// object.cancel()
}
return canceller
}
I expect that canceller variable should be assigned to value.cancel(), but the compiler is unsure that cancel() function exist (with an error "Unresolved reference: cancel") in the object even after we supplied a check inside if statement
It's not meant to be used like this. Reflection is something you use if you don't know at compile time what you are dealing with at runtime. Some examples:
you need to use a type that's configured in some properties file (Class.forName("someTypeString").newInstance())
you have written an utility that extracts the contents of your object for debugging purposes
you need to access code that isn't really visible to you (private fields that you can't easily access, but you need to)
many more... but most of the time very special use-cases
Now what you have shown is a function reference (object::cancel). In order to use a function reference the compiler must know the type of object and the cancel-function must exist for that type. As object is of type Any and the if-condition is only relevant at runtime, the compiler does not know that there is a cancel-function available and therefore compilation fails.
Note that if you aren't doing anything special, you should rather check for a common type/interface. So for example, if your objects implement an interface Cancellable you could just change your code to something as follows:
fun canceller(object: Any): KFunction<Any>? {
var canceller: KFunction<Any>? = null
// check if object is of type Cancellable
if (object is Cancellable) {
// make reference of the Cancellable::cancel-function
canceller = object::cancel // smart-cast acting
// or you could also call it directly: object.cancel()
}
return canceller
}
or probably you could just spare that function altogether and end up with something like just:
val someObj : Cancellable = ...
// somewhere later:
someObj.cancel()
Reflection is rather expensive and if you aren't entirely sure what it is useful for, you should not use it.
If you really knew what you were doing... then ok... it's of course also possible to call that function via reflection and if you ask for the existance of a function via reflection you also have to call it via reflection:
object::class.members.first {
// note: I am using just the first function... if there are several, you need to check which one to use (parameter/type)
it.name == "cancel"
}
.call(object)
I think you can use reflections for this purpose.
myObject.javaClass.kotlin.members.any { it.name == "cancel" }
And the better way to express the idea of "object that has all the variables" is to define the interface and have all those object implemented
interface Achiever { val name: String }
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").
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?
I was trying to write some javascript function and realised that
function testFunction(input_1, input_2, input_3) {
alert("alert");
}
however when i call the function like this:
<input type="button" value="click" onclick="testFunction("1", "2")">
why will it still work even with just two parameters?
You can call a Javascript function with any number of parameters, regardless of the function's definition.
Any named parameters that weren't passed will be undefined.
Extra parameters can be accessed through the arguments array-like object.
It doesn't actually matter how many parameters you are providing. the function interprets them and creates the arguments object (which acts as an array of parameters).
Here's an example:
function sum(){
if(arguments.length === 0)
return 0;
if(arguments.length === 1)
return arguments[0];
return arguments[0] + sum.apply(this, [].slice.call(arguments, 1));
}
It's not the most efficient solution, but it provides a short peak at how functions can handle arguments.
Because javascript treats your parameters as an array; if you never go beyond the second item, it never notices an argument is missing.
Javascript does not support Method overloading hence method will be execute in order of their occurence irrelevant of arguments passed Because javascript has no type checking on arguments or required qty of arguments, you can just have one implementation of testFunction() that can adapt to what arguments were passed to it by checking the type, presence or quantity of arguments..
Because Parameters are optional
Some Reading:
http://www.tipstrs.com/tip/354/Using-optional-parameters-in-Javascript-functions
Javascript is a very dynamic language and will assume a value of "undefined" for any parameters not passed a value.
Try using the below code
var CVH = {
createFunction: function (validationFunction, extParamData, extParamData1) {
var originalFunction = validationFunction;
var extParam = extParamData;
var extParam1 = extParamData1;
return function (src, args) {
// Proxy the call...
return originalFunction(src, args, extParam, extParam1);
}
}
}
function testFunction(input_1, input_2, input_3) {
alert("alert");
}
and you can call this function as below
<input type="button" value="click" onclick="CVH.createFunction(testFunction('1', '2'),'3','4')">
The third parameter can be optional and will have a null undefined default value.
If you explicitly want to have a required parameter, you need to require it via code inside the function.
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.