I was looking into co- and contravariance in several programming languages' collection libraries, and stumbled over Kotlin's Set interface.
It is documented as
interface Set<out E> : Collection<E>
which means it is covariant – only "producing" E objects, following the Kotlin documentation, not consuming them.
And Set<String> becomes a subtype of Set<Any>.
Yet, it has those two methods:
abstract fun contains(element: E): Boolean
abstract fun containsAll(elements: Collection<E>): Boolean
So when I create a class implementing Set<String>, I have to implement (beside others) contains(String). But later someone can use my class as a Set<Any> and call set.contains(5).
I actually tried this:
class StringSet : Set<String> {
override val size = 2
override fun contains(element: String): Boolean {
println("--- StringSet.contains($element)")
return element == "Hallo" || element == "World"
}
override fun containsAll(elements: Collection<String>) : Boolean =
elements.all({it -> contains(it)})
override fun isEmpty() = false
override fun iterator() = listOf("Hallo", "World").iterator()
}
fun main() {
val sset : Set<String> = StringSet()
println(sset.contains("Hallo"))
println(sset.contains("xxx"))
//// compiler error:
// println(set.contains(5))
val aset : Set<Any> = sset
println(aset.contains("Hallo"))
println(aset.contains("xxx"))
// this compiles (and returns false), but the method is not actually called
println(aset.contains(5))
}
(Run online)
So it turns out that Set<String> is not a "real" subtype of Set<Any>, as the set.contains(5) works with the second but not the first.
Actually calling the contains method even works at runtime – just my implementation will never be called, and it just prints false.
Looking into the source code of the interface, it turns out that the two methods are actually declared as
abstract fun contains(element: #UnsafeVariance E): Boolean
abstract fun containsAll(elements: Collection<#UnsafeVariance E>): Boolean
What is going on here?
Is there some special compiler magic for Set?
Why is this not documented anywhere?
Declaration-site covariance in the form of the out modifier misses a useful use case of making sure that an instance passed as an argument is generally sensible to pass here. The contains functions are a good example.
In the particular case of Set.contains, the #UnsafeVariance annotation is used to ensure that the function accepts an instance of E, as passing an element that is not E into contains makes no sense – all proper implementation of Set will always return false. The implementations of Set are not supposed to store the element passed to contains and thus should never return it from any other function with the return type E. So a properly implemented Set won't violate the variance restrictions at runtime.
The #UnsafeVariance annotation actually suppresses the compiler variance conflicts, like using an out-projected type parameter in an in-position.
Its motiviation is best described in this blog post:
#UnsafeVariance annotation
Sometimes we need to suppress declaration-site variance checks in our classes. For example, to make Set.contains typesafe while keeping read-only sets co-variant, we had to do it:
interface Set<out E> : Collection<E> {
fun contains(element: #UnsafeVariance E): Boolean
}
This puts some responsibility on the implementor of contains, because with this check suppressed the actual type of element may be anything at all at runtime, but it’s sometimes necessary to achieve convenient signatures. See more on the type-safety of collections below.
So, we introduced the #UnsafeVariance annotation on types for this purpose. It’s been deliberately made long and stands out to warn agains abusing it.
The rest of the blog post also explicitly mentions that the signature of contains using #UnsafeVariance improves type-safety.
The alternative to introducing #UnsafeVariance was to keep contains accepting Any, but this option lacks the type check on contains calls that would detect erroneous calls with elements that can't be present in the set due to not being instances of E.
Related
I just cannot override hashCode() function on value class.
minimal example (I know that in this example there is no need to override it...)
#JvmInline
value class Identifier(val value: String){
override fun hashCode(): Int = this.value.hashCode()
}
I get error: Member with the name 'hashCode' is reserved for future releases
Edit: Is there any way to specify own hashCode() function?
As of right now, you cannot override the equals or hashCode method of value classes. The language specification explicitly disallows this:
Value classes must adhere to the following limitations:
[...]
They must not override equals and hashCode member functions of kotlin.Any
[...]
This is because the developers of Kotlin are planning to add a strongly typed equals method that you can override.
From the inline classes proposal:
Methods from Any (toString, hashCode, equals) can be useful for a user-defined inline classes and therefore should be customizable. Methods toString and hashCode can be overridden as usual methods from Any. For method equals we're going to introduce new operator that represents "typed" equals to avoid boxing for inline classes:
#JvmInline
value class Identifier(val value: String){
override fun hashCode(): Int = ...
operator fun equals(other: Identifier): Boolean = ...
}
This is so that when you use == on value classes with a custom equals, you don't have to box them every time as you are passing it to the Any? parameter on the Any.equals method. The compiler would also automatically generate an equals(Any?) implementation from your equals(Identifier) implementation.
But they haven't implemented this feature yet. This is why they don't let you implement hashCode - because if you do, you would most likely also need to implement equals(Any?) (it is rarely useful/correct to just implement hashCode), but that means your code would break in future versions of Kotlin! In future versions, you would need to implement equals(Identifier), not equals(Any?).
So you can only wait until this feature gets added. Until then, you cannot have hashCode and equals that does not delegate to the wrapped value.
I'm exploring the Substitution principal and from what I've understood about the principal is that a sub type of any super type should be passable into a function/class. Using this idea in a new section of code that I'm writing, I wanted to implement a abstract interface for a Filter like so
interface Filter {
fun filter(): Boolean
}
I would then imagine that this creates the contract for all classes that inherit this interface that they must implement the function filter and return a boolean output. Now my interpretation of this is that the input doesn't need to be specified. I would like it that way as I want a filter interface that guarantee the implementation of a filter method with a guarantee of a return type boolean. Does this concept even exists in Kotlin? I would then expect to implement this interface like so
class LocationFilter {
companion object : Filter {
override fun filter(coord1: Coordinate, coord2: Coordinate): Boolean {
TODO("Some business logic here")
}
}
}
But in reality this doesn't work. I could remove remove the filter method from the interface but that just defeats the point of the whole exercise. I have tried using varargs but again that's not resolving the issue as each override must implement varargs which is just not helpful. I know this may seem redundant, but is there a possibility to have the type of abstraction that I'm asking for? Or am I missing a point of an Interface?
Let's think about it a little. The main point of abstraction is that we can use Filter no matter what is the implementation. We don't need to know implementations, we only need to know interfaces. But how could we use Filter if we don't know what data has to be provided to filter? We would need to use LocationFilter directly which also defeats the point of creating an interface.
Your problem isn't really related to Kotlin, but to OOP in general. In most languages it is solved by generics/templates/parameterized types. It means that an interface/class is parameterized by another type. You use it in Kotlin like this:
interface Filter<in T> {
fun filter(value: T): Boolean
}
object LocationFilter : Filter<Coordinate> {
override fun filter(value: Coordinate): Boolean {
TODO()
}
}
fun acquireCoordinateFilter(): Filter<Coordinate> = LocationFilter
fun main() {
val coord: Coordinate = TODO()
val filter: Filter<Coordinate> = acquireCoordinateFilter()
val result = filter.filter(coord)
}
Filter is parameterized, meaning that we can have a filter for filtering strings (type is: Filter<String>), for filtering integers (Filter<Int>) or for filtering coordinates (Filter<Coordinate>). Then we can't use e.g. Filter<String> to filter integers.
Note that the code in main() does not use LocationFilter directly, it only knows how to acquire Filter<Coordinate>, but the specific implementation is abstracted from it.
Also note there is already a very similar interface in Java stdlib. It is called Predicate.
my interpretation of this is that the input doesn't need to be specified.
Where did you get that interpretation from?
You can see that it can't be correct, by looking at how the method would be called. You should be able to write code that works for any instance of Filter — and that can only happen if the number and type of argument(s) is specified in the interface. To use your example:
val f: Filter = someMethodReturningAFilterInstance()
val result = f.filter(coord1, coord2)
could only work if all implementations used two Coordinate parameters. If some used one String param, and others used nothing at all, then how would you call it safely?
There are a few workarounds you could use.
If every implementation takes the same number of parameters, then you could make the interface generic, with type parameter(s), e.g.:
interface Filter<T1, T2> {
fun filter(t1: T1, t2: T2): Boolean
}
Then it's up to the implementation to specify which types are needed. However, the calling code either needs to know the types of the particular implementation, or needs to be generic itself, or the interface needs to provide type bounds with in variance.
Or if you need a variable number of parameters, you could bundle them up into a single object and pass that. However, you'd probably need an interface for that type, in order to handle the different numbers and types of parameters, and/or make that type a type parameter on Filter — all of which smells pretty bad.
Ultimately, I suspect you need to think about how your interface is going to be used, and in particular how its method is going to be called. If you're only ever going to call it when the caller knows the implementation type, then there's probably no point trying to specify that method in the interface (and maybe no point having the interface at all). Or if you'll want to handle Filter instances without knowing their concrete type, then look at how you'll want to make those calls.
The whole this is wrong!
First, OOP is a declarative concept, but in your example the type Filter is just a procedure wrapped in an object. And this is completely wrong.
Why do you need this type Filter? I assume you need to get a collection filtered, so why not create a new object that accepts an existing collection and represents it filtered.
class Filtered<T>(private val origin: Iterable<T>) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then in your code, anywhere you can pass an Iterable and you want it to be filtered, you simply wrap this original iterable (any List, Array or Collection) with the class Filtered like so
acceptCollection(Filtered(listOf(1, 2, 3, 4)))
You can also pass a second argument into the Filtered and call it, for example, predicate, which is a lambda that accepts an element of the iterable and returns Boolean.
class Filtered<T>(private val origin: Iterable<T>, private val predicate: (T) -> Boolean) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then use it like:
val oddOnly = Filtered(
listOf(1, 2, 3, 4),
{ it % 2 == 1 }
)
I'm working with a Java API now converted into multiplatform Kotlin. It used to use java.lang.Optional as the return type of many calls. I understand this is not the idiomatic Kotlin-way (see discussion) but this is an existing API, Optional stays (also it isn't a bad choice for the Java-facing client). My question is how?
Note: The code only needs to return Optional.of(x) or return Optional.empty() to the external API. Any internal uses will be purged.
How do we use expect/actual/typealias to use the real Optional class when available?
Is there a way to avoid re-implementing a fake Optional class on non-Java targets (i.e. work idiomatically with nullable? suffix)
At this point, Kotlin doesn't allow providing an actual typealias for an expected class with a companion object by using a Java class with matching static declarations. Follow this issue for updates: KT-29882.
For now, you can workaround that by declaring the factory functions separately, outside the expected Optional class, as follows:
expect class Optional<T : Any> {
fun get(): T
fun isPresent(): Boolean
/* ... */
}
expect object Optionals {
fun <T : Any> of(t: T): Optional<T>
fun empty(): Optional<Nothing>
}
That should not necessarily be an object, you could just use top-level functions.
Then, on the JVM, you would have to provide an actual typealias for the Optional class and, additionally, provide the trivial actual implementation for the Optionals object:
actual typealias Optional<T> = java.util.Optional<T>
actual object Optionals {
actual fun <T : Any> of(t: T): Optional<T> = java.util.Optional.of(t)
actual fun empty(): Optional<Nothing> = java.util.Optional.empty()
}
As for not providing an implementation for the non-JVM platforms, I doubt it's possible, as that would require some non-trivial compile-time transformations of the Optional usages to just the nullable type. So you would want something like this:
actual typealias Optional<T> = T?
which is now an error:
Type alias expands to T?, which is not a class, an interface, or an object
So you actually need a non-JVM implementation. To avoid duplicating it for every non-JVM target, you can declare a custom source set and link it with the platform-specific source sets, so they get the implementation from there:
build.gradle.kts
kotlin {
/* targets declarations omitted */
sourceSets {
/* ... */
val nonJvmOptional by creating {
dependsOn(getByName("commonMain"))
}
configure(listOf(js(), linuxX64())) { // these are my two non-JVM targets
compilations["main"].defaultSourceSet.dependsOn(nonJvmOptional)
}
}
}
Then, inside this custom source set (e.g. in src/nonJvmOptional/kotlin/OptionalImpl.kt) you can provide an actual implementation for the non-JVM targets.
Here's a minimal project example on Github where I experimented with the above: h0tk3y/mpp-optional-demo
Kotlin has three types that are very similar in nature:
Void
Unit
Nothing
It almost seems like they're making the JavaScript mistake:
null
undefined
void(0)
Assuming that they haven't fallen into the same mistake, what are they all for, and how do they differ?
The Void type is from Java. You generally won't use this from Kotlin unless you're using some Java-library that uses it.
The Unit type is what you return from a function that doesn't return anything of interest. Such a function is usually performing some kind of side effect. The unit type has only one possible value, which is the Unit object. You use Unit as a return type in Kotlin when you would use void (lowercase v) in Java.
The Nothing type has no values. If a function has return type Nothing, then it cannot return normally. It either has to throw an exception, or enter an infinite loop. Code that follows a call to a function with return type Nothing will be marked as unreachable by the Kotlin compiler.
Because Nothing has no values, Nothing? is actually the type that captures only the null value in Kotlin.
Unit
Unit is like void
In Kotlin, when a function does not return any meaningful value, it is declared to return Unit, just like void in Java:
fun greet(): Unit { println("Good day!") }
It's a convention to skip writing Unit when a function returns Unit because Unit is considered the default return type by the compiler:
fun greet() { println("Good day!") }
Unit is a Singleton
The Unit is a class with only a single object (singleton pattern) and that object is the Unit itself. It is declared in the kotlin package using an object declaration as shown below:
public object Unit {
override fun toString() = "kotlin.Unit"
}
Unit in Functional Programming
Kotlin has first-class support for functional programming. It's common to have a Unit in a functional programming language. It makes the function types more readable by enabling all the functions to be declared as having a return value, even when a function does not return a value:
val greet: () -> Unit = { println("Good day!") }
Here, () -> Unit is a function type and the Unit after the -> indicates that this function type does not return any meaningful value. Mentioning the Unit cannot be skipped in function types.
Unit for Extending Generics
Every function has to return a value. Kotlin decided to represent this with a class rather than with a special type void as in Java. The reason for using a class is that the type system can be made more consistent by making it a part of the type hierarchy.
For example, let's say we have a generic interface called Worker<T> that performs some work. The doWork() function of this interface does some work and has to return a value T:
interface Worker<T> {
fun doWork(): T
}
But sometimes, we might want to use this interface for some work where we don't need to return any value, for example, the work of logging, in the LogWorker class shown below that extends the Worker interface:
class LogWorker : Worker<Unit> {
override fun doWork() {
// Do the logging
}
}
This is the magic of Unit where we are able to use the pre-existing interface that was originally designed to return a value. Here we make the doWork() function return the Unit value to serve our purpose in which we don't have anything to return. So, it's useful when you override a function that returns a generic parameter.
Notice that we have also skipped mentioning Unit return type for the doWork() function. There's no need to write a return statement either.
Nothing
Nothing's Value Never Exists
In Kotlin, the class Nothing represents a value that never exists. There can never be any value/object of this class because its constructor is kept private. It's defined in the kotlin package as follows:
public class Nothing private constructor()
Nothing is used for the return type of a function that never returns a value. For example, a function with an infinite loop or a function that always throws an exception. The error() function from Kotlin standard library is an example that always throws an exception and returns Nothing. Here is the code for it:
fun error(message: Any): Nothing = throw IllegalStateException(message.toString())
Nothing is the Bottom Type
In type theory, the type that has no values is called a bottom type and it is a subtype of all other types. So, Nothing is the subtype of all types in Kotlin, just like Any? is the supertype of all types. So, the value(that never exists) of type Nothing is assignable to the variables of all types, for example:
val user: User = request.user ?: error("User not found")
Here, we are calling the error() function that we defined earlier, if the user is null, using the elvis operator(?:). The error() function returns the value of type Nothing but it can be assigned to the variable of type User because Nothing is a subtype of User, just like it is a subtype of any other type. The compiler allows this because it knows that the error() function will never return a value, so there is no harm.
Similarly, you can return Nothing from a function that has any other return type:
fun getUser(request: Request): User {
return request.user ?: error("User not found")
}
Here, even though the getUser() function is declared to return a User, it may return Nothing, if the user is null.
Nothing in Null Object Pattern
Consider the following example of a function that deletes the files given in a list:
fun deleteFiles(files: List<File>? = null) {
if (files != null) files.forEach { it.delete() }
}
The problem with the design of this function is that it doesn't convey whether the List<File> is empty or null or has elements. Also, we need to check whether the list is null before using it.
To solve this problem, we use the null object design pattern. In null object pattern, instead of using a null reference to convey the absence of an object, we use an object which implements the expected interface, but leaves the method body empty.
So, we define the object of the interface List<Nothing>:
// This function is already defined in the Kotlin standard library
fun emptyList() = object : List<Nothing> {
override fun iterator(): Iterator<Nothing> = EmptyIterator
...
}
Now we use this null object in our deleteFiles() function as a default value of our parameter:
fun deleteFiles(files: List<File> = emptyList()) {
files.forEach { it.delete() }
}
This removes the uncertainty of null or empty and makes the intent clearer. It also removes the null checks because the functions on the null object are empty, they will be called but they are no-ops (no operation in them, so they will do nothing).
Nothing for Covariant Generics
In the example above, the compiler allows us to pass List<Nothing> where List<File> is expected. This is because the List interface in Kotlin is covariant since it's defined using the out keyword, that is, List<out T>. And as we learnt, Nothing is a subtype of all types, Nothing is a subtype of File too. And due to covariance, List<Nothing> is a subtype of List<File>, List<Int>, List<User> and so on... List<AllTypes>. This applies to any type with the covariant generics(out), not just List.
Nothing for Better Performance
Just like the function emptyList() used in our example, there are predefined functions like emptyMap(), emptySet(), emptySequence() that return null objects. All these are defined using Nothing. You can define your own objects like this.
The advantage here is that these return singleton objects, for example, you can call the same emptyList() function for getting an empty instance, whether it is for assigning to List<File>, List<Int> and ... List<AllTypes> and in multiple places. Since the same object is returned every time, it saves the cost of object creation and memory allocation.
Void
Void for Extending Generics in Java
The Void class is from the java.lang package while the Unit and Nothing are from the kotlin package. Void is not intended to be used in Kotlin. Kotlin has its own class in the form of Unit.
Void is used in Java for extending generic interfaces like our Worker interface example written for Unit where we have to return a value. So for converting our Kotlin code to Java, we can use Void the same way we have used Unit for our Worker example and rewrite the code in Java as follows:
interface Worker<T> {
T doWork();
}
class LogWorker implements Worker<Void> {
#Override public Void doWork() {
// Do the logging
return null;
}
}
Notice that when using Void, we have to use Void as a return type(can't skip) as well as need to write the return statement whereas for Unit we can skip both. This is another reason to avoid using Void in Kotlin code.
Conclusion
So, Unit and Nothing are not a mistake by Kotlin designers in my opinion and are not as questionable as null, undefined and void(0) in Javascript. Unit and Nothing make the functional programming a breeze while providing other useful features mentioned. They are common in other functional programming languages too.
That's it!
Void is uninstantiable type. It is a plain Java class and has no special meaning in Kotlin.
Unit type has only one value. Replaced Java void (notice: not Void). More info in Kotlin docs.
Nothing has no instances (just like Void). It represents "a value that never exists". In Kotlin if you throw an error it is a Nothing (see Kotlin docs).
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"
}