Idiomatic way to invoke methods through reflection in Kotlin - reflection

I have a piece of Kotlin code that is trying to reflectively invoke a method using Java's Reflection package:
val arguments = arrayOfNulls<Any>(numberOfParams)
// Populate arguments
try {
fooMethod.invoke(fooClass, arguments)
} catch (e: Exception) {
// Panic
}
It keeps failing with an IllegalArgumentException of "wrong number of parameters".
I did some reading on the issue and it seems the spread operator of the invoke() method refuses to unpack Array<Any> because it's not equivalent to Object[]. I could try to use a standard Object[] from Java, but it makes me wonder, is this the only way? Is it the best way? Is there some way I can do this with Kotlin's types?
What is the most idomatic way to achieve what I want in Kotlin?

You need to add the spread operator * to your call:
fooMethod.invoke(fooClass, *arguments)
Using arguments without prefixing it with * will cause a new array of length 1 containing arguments as its single element to be created and passed as args to invoke. Prefixing it with the spread operator causes the arguments array to be passed to invoke as args.
See Variable number of arguments (Varargs) - Functions - Kotlin Programming Language for more details.

Related

Why I cannot get exactly the same GString as was put to map in Groovy?

With the following snippet I cannot retrieve gString from a map:
def contents = "contents"
def gString = "$contents"
def map = [(gString): true]
assert map.size() == 1 // Passes
assert gString.hashCode() == map.keySet().first().hashCode() // Passes, same hash code
assert gString.is(map.keySet().first()) // Passes, exactly the same object
assert map[gString] // Fails
How is that possible?
What's interesting here is that map.get(map.keySet()[0]) works fine while map.get[map.keySet()[0]] does not.
Assertion message clearly shows that there's something wrong:
assert map[gString] // Fails
| ||
| |contents
| null
[contents:true]
It's not the same question as Why groovy does not see some values in dictionary?
First answer there suggests:
You're adding GString instances as keys in your map, then searching for them using String instances.
In this question I clearly add GString and try to retrieve GString.
Also neither Why are there different behaviors for the ways of addressing GString keys in maps? nor Groovy different results on using equals() and == on a GStringImpl have an answer for me. I do not mutate anything and I do not mix String with GString. Groovy documentation is not helpful as well.
tl;dr: You seem to have discovered a bug in Groovy's runtime argument overloading evaluation.
Answer:
map[gString] is evaluated as map.getAt(gString) at runtime straightforwardly via Groovy's operator overloading mechanism. So far, so good, but now is where everything starts to go awry. The Java LinkedHashMap class does not have a getAt method anywhere in it's type hierarchy, so Groovy must use dynamically associated mixin methods instead (Actually that statement is sort of reversed. Groovy uses mixin methods before using the declared methods in the class hierarchy.)
So, to make a long story short, Groovy resolves map.getAt(gString) to use the category method DefaultGroovyMethods.getAt(). Easy-peasy, right? Except that this method has a large number of different argument overloads, several of which might apply, especially when you take Groovy's default argument coercion into account.
Unfortunately, instead of choosing DefaultGroovyMethods.getAt(Map<K,V>,K), which would seem to be a perfect match, Groovy chooses DefaultGroovyMethods.getAt(Object,String), which coerces the GString key argument into a String. Since the actual key is in fact a GString, the method ultimately fails to find the value.
To me the real killer is that if the argument overload resolution is performed directly from code (instead of after the operator resolution and the category method selection), then Groovy makes the right overload choice! That is to say, if you replace this expression:
map[gString]
with this expression:
DefaultGroovyMethods.getAt(map,gString)
then the argument overloading is resolved correctly, and the correct value is found and returned.

QMetaObject::invokeMethod alternative with compile-time checking

Besides QMetaObject::invokeMethod is there any type-safe way of invoking a method/slot asynchronously (a.k.a queuing its execution in the GUI thread)?
The QMetaObject::invokeMethod doesn't have compile-time checking for function names. There is also an overhead in specifying the member function by a string since a lookup and string matching is performed for every call.
I wonder if there is anything similar to the new QObject::connect syntax for invoking a method that provides compile time checking.
One solution is using the signal-slot architecture, but this enforces wrapping each caller code in a QObject class to be able to emit that signal.
It is possible to use the QTimer::singleShot for this purpose
QTimer::singleShot(0, object, &Object::method...);
--
QTimer::singleShot(0, object, [object](){
object->method(arg1, arg2, ...);
});
Note: The thread in which QTimer::singleShot is invoked must have an QEventLoop.
Please see this https://doc.qt.io/qt-5/qmetaobject.html#invokeMethod-4
template <typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor function, FunctorReturnType *ret)
This is an overloaded function.
Invokes the function in the event loop of context using the connection type Qt::AutoConnection. function can be a functor or a pointer to a member function. Returns true if the function could be invoked. Returns false if there is no such member or the parameters did not match. The return value of the function call is placed in ret.
Note: This function is thread-safe.
This function was introduced in Qt 5.10.

need clarity implementing interface GridTask<T,R>

I need clarity in implementing reduce() and map() methods of GridTask,
How can we Pass arguments to these methods,
Map<? extends GridJob, GridNode>
map(List<GridNode> subgrid, T arg) throws GridException
R reduce(List<GridJobResult> results) throws GridException
Specifically, I need to know, how to pass/ invoke reduce method, or if it is invoked implicitly, then how and what arguments are passed to it.
The arguments are passed from GridProjection.execute(...) method.
Every time a GridJob completes, its result is passed to GridTask.result(...) method. The reduce() method is invoked whenever all results from GridJobs are received. You can also force to reduce sooner by returning REDUCE policy form GridTask.result(...) method.

Can I pass an array to a function using the ... rest* construction?

I'm making multiple similar calls with similar results to one remote object. Because these calls are so similar and very changeable, I've been keeping the name of the remote method in a config file, and when I need to make the call I use getOperation() on the remote object, and call send() on the operation object. However, the requirements have changed so that not all of the calls will have the same number of parameters.
Because send uses ..., will I be able to continue using the same formation and pass an array, or will send() treat that as passing one argument of type array?
The Operation class also has an "arguments" property that you can use. That way you can prefill it before calling send(). The send() method then requires not extra arguments.
var operation:Operation = Operation(remoteObject.getOperation(methodName));
operation.arguments = parameters;
var token:AsyncToken = operation.send();
var responder:Responder = new Responder(resultHandler, faultHandler);
token.addResponder(responder);
you can use the ...rest
that will give you an array with a bunch of objects. I would recommend tat you make the first item [0] always the ID. This ID should identify either the sender or the type of object being passed. you can easily do a switch/case for each type of item. You could also do a more sophisticated way of dealing with this, but this should work.

Actionscript - is it better to cast or create a new variable? Or does it matter at all?

I find that in my daily Flex/Flash work, I do this number a lot:
//Calling a function...
MyCustomObject(container.getChildAt(i)).mySpecialFunction();
The question is - is this the best way to do this? Should I do this:
//Calling a function
var tempItem:MyCustomObject = container.getChildAt(i) as MyCustomObject;
tempItem.mySpecialFunction();
It might be incidental but I'm just wondering if there is an "accepted" way or a preferred way to do this. The second option seems more readable but I wonder if it takes more of a performance hit to create a new variable. Or does it all come down to style and preference?
It's important to remember that there is a difference between explicit casting and using the as keyword. Casting throws an error when it fails, whereas the as keyword does not (it just returns null).
// a casting error
try {
var number:int = 666;
var urlreq:URLRequest = URLRequest( number );
} catch(e:TypeError) {
// TypeError: Error #1034: Type Coercion failed: cannot
// convert 666 to flash.net.URLRequest.
trace(e);
}
Whereas the as keyword fails silently:
var number:int = 666;
var urlreq:URLRequest = number as URLRequest;
trace(urlreq); // prints null to the debug pane
Personally, I bear these behaviours in mind when deciding method to use. Generally, I'd recommend casting explicitly, as you'll know exactly how/when a cast failed. Often, though, you might want to fail silently and continue.
It generally doesn't matter. Creating a var just creates a pointer to the object, so it's not using more memory or anything like that.
The second example is definitely more readable and debuggable and should thus be preferred.
The risk you run from creating temp vars is that you might delay or prevent garbage collection for that object. This generally isn't a problem when it's just a local var in a function; just keep scope in mind when you're creating vars and passing them around.
For in-depth on the subject, read Grant Skinner's series on resource management in AVM2:
http://www.gskinner.com/blog/archives/2006/06/as3_resource_ma.html
for the second example you might want to test for the nullity to avoid a NullPointerException when invoking "mySpecialFunction", e.g.
var tempItem:MyCustomObject = container.getChildAt(i) as MyCustomObject;
if ( tempItem )
{
tempItem.mySpecialFunction();
}
I usually prefer the second approach but you have to remember that you can only use the as operator for casting "Date" and "Array" types.

Resources