I would like to get some help to understand a Kotlin code snippet about functional interface used in Http4k org.http4k.core package
typealias HttpHandler = (Request) -> Response
fun interface Filter : (HttpHandler) -> HttpHandler {
companion object
}
I don’t understand the Filter interface, especially the companion object part. A typical functional interface is like this
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
And you can create a lambda isEven
val isEven = IntPredicate { it % 2 == 0 }
According to this simple example, it looks like the interface Filter extends another interface (HttpHandler) -> HttpHandler? Then it defines a function signature companion object? Is this correct? What does the part companion object really mean?
Filter extends (HttpHandler) -> HttpHandler and the function type (HttpHandler) -> HttpHandler has a single abstract method (operator) - invoke - implicitly declared, like this:
operator fun invoke(HttpHandler): HttpHandler
So that is the function signature for the functional interface, not companion object.
companion object means what it has always meant - a companion object declaration. The companion object might seem empty, just from looking at the code you showed, and it makes one wonder what its purpose is. If you have removed the declaration, the functional interface would still have compiled, and can be used just like a functional interface representing the function type (HttpHandler) -> HttpHandler.
If you look further down the file, however, you'll see that there is (at least) one extension function declared on the companion object:
val Filter.Companion.NoOp: Filter get() = Filter { next -> { next(it) } }
This allows you to do val noOp = Filter.NoOp for example, so the companion object isn't that pointless.
Related
I'm building an ORM for use with jasync-sql in Kotlin and there's a fundamental problem that I can't solve. I think it boils down to:
How can one instantiate an instance of a class of type T, given a
non-reified type parameter T?
The well known Spring Data project manages this and you can see it in their CrudRepository<T, ID> interface that is parameterised with a type parameter T and exposes methods that return instances of type T. I've had a look through the source without much success but somewhere it must be able to instantiate a class of type T at runtime, despite the fact that T is being erased.
When I look at my own AbstractRepository<T> abstract class, I can't work out how to get a reference to the constructor of T as it requires accessing T::class.constructors which understandably fails unless T is a reified type. Given that one can only used reified types in the parameters of inline functions, I'm a bit lost as to how this can work?
On the JVM, runtime types of objects are erased, but generic types on classes aren't. So if you're working with concrete specializations, you can use reflection to retrieve the type parameter:
import java.lang.reflect.*
abstract class AbstractRepository<T>
#Suppress("UNCHECKED_CAST")
fun <T> Class<out AbstractRepository<T>>.repositoryType(): Class<T> =
generateSequence<Type>(this) {
(it as? Class<*> ?: (it as? ParameterizedType)?.rawType as? Class<*>)
?.genericSuperclass
}
.filterIsInstance<ParameterizedType>()
.first { it.rawType == AbstractRepository::class.java }
.actualTypeArguments
.single() as Class<T>
class IntRepository : AbstractRepository<Int>()
class StringRepository : AbstractRepository<String>()
interface Foo
class FooRepository : AbstractRepository<Foo>()
class Bar
class BarRepository : AbstractRepository<Bar>()
fun main() {
println(IntRepository::class.java.repositoryType())
println(StringRepository::class.java.repositoryType())
println(FooRepository::class.java.repositoryType())
println(BarRepository::class.java.repositoryType())
}
class java.lang.Integer
class java.lang.String
interface Foo
class Bar
In your own CrudRepository you can add a companion object with an inline fun which is responsible to instantiate your repository by passing to it the corresponding class.
class MyCrudRepository<T> protected constructor(
private val type: Class<T>,
) {
companion object {
inline fun <reified T : Any> of() = MyCrudRepository(T::class.java)
}
fun createTypeInstance() = type::class.createInstance()
}
I'm trying to create a Map that contains generic-parameterized types. For example:
abstract class Foo {
companion object {
val fooInjectors = HashMap<Class<T: Foo>, Injector<T: Foo>>()
}
}
The idea is to have fooInjectors (which would be static in Java or in a companion object in Kotlin) contain a cache of sub-classes of Foo and their corresponding Injector.
Unfortunately, I can't get this to compile. I'd very much appreciate it if someone would help me figure out the syntax for this!
As far as I know, you are trying to do something that is impossible in Kotlin. The companion object is a singleton and it doesn't make sense to generify a singleton as there will not be any further objects created hence generic types are irrelevant. So you can't generify the property you declared because it's in the companion object.
However, one way you could make this working is using a backing function. This backing function should annotate with declaration-site variance.
This simply means we tell the compiler that we only return a type T from the method (and don't consume). That allows us to use subtypes and the supertype of the T if required. This is called covariance.
You can look at the docs to understand it further - https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance
Here's what I meant.
interface Injector<T>
class InjectorImpl<T> : Injector<T>
abstract class Foo {
companion object {
val fooInjectors = createMap<Foo>()
private fun <T> createMap(): HashMap<Class<out T>, Injector<out T>> {
return HashMap()
}
}
}
class Bar: Foo()
object Runner {
#JvmStatic
fun main(args: Array<String>) {
Foo.fooInjectors[Bar::class.java] = InjectorImpl<Bar>()
Foo.fooInjectors[Foo::class.java] = InjectorImpl<Bar>()
}
}
coming across a sample with a class and a function and trying to understand the koltin syntax there,
what does this IMeta by dataItem do? looked at https://kotlinlang.org/docs/reference/classes.html#classes and dont see how to use by in the derived class
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
class DerivedStreamItem(private val dataItem: IMeta, private val dataType: String?) :
IMeta by dataItem {
override fun getType(): String = dataType ?: dataItem.getType()
fun getData(): DerivedData? = getDataItem()
private inline fun <reified T> getDataItem(): T? = if (dataItem is T) dataItem else null
}
for the reference, copied the related defines here:
interface IMeta {
fun getType() : String
fun getUUIDId() : String
fun getDataId(): String?
}
class DerivedData : IMeta {
override fun getType(): String {
return "" // stub
}
override fun getUUIDId(): String {
return "" // stub
}
override fun getDataId(): String? {
return "" // stub
}
}
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
There is some good documentation on reified type parameters, but I'll try to boil it down a bit.
The reified keyword in Kotlin is used to get around the fact that the JVM uses type erasure for generic. That means at runtime whenever you refer to a generic type, the JVM has no idea what the actual type is. It is a compile-time thing only. So that T in your example... the JVM has no idea what it means (without reification, which I'll explain).
You'll notice in your example that you are also using the inline keyword. That tells Kotlin that rather than call a function when you reference it, to just insert the body of the function inline. This can be more efficient in certain situations. So, if Kotlin is already going to be copying the body of our function at compile time, why not just copy the class that T represents as well? This is where reified is used. This tells Kotlin to refer to the actual concrete type of T, and only works with inline functions.
If you were to remove the reified keyword from your example, you would get an error: "Cannot check for instance of erased type: T". By reifying this, Kotlin knows what actual type T is, letting us do this comparison (and the resulting smart cast) safely.
(Since you are asking two questions, I'm going to answer them separately)
The by keyword in Kolin is used for delegation. There are two kinds of delegation:
1) Implementation by Delegation (sometimes called Class Delegation)
This allows you to implement an interface and delegate calls to that interface to a concrete object. This is helpful if you want to extend an interface but not implement every single part of it. For example, we can extend List by delegating to it, and allowing our caller to give us an implementation of List
class ExtendedList(someList: List) : List by someList {
// Override anything from List that you need
// All other calls that would resolve to the List interface are
// delegated to someList
}
2) Property Delegation
This allows you to do similar work, but with properties. My favorite example is lazy, which lets you lazily define a property. Nothing is created until you reference the property, and the result is cached for quicker access in the future.
From the Kotlin documentation:
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
I thought typealiases were the same as the original type, just a different name.
I figure typealiases have the same references as the original type.
typealias Celsius = Double
fun Double.Companion.foo() {} // Works
fun Celsius.Companion.foo() {} // Does not work
Here, Companion is accessible from Double but Celsius gives an unresolved reference error.
No, you can't access to the companion objects via typealias. One possible workaround to create one more typealias for concrete companion:
typealias CelsiusCompanion = Double.Companion
After that you can use it as following:
fun CelsiusCompanion.foo() {}
If you want to define an extension function, it is not possible as hluhovskyi already stated, but things are differently if you just want to invoke functions of a companion object.
There are two ways of accessing functions and properties within a companion object. You can either specify the access explicitely or implicitely. The implicit way works with a typealias the explicit one does not.
Consider this minimal example:
class ClassWithCompanion{
companion object {
fun sayHello() {
println("Hello")
}
}
}
typealias Alias = ClassWithCompanion
fun main(args: Array<String>) {
ClassWithCompanion.sayHello() // implicit
ClassWithCompanion.Companion.sayHello() // explicit
Alias.sayHello() // implicit (works)
Alias.Companion.test() // explicit (does not work)
}
The documentation for companion objects has the following example
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Here Factory is the name of the companion object. It then goes on to say:
The name of the companion object can be omitted, in which case the name Companion will be used:
However there is no example that I can see that uses the name of the companion object.
Since you can only have one companion object per class (otherwise you get a Only one companion object is allowed per class error) the name feels like some pretty useless syntactic sugar to me.
What can the name of the companion object actually be used for?
Why would one bother to use any name for it?
You can use the name of the companion like:
MyClass.create() // not via companion name
MyClass.Companion.create() // via default companion name
MyClass.Factory.create() // via companion name
The name is maybe not that important for Kotlin, because you can just access the method without knowing that there is a companion object (line one above). It is more like a personal style, if you want to make the access to such functions more explicit.
But for java interop it makes a difference, because you have to access the function via the companion name:
MyClass.Factory.create(); // with named companion
MyClass.Companion.create(); // with unnamed comanion
Well, companion objects in Kotlin are not just syntactic sugar. They are actually a type. They are able to do much more thing, and need not to be see as just replacement of static.
You can actually extend class or implement an interface. See an example below.
open class Super {
open fun sayHello() {
println("Hello")
}
}
class Some {
companion object Child : Super() {
override fun sayHello() {
super.sayHello()
println("Hello from companion object")
}
}
}
fun main() {
Some.Child.sayHello()
}
If you do not use an explicit name, the companions name is Companion, thus it can be omitted, like you already quoted.
Sometimes you may want to have an explicit name in your calls, which would be MyClass.Factory.create() in your example. For namespace reasons maybe.
I don't see a many reasons to name a companion object, either. Except if you care about Java interop with your Kotlin code. Then, you need to explicitly write the companions name.
Another reason you might care about the name is, when you define an extension function on it:
fun MyClass.Companion.ext() = "myext"
In this case, it can be clearer when it has a name like Factory, on which specific factory methods are added via extension.
However there is no example that I can see that uses the name of the companion object.
class Person(val name: String) { companion object Loader {
fun fromJSON(jsonText: String): Person = ... }
}
>>> person = Person.Loader.fromJSON("{name: 'Dmitry'}") >>> person.name
Dmitry
>>> person2 = Person.fromJSON("{name: 'Brent'}") >>> person2.name
Brent