Kotlin syntax confusion: fun Foo.bar() = (...) - java

I'm confused on what the following line of code is supposed to be doing:
fun MyContext.req() = request as LaunchRequest
LaunchRequest is a Java class, and MyContext is a Kotlin data class. I've tried looking up examples of Kotlin code that use this syntax, but haven't found anything.
MyContext doesn't have a req() function, so is this just defining a new function for MyContext that returns a variable called "request" of type LaunchRequest?

It’s an extension function named req defined on the receiver MyContext. This technique is used to add new functions to existing classes without the use of inheritance. This concrete example req can be invoked on any object of MyContext.
If you have a reference of MyContext it may be used as follows:
val ctx: MyContext = ...
val req: LaunchRequest = ctx.req()
The as keyword is used to cast the variable request to LaunchRequest.
If the = in the function declaration also leads to confusion: it’s called function with expression body, which can be used to replace block bodies (enclosed in curly brackets) when the function contains a single expression like given in your code.

These are extension functions of Kotlin which help in improving a class's functionality without actually writing a lot of boilerplate code.The function could be also written as
fun MyContext.req(): LaunchRequest(){
return (request as LaunchRequest)
}
Another example of Extension function(to animate view)is:
fun View.animatePulsing() {
val animation = AnimatorSet()
....
....
animation.duration = 150
animation.start()
}
We can use this as:
txtView.animatePulsing()

Related

Java signature for Kotlin single-expression functions

I have several Kotlin methods I want to call from JNI.
With my current implementation, I have the following source on Kotlin side.
var eventLayer: EventInterface? = null
private fun onDisconnection(start: Boolean) {
eventLayer?.onDisconnection(start)
}
The method signature is "onDisconnection(Z)V" and everything's working fine.
For such a simple method, I was thinking of using a single-expression function. Something like.
var eventLayer: EventInterface? = null
private fun onDisconnection(start: Boolean) = eventLayer?.onDisconnection(start)
When running my application, I have a (not so expected!) NoSuchMethod exception, and I checked the method signature which changed to "onDisconnection(Z)Ljava/lang/Void;"
Anyone to explain me this slight difference? And is there a way to have the same "(Z)V" signature with the single-expression function?
Thank you!
VR
The return type of
private fun onDisconnection(start: Boolean) = eventLayer?.onDisconnection(start)
is whatever eventLayer?.onDisconnection returns. This at least includes null because that's what it returns when eventLayer is null.
If you care about the return type of this function, then you should probably declare it. Then you'll get a compiler error because null is not Unit.
I'm prett sure you could fix it like this:
private fun onDisconnection(start: Boolean) : Unit =
eventLayer?.onDisconnection(start) ?: Unit
... but it's pretty odd to use = with an expression that produces no value. You should probably just write it with braces.

Calling asynchronous kotlin method from java

I have a library written in kotlin which i want to use in my Java program, but i don't know how to call an asynchronous method correctly.
/*This is my asynchronous kotlin method from the library*/
fun getNames(callback: (List<String>) -> Unit) = ...
/*In Java i want to call this method*/
List<String> names = getNames(...);
What parameter do i have to pass into the function in Java?
IntelliJ says i need something like this: 'kotlin.jvm.functions.Function1<? super java.util.List<String>,kotlin.Unit>' But i don't know how to instantiate such a class.
Ok, first of all give it a look at this great response from Kirill Rakhman.
Now, the result given by a callback from a asynchronous operation will come from the parameter. In this case it'll be the (List<String>) at the fun getNames().
A simple usage of this function in JAVA (8+) can look like this :
getNames(
strings -> {
strings.forEach(System.out::println);
return Unit.INSTANCE;
}
);

How to use to #file:JvmName in anotations [duplicate]

I want to load a resource in a top level function using Class.getResourceAsStream().
Is there any way to get a reference to the class that the top level function will be compiled into so that I can write, for example
val myThing = readFromStream(MYCLASS.getResourceAsStream(...))
Another way I found is to declare a local class or an anonymous object inside a top level function and to get its enclosingClass:
val topLevelClass = object{}.javaClass.enclosingClass
Note: to work, this declaration should be placed on top level or inside a top-level function.
Then you can use the topLevelClass as a Class<out Any>:
fun main(args: Array<String>) {
println(topLevelClass) // class MyFileNameKt
}
With Java 7 you can get a reference to the current Java class from a top level function using
MethodHandles.lookup().lookupClass()
No, there is no syntax to reference that class. You can access it using Class.forName(). For example, if the file is called "Hello.kt" and is located in the package "demo", you can obtain the class by calling Class.forName("demo.HelloKt").
In the absence of a way to get a reference directly, I've fallen back on creating an anonymous object in the current package
val myThing = object: Any() {}.javaClass.getResourceAsStream(...)
As linters like detekt would flag anonymous classes as EmptyClassBlock you could also use something like
internal object Resources
fun resourceStream(name: String): InputStream {
return Resources.javaClass.getResourceAsStream(name)
}

How to pass nested scala object reference in Java?

There have been some questions answered on this before.
How can I pass a scala object reference around in Java
How can I use a Scala singleton object in Java?
But my problem is that I have nested scala objects, something like:
object Criteria {
object ActionCriteria {
case class Action (parameter: String) {
def this(parameter: String) = { this(paramerter) }
}
object Action {
def apply(parameter: String): Action = { apply(parameter) }
}
}
}
In java I then need to create a list of Actions. I have tried this... to no avail:
import Criteria.ActionCriteria.Action$
....
List<Criteria.ActionCriteria.Action$.MODULE$> actions = new ArrayList<>();
As well as a bunch of other combinations like adding $.MODULE$ with every object. Right now I am getting the following error:
error: cannot find symbol Criteria.ActionCriteria
List<Criteria$ActionCriteria$Action> actions = new ArrayList<>();
Seems to work fine. Found this with Scala REPL:
scala> classOf[Criteria.ActionCriteria.Action]
res1: Class[Criteria.ActionCriteria.Action] = class Criteria$ActionCriteria$Action
If you want the type of Action object, not case class (highly unlikely, but for the sake of completeness):
scala> Criteria.ActionCriteria.Action.getClass
res2: Class[_ <: Criteria.ActionCriteria.Action.type] = class Criteria$ActionCriteria$Action$
The difference is caused by Scala expecting Action to be a type in classOf[Action], so it returns the type corresponding to the case class. When you use Action in a context where a value is expected, it returns the singleton instance instead, so you can call standard Java method getClass to get the type of object Action.
In case you need other types:
Criteria$ cm = Criteria$.MODULE$;
Criteria.ActionCriteria$ cacm = Criteria.ActionCriteria$.MODULE$;
Criteria$ActionCriteria$Action$ cacam = Criteria$ActionCriteria$Action$.MODULE$;
Criteria$ActionCriteria$Action caca = new Criteria$ActionCriteria$Action("Foo");
Criteria.ActionCriteria$ is breaking the pattern here. Why? According to Iulian Dragos' comment under bug SI-2034 this is a special case:
since objects are "the equivalent of static" in the Java world, we
wanted to make it easier for Java code to use static inner classes.
When there's only one level of nesting, there's a guaranteed
companion: every top-level object gets a mirror class (if there isn't
one) that creates static forwarders to module methods (that's how one
can run a main method defined inside an object). Therefore, a
special case for one-level nesting: those classes use the flattened
name (without a $ suffix) as outer_name. So, Java code can say new Outer.Inner.
Summary
For every level of nesting other than first you replace . with $ in your class names
If the target type is also an object you add $ at the end
If you want an instance you add .MODULE$

Is it safe to define a method that has the same name as the class in scala?

I am trying to introduce Scala into my Android project, which uses Guice for DI. For Guide to work, I need to add the #Inject annotation to the constructor I would like Guice to use. In my case I created a Scala class and I need to use it in my Java code.
scala:
class scalaClass1(a: String) {
var myA = a
#Inject
def this() = { this("test") }
}
This looks alright, correct? But in another case the constructor does not have any parameters, so I tried
scala:
class scalaClass2() {
var myA: String = null
#Inject
def this() = { this() }
}
And I got an syntax error. Something like recursive definition. Then I tried this:
scala:
class scalaClass2() {
var myA: String = null
#Inject
def scalaClass2() = { this }
}
The code compiled and the app works well on my phone. I have no idea why. I browsed in google, but I could not find any definition/explanation about having a method that has the same name as the class. Why this works? Is there any better solution to my problem?
If you need to to apply #Inject to a constructor without parameters you can use this:
class scalaClass2 #Inject () {
// whatever
}
Note the mandatory empty parentheses. You need them to apply an annotation on the primary constructor. But in this particular case you don't even need #Inject; see below.
In your second example (when you define def this() = { this() }) you are getting an error because you can't define multiple constructors with the same signature, and that's exactly what you are doing - you define primary constructor without parameters and immediately you define secondary constructor, again without parameters.
And in the third example you're really defining a method named scalaClass2 which returns this. It is perfectly valid, but it is not a constructor. As far as I remember, Guice does not need #Inject annotation on parameterless constructor when it is the only constructor in the class, so you can inject scalaClass2 or ask it from Guice, who will create it for you. But you don't really need scalaClass2 method; Guice may call it as a part of method injection procedure but it won't do anything.
Firstly, according to convention class names should start with upper case and methods with lower. But if we would not follow them I would say it is not safe.
Consider having a companion object to the class with apply method defined.
class Person(val name: String, val age: Int)
object Person {
def apply(name: String, age: Int) = new Person(name, age) }
and then create a method with same name and list parameters:
def Person(lastName: String, score: Int): String = s"${lastName} got ${score} points in last game"
Now if you want to make use of object apply method you cannot do it in regular way:
Person("McKenzie", 1000)
will yield McKenzie got 1000 points in last game

Categories