Is it possible to make safe inline Optional in Kotlin? - kotlin

In Kotlin sometimes I have to work with double nullability. For example, I need double nullability, when I want to use T? where T may be a nullable type. There are a few approaches for doing this:
Holder<T>? where Holder is data class Holder<out T>(val element: T) - example1
boolean flag variable - example1
containsKey for Map<K, T?> - example1
The special UNINITIALIZED_VALUE for representing the second kind of null - example1
The last approach has the best performance, but it's also the most error-prone. So I've decided to encapsulate it in inline class Optional<T>:
inline class Optional<out T> #Deprecated(
message = "Not type-safe, use factory method",
replaceWith = ReplaceWith("Optional.of(_value)")
) constructor(private val _value: Any?) {
val value: T?
get() =
#Suppress("UNCHECKED_CAST")
if (isPresent) _value as T
else null
val isPresent: Boolean
get() = _value != NULL
companion object {
#Suppress("DEPRECATION")
fun <T> of(value: T) = Optional<T>(value)
fun <T : Any> ofNullable(value: T?): Optional<T> =
if (value == null) EMPTY
else of(value)
#Suppress("DEPRECATION")
val EMPTY = Optional<Nothing>(NULL)
}
private object NULL
}
inline fun <T> Optional<T>.ifPresent(code: (T) -> Unit) {
#Suppress("UNCHECKED_CAST")
if (isPresent) return code(value as T)
}
inline fun <T> Optional<T>.or(code: () -> T): T {
ifPresent { return it }
return code()
}
The first problem with this Optional is public constructor, which allows creating instances with arguments of not matching type.
The second problem was noticed at testing time. Here is the failed test:
emptyOr { Optional.EMPTY }.value assertEql null
fun <T> emptyOr(other: () -> T): T = Optional.EMPTY.or(other)
Exception:
Exception ClassCastException: Optional$NULL cannot be cast to Optional
at (Optional.kt:42) // emptyOr { Optional.EMPTY }.value assertEql null
If I remove inline modifier from Optional, the test will pass.
Q: Is there any way to fix these problems without removing inline modifier from Optional?
1 Examples include some context. Please read them fully before writing that I added incorrect links.

I implemented exactly the same utility in one of my projects: OptionalValue.kt. My implementation is very similar to yours, it is also an inline/value class, so it should be cpu/memory efficient and it passes all tests I throw at it.
Regarding your first question: about a public constructor. There is an annotation specifically for this case: #PublishedApi. I tried to reproduce ClassCastException from your example, but it worked for me without problems, so I believe it was a bug in Kotlin itself (?).
Also, to answer the question why do we need double nullability, I explained my point here

Related

How to implement property delegate that works with an arbitrary type

I'm trying to implement custom property delegate to store props in a Map (just like in docs, for the educational purposes)
Delegate implementation must:
allow to store properties of arbitrary type
allow for type inference (just like the original one)
I've wrote a code that satisfies first condition:
import kotlin.reflect.KProperty
fun main() {
val e = Example(PropInMapDelegate())
e.myProp = 1;
println(e.myProp) // e.myProp is "Any?" :(
}
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp by propInMapDelegate
}
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun getValue(thisRef: Any, property: KProperty<*>): Any? {
return _map[property.name]
}
operator fun setValue(thisRef: Any, property: KProperty<*>, value: Any?) {
_map[property.name] = value
}
}
But, it has obvious 2 issues:
Using "Any?" breaks type inference
Explicitly specifying property type var myProp: Int by propInMapDelegate leads to errors:
error#1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any?, KProperty<*>) defined in PropInMapDelegate
error#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any?, KProperty<*>, Any?) defined in PropInMapDelegate
I've tried to employ generics to allow for type inference, but failed.
Changing PropInMapDelegate implementation like so:
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun <T>getValue(thisRef: Any, property: KProperty<*>): T? {
return _map[property.name] as T // That feels very wrong
}
operator fun <T>setValue(thisRef: Any, property: KProperty<*>, value: T?) {
_map[property.name] = value
}
}
And using the following
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp: Int by propInMapDelegate // error (see below)
}
Leads to:
error#1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any, KProperty<*>)   where T = Int for   operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T? defined in PropInMapDelegate
error#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any, KProperty<*>, Int?)   where T = Int for   operator fun <T> setValue(thisRef: Any, property: KProperty<*>, value: T?): Unit defined in PropInMapDelegate
Questions:
What am I missing?
Why does Kotlin expect the exact "Example" type in setValue/getValue signature?
How to implement "getValue" without using unsafe "as T" operator?
Edit: it seems that original implementation utilizes as too, so it's probably ok?
public inline operator fun <V, V1 : V> MutableMap<in String, out #Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1 =
#Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V1)
I think the error message is misleading you because of the way it is worded. "Example" isn't the part that doesn't match. Since Example is a subtype of Any, that part of your getValue() function signature is fine.
The part that doesn't match is that you are returning T? but you're trying to use it for a non-nullable property.
If you change your property to be nullable, it will work:
var myProp: Int? by propInMapDelegate
Or if you change your operator function to return a non-nullable, it will work:
operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T {
return _map[property.name] as T
}
Note that casting as T will fail if the value for that key doesn't exist in the map and you're using this for a non-nullable property, because null cannot be cast to a non-nullable T.
Regarding your question marked 3: As you can see in the standard library source code, casting is unavoidable if you are using a map of arbitrary value types. It's part of the potential danger in using a map for this purpose. It is also possible the map doesn't have the values at all that match up with the requested property names.

How to overload function with different return types and the same parameters in Kotlin?

I want to overload function with the same parameters (or without parameters at all) and different return types. Correct implementation should be chosen by the type of variable I assign returning value of a function to.
The only way to do this I found is using reified generics and comparing KClass'es:
inline fun <reified T: Any> read(): T {
return read(T::class)
}
#Suppress("UNCHECKED_CAST")
fun <T: Any> read(t: KClass<T>): T {
return when (t) {
Int::class -> readInt() as T
UInt::class -> readUInt() as T
String::class -> readString() as T
// ...
else -> throw Exception("Unsupported type")
}
}
fun readInt(): Int {
// ...
}
fun readUInt(): UInt {
// ...
}
fun readString(): String {
// ...
}
The problem with this approach is that the compiler and IDEA are not smart enough to determine types at compile time for which there is no implementation. The most I can do is throw a runtime exception:
val int: Int = read()
val string: String = read()
val double: Double = read()
// ^^^^ No compile-time error here
Maybe I'm missing something and there is more "correct" way of doing this?
Maybe I'm missing something and there is more "correct" way of doing this?
No. You cannot do this at all. You must name the methods differently.

Cloning object of subclass type in Kotlin

I wanted to be able to define a method to clone an object that is the same type of itself. I define the interface requesting such, but the following does not compile or run.
interface Foo {
fun <T: Foo> copy() : T
}
class Bar(private val v:Int) : Foo {
override fun copy():Bar = Bar(v)
}
main() {
val bar1 = Bar(1)
val bar2 = bar1.copy()
}
If however I write the implementing class in Java, it will compile
class Bar implements Foo {
private int v;
public Bar(int v) {this.v = v;}
public Bar copy() {
return new Bar(v);
}
}
I can rewrite the code like the following that compiles:
interface Foo<out Foo>{
fun copy(): Foo
}
class Bar(private val v:Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
However the following will fail with error: no type arguments expected for fun copy(): Foo
val newF = f.copy()
fun <T: Foo> addFoo(
foo: T,
fooList: List<T>,
): MutableList<T> {
val result: MutableList<T> = arrayListOf()
for (f in fooList) {
val newF = f.copy<T>()
result.add(newF)
}
result.add(foo)
return result
}
Is there a good solution to the problem?
The problem here is that Foo doesn't know the exact type of the implementing class, so has no way to specify that its method returns that same type.
Unfortunately, Kotlin doesn't have self types (see this discussion), as they would handle this situation perfectly.
However, you can get close enough by using what C++ calls the curiously-recurring template pattern. In Kotlin (and Java) you do this by defining Foo with a type parameter explicitly extending itself (including its own type parameter):
interface Foo<T : Foo<T>> {
fun copy(): T
}
Then the implementing class can specify itself as the type argument:
class Bar(private val v: Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
And because T is now the correct type, everything else works out. (In fact, the : Bar is redundant there, because it already knows what the type must be.)
Your addFoo() method will then compile with only a couple of changes: give it the same type parameter <T: Foo<T>>, and remove the (now wrong, but unnecessary) type parameter when calling f.copy(). A quick test suggests it does exactly what you want (creates a list with clones of fooList followed by foo).
Since it's often useful for a superclass or interface to refer to the implementing class, this pattern crops up quite often.
BTW, your code is easier to test if Bar has its own toString() implementation, as you can then simply print the returned list. You could make it a data class, or you could write your own, e.g.:
override fun toString() = "Bar($v)"

Kotlin How to create dynamic Object

In javascript we can do something like this
function putritanjungsari(data){
console.log(data.name)
}
let data = {
name:"putri",
div:"m4th"
}
putritanjungsari(data)
In kotlin, i'am creating a function that accept an object as parameter then read it's properties later, how to do that in kotlin that targeting JVM?
If I understood your question correct, you are trying to have a variable that associates keys with some value or undefined(null in kt) if none are found. You are searching for a Map
If you don't know what types you want, you can make a map of type Any? So
Map<String, Any?>
Which is also nullable
Map<String, Any>
If you don't want nullables
Your code for example:
fun putritanjungsari(data: Map<String, Any?>){
print(data["name"])
}
val data: Map<String, Any?> =mapOf(
"name" to "putri",
"div" to "m4th"
)
putritanjungsari(data)
Note that you can't add new keys or edit any data here, the default map is immutable. There is MutableMap (which is implemented the same, only it has a method to put new data)
You can apply the property design pattern to solve your problem.
Here is its implementation in Kotlin:
interface DynamicProperty<T> {
fun cast(value: Any?): T
fun default(): T
companion object {
inline fun <reified T> fromDefaultSupplier(crossinline default: () -> T) =
object : DynamicProperty<T> {
override fun cast(value: Any?): T = value as T
override fun default(): T = default()
}
inline operator fun <reified T> invoke(default: T) = fromDefaultSupplier { default }
inline fun <reified T> required() = fromDefaultSupplier<T> {
throw IllegalStateException("DynamicProperty isn't initialized")
}
inline fun <reified T> nullable() = DynamicProperty<T?>(null)
}
}
operator fun <T> DynamicProperty<T>.invoke(value: T) = DynamicPropertyValue(this, value)
data class DynamicPropertyValue<T>(val property: DynamicProperty<T>, val value: T)
class DynamicObject(vararg properties: DynamicPropertyValue<*>) {
private val properties = HashMap<DynamicProperty<*>, Any?>().apply {
properties.forEach { put(it.property, it.value) }
}
operator fun <T> get(property: DynamicProperty<T>) =
if (properties.containsKey(property)) property.cast(properties[property])
else property.default()
operator fun <T> set(property: DynamicProperty<T>, value: T) = properties.put(property, value)
operator fun <T> DynamicProperty<T>.minus(value: T) = set(this, value)
}
fun dynamicObj(init: DynamicObject.() -> Unit) = DynamicObject().apply(init)
You can define your properties these ways:
val NAME = DynamicProperty.required<String>() // throws exceptions on usage before initialization
val DIV = DynamicProperty.nullable<String>() // has nullable type String?
val IS_ENABLED = DynamicProperty(true) // true by default
Now you can use them:
fun printObjName(obj: DynamicObject) {
println(obj[NAME])
}
val data = dynamicObj {
NAME - "putri"
DIV - "m4th"
}
printObjName(data)
// throws exception because name isn't initialized
printObjName(DynamicObject(DIV("m4th"), IS_ENABLED(false)))
Reasons to use DynamicObject instead of Map<String, Any?>:
Type-safety (NAME - 3 and NAME(true) will not compile)
No casting is required on properties usage
You can define what the program should do when a property isn't initialized
Kotlin is statically typed language, so it required a param type to be precisely defined or unambiguously inferred (Groovy, for instance, addresses the case by at least two ways). But for JS interoperability Kotlin offers dynamic type.
Meanwhile, in your particular case you can type data structure to kt's Map and do not argue with strict typing.
You have to use Any and after that, you have to cast your object, like this
private fun putritanjungsari(data : Any){
if(data is Mydata){
var data = data as? Mydata
data.name
}
}
Just for the sake of inspiration. In Kotlin, you can create ad hoc objects:
val adHoc = object {
var x = 1
var y = 2
}
println(adHoc.x + adHoc.y)

How to implement mutable optional in Kotlin?

I want a class which is equivalent to Java Optional but also
Properly handles null value ("Not set" state is different from "Null set")
Is mutable
Uses Kotlin built-in null-safety, type parameter can be either nullable or non-nullable which affects all methods.
Non-working code:
class MutableOptional<T> {
private var value: T? = null
private var isSet: Boolean = false
fun set(value: T)
{
this.value = value
isSet = true
}
fun unset()
{
isSet = false
value = null
}
fun get(): T
{
if (!isSet) {
throw Error("Value not set")
}
return value!! // <<< NPE here
}
}
fun f()
{
val opt = MutableOptional<Int?>()
opt.set(null)
assertNull(opt.get())
}
The problem is that if I try to set null, get() call fails with null pointer exception (caused by !! operator).
Some not-working proposals:
Do not use members of type "T?" in such class. I would not use it if I knew how to leave them uninitialized (not allowed by the compiler) or how to make them to have default initialization.
Use "fun get(): T?" (with nullable result). I want the result type to have the same nullability as the class type parameter. Otherwise there is no meaning in such null-safety if it is lost in a simple generic class, and I will need to set !! manually where I am sure it is non-nullable (the thing the compiler should ensure), making my code looking like wedge-writing.
Note: This example is synthetic, I do not really need the mutable optional, it is just a simple and understandable example, illustrating a problem I encounter occasionally with Kotlin generics and null-safety. Finding solution to this particular example will help with many similar problems. Actually I have a solution for immutable version of this class but it involves making interface and two implementation classes for present and non-present values. Such immutable optional can be used as type of "value" member but I think it's quite big overhead (accounting also wrapper object creation for each set()) just to overcome the language constraints.
The compiler wants you to write code that will be type-safe for all possible T, both nullable and not-null (unless you specify a not-null upper bound for the type parameter, such as T : Any, but this is not what you need here).
If you store T? in a property, it is a different type from T in case of not-null type arguments, so you are not allowed to use T and T? interchangeably.
However, making an unchecked cast allows you to bypass the restriction and return the T? value as T. Unlike the not-null assertion (!!), the cast is not checked at runtime, and it won't fail when it encounters a null.
Change the get() function as follows:
fun get(): T {
if (!isSet) {
throw Error("Value not set")
}
#Suppress("unchecked_cast")
return value as T
}
I got a similar issue. My use case was to differentiate null and undefined value when I deserialize JSON object. So I create an immutable Optional that was able to handle null value. Here I share my solution:
interface Optional<out T> {
fun isDefined(): Boolean
fun isUndefined(): Boolean
fun get(): T
fun ifDefined(consumer: (T) -> Unit)
class Defined<out T>(private val value: T) : Optional<T> {
override fun isDefined() = true
override fun isUndefined() = false
override fun get() = this.value
override fun ifDefined(consumer: (T) -> Unit) = consumer(this.value)
}
object Undefined : Optional<Nothing> {
override fun isDefined() = false
override fun isUndefined() = true
override fun get() = throw NoSuchElementException("No value defined")
override fun ifDefined(consumer: (Nothing) -> Unit) {}
}
}
fun <T> Optional<T>.orElse(other: T): T = if (this.isDefined()) this.get() else other
The trick: the orElse method have to be defined as an extension to not break the covariance, because Kotlin does not support lower bound for now.
Then we can define a MutableOptional with no cast in the following way:
class MutableOptional<T> {
private var value: Optional<T> = Optional.Undefined
fun get() = value.get()
fun set(value: T) { this.value = Optional.Defined(value) }
fun unset() { this.value = Optional.Undefined }
}
I am happy with my immutable Optional implementation. But I am not very happy with MutableOptional: I dislike the previous solution based on casting (I dislike to cast). But my solution creates unnecessary boxing, it can be worst...