In a inputTask I'm programmatically calling another inputTask, e.g. testOnly, with parameter string as follows:
val readParams = inputKey[Unit]("reads version")
readParams := {
... // here some Parser code
val a = "*OnlyThisClassPls*"
testOnly.toTask(a)
}
Unfortunately instead of result I get an exception Illegal dynamic reference. Why?
I think I solved my problem.
I created a method which converts testOnly inputTask to dynamic task (taskDyn) with parameter
def testOnlyWithDynamicParams(params: String) = Def.taskDyn {
(testOnly in Test).toTask(params)
}
I defined an dynamic input task (inputTaskDyn) which uses method to convert and evaluates value at the end
readParams := Def.inputTaskDyn {
... // here some Parser code
val paramsForTestOnly = " *OnlyThisClassPls*"
testOnlyWithDynamicParams(paramsForTestOnly)
}.evaluated
I'm not sure if it is a best way but it works for me. If you know the better solution please correct me.
Related
I am new to Kotlin and am still trying to learn it. I have been researching this problem for several hours now and still have not figured it out. I want to get an element from inside of a list by it's index. I figured out how to do this with a plain list, like so
val my_list = listOf(1,2,3)
println(my_list.get(0))
The above works, but when I try to do this with a list that is stored inside of a map
val my_list = mutableMapOf<String, Any>()
my_list["set1"] = listOf(1,2,3)
my_list["set2"] = listOf("A","B","C")
my_list["set3"] = listOf("d","e","f")
val sub_list = my_list["set1"]
println(sub_list.get(0))
I get the following error
Unresolved reference. None of the following candidates is applicable
because of receiver type mismatch: #InlineOnly public inline operator
fun <#OnlyInputTypes K, V> Map.get(key: Int): ???
defined in kotlin.collections #SinceKotlin public operator fun
MatchGroupCollection.get(name: String): MatchGroup? defined in
kotlin.text
Note: I primarily use Python, so that is what I am used to. The functionality from Python that I am trying to reproduce in Kotlin is having a dictionary of lists.
The problem is the type declaration of your map, it should be:
val my_list = mutableMapOf<String, List<Any>>()
Any doesn't have a get() method, so there's no way to invoke it.
Even when that problem is solved, you'll probably have to deal with nullability, though, as:
val sub_list = my_list["set1"]
Will return List<Any>?, which means that my_list might not have a value for the specified key. If that's the case, you'll have to do something like:
sub_list?.get(0)?.run { println(it) }
Which in turn, could also cause an exception if the sub_list is empty. That could be solved with something more like:
vsub_list?.firstOrNull()?.run { println(it) }
I have an existing task called myTask, whose implementation I don't control.
I want to redefine it in this way:
myTask := {
val x = prepare()
try
myTask.value
finally
cleanup(x)
}
As you probably know, this code wouldn't work, as we don't control when myTask.value is executed.
prepare can be called with Def.sequential(), and cleanup with the andFinally construct. The only problem is how cleanup can get the return value of prepare().
Def.sequential{
Def.task{
prepare()
},
myTask
}.andFinally(cleanup(???))
One workaround is to use global variables, but this is a dirty hack.
Any ideas?
Related doc
I've tried to use global variables, and it works ok, even though it isn't the most elegant way to implement it.
I have:
project/MyTasks.scala
build.sbt
snippet in MyTasks.scala:
object MyTasks {
var x = Option.empty[String]
def prepare(): String = ???
def cleanup(x: String): Unit = ???
}
snippet in build.sbt:
myTask := Def.sequential{
Def.task{
MyTasks.x = Some(MyTasks.prepare())
},
myTask
}.andFinally {
MyTasks.cleanup(MyTasks.x.get)
MyTasks.x = None
}.value
In this way, we can get the state from prepare, and bypass SBT limitations.
With this excerpt, I try to create a 2nd inputKey with some preapplied input coming from a setting:
val foo = inputKey[Unit]("....")
foo := { ... }
val foo2 = inputKey[Unit]("....")
foo2 := {
foo.partialInput(" "+name.value).evaluated
}
But I get the Illegal dynamic reference error, as the arguments of partialInput must be constant if I use evaluated.
What is the best way of solving this?
Similar questions, I've read before:
combining input task with dynamic task in sbt
SBT How to pass input from one inputTask to another inputTask
How to call inputTask from within another inputTask?
Using SBT 0.13.7.
Related documentation.
The technique shown in this example taken from the SBT reference documentation doesn't work:
lazy val run2 = inputKey[Unit]("Runs the main class twice: " +
"once with the project name and version as arguments"
"and once with command line arguments preceded by hard coded values.")
// The argument string for the first run task is ' <name> <version>'
lazy val firstInput: Initialize[String] =
Def.setting(s" ${name.value} ${version.value}")
// Make the first arguments to the second run task ' red blue'
lazy val secondInput: String = " red blue"
run2 := {
val one = (run in Compile).fullInput(firstInput.value).evaluated
val two = (run in Compile).partialInput(secondInput).evaluated
}
Can I retrieve a Method via reflection, somehow combine it with a target object, and return it as something that looks like a function in Scala (i.e. you can call it using parenthesis)? The argument list is variable. It doesn't have to be a "first-class" function (I've updated the question), just a syntactic-looking function call, e.g. f(args).
My attempt so far looks something like this (which technically is pseudo-code, just to avoid cluttering up the post with additional definitions):
class method_ref(o: AnyRef, m: java.lang.reflect.Method) {
def apply(args: Any*): some_return_type = {
var oa: Array[Object] = args.toArray.map { _.asInstanceOf[Object] }
println("calling: " + m.toString + " with: " + oa.length)
m.invoke(o, oa: _*) match {
case x: some_return_type => x;
case u => throw new Exception("unknown result" + u);
}
}
}
With the above I was able to get past the compiler errors, but now I have a run-time exception:
Caused by: java.lang.IllegalArgumentException: argument type mismatch
The example usage is something like:
var f = ... some expression returning method_ref ...;
...
var y = f(x) // looks like a function, doesn't it?
UPDATE
Changing the args:Any* to args:AnyRef* actually fixed my run-time problem, so the above approach (with the fix) works fine for what I was trying to accomplish. I think I ran into a more general issue with varargs here.
Sure. Here's some code I wrote that add an interface to a function. It's not exactly what you want, but I think it can be adapted with few changes. The most difficult change is on invoke, where you'll need to change the invoked method by the one obtained through reflection. Also, you'll have to take care that the received method you are processing is apply. Also, instead of f, you'd use the target object. It should probably look something like this:
def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]) = method match {
case m if /* m is apply */ => target.getClass().getMethod("name", /* parameter type */).invoke(target, args: _*)
case _ => /* ??? */
}
Anyway, here's the code:
import java.lang.reflect.{Proxy, InvocationHandler, Method}
class Handler[T, R](f: Function1[T, R])(implicit fm: Manifest[Function1[T, R]]) extends InvocationHandler {
def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]) = method.invoke(f, args: _*)
def withInterface[I](implicit m: Manifest[I]) = {
require(m <:< manifest[Function1[T, R]] && m.erasure.isInterface)
Proxy.newProxyInstance(m.erasure.getClassLoader(), Array(m.erasure), this).asInstanceOf[I]
}
}
object Handler {
def apply[T, R](f: Function1[T, R])(implicit fm: Manifest[Function1[T, R]]) = new Handler(f)
}
And use it like this:
trait CostFunction extends Function1[String, Int]
Handler { x: String => x.length } withInterface manifest[CostFunction]
The use of "manifest" there helps with syntax. You could write it like this:
Handler({ x: String => x.length }).withInterface[CostFunction] // or
Handler((_: String).length).withInterface[CostFunction]
One could also drop the manifest and use classOf instead with a few changes.
If you're not looking for a generic invoke that takes the method name--but rather, you want to capture a particular method on a particular object--and you don't want to get too deeply into manifests and such, I think the following is a decent solution:
class MethodFunc[T <: AnyRef](o: Object, m: reflect.Method, tc: Class[T]) {
def apply(oa: Any*): T = {
val result = m.invoke(o, oa.map(_.asInstanceOf[AnyRef]): _*)
if (result.getClass == tc) result.asInstanceOf[T]
else throw new IllegalArgumentException("Unexpected result " + result)
}
}
Let's see it in action:
val s = "Hi there, friend"
val m = s.getClass.getMethods.find(m => {
m.getName == "substring" && m.getParameterTypes.length == 2
}).get
val mf = new MethodFunc(s,m,classOf[String])
scala> mf(3,8)
res10: String = there
The tricky part is getting the correct type for the return value. Here it's left up to you to supply it. For example,if you supply classOf[CharSequence] it will fail because it's not the right class. (Manifests are better for this, but you did ask for simple...though I think "simple to use" is generally better than "simple to code the functionality".)
I ran across the following code in Ely Greenfield's SuperImage from his Book component - I understand loader.load() but what does the rest of do?
loader.load((newSource is URLRequest)? newSource:new URLRequest(newSource));
It looks like some kind of crazy inline if statement but still, I'm a little preplexed. And if it is an if statement - is this way better than a regular if statement?
? is called the 'ternary operator' and it's basic use is:
(expression) ? (evaluate to this if expression is true) : (evaluate to this otherwise);
In this case, if newSource is a URLRequest, loader.load will be passed newSource directly, otherwise it will be passed a new URLRequest built from newSource.
The ternary operator is frequently used as a more concise form of if statement as it allows ifs to be inlined. The corresponding code in this case would be:
if (newSource is URLRequest)
loader.load(newSource);
else
loader.load(new URLRequest(newSource));
Basically what it says is: if newsource is a type of URLRequest, then pass the newSource variable into the load method, if its not a type of URLReuqest, create a new URLRequest and pass that into the load method.
The basic syntax is: (condition) ? (code to execute if true) : (code to execute if false)
this is using the ternary ?: operator. the first part is the condition, between the ? and : is what to return if the condition is true. after the : is what to return if the condition is false.
a simpler example
String str = null;
int x = (str != null) ? str.length() : 0;
would be the same as
String str = null;
int x;
if (str != null)
x = str.length()
else
x = 0;
Basically what this means, as far as im aware of, is its asking wheter that variable newSource's class is String or URLRequest like workmad and jason explained. If its an URLRequest it will run loader.load(newSource:URLRequest). If its not an URLRequest it means automatically that it is a String (in other words the url). And in that case it will run loader.load(new URLrequest(newSource:String).
The complete code could look something like this:
function myFunction(newSource:Object):SomeClass {
var loader:URLLoader = new URLLoader();
loader.load((newSource is URLRequest)? newSource:new URLRequest(newSource));
}
Regards,
Filipe A.