Nullable of nullable in Kotlin? - kotlin

I have a use case where I need double level of nullable, something like x: SomeClass??. See prefetchedRecord argument in java code below
public Optional<SomeClass> fetchRecord(Long id) {
...
}
public void process(
Long id,
Optional<Optional<SomeClass>> prefetchedRecord
) {
Optional<SomeClass> fetchedRecord = prefetchedResult.orElseGet( () -> fetchRecord(id) )
if (fetchedRecord.isPresent()) { ... process ... }
else { ... do something else ... }
}
So for the prefetchedRecord the inner optional signifies the result of the fetching and the outer optional shows whether the fetching was ever done before calling the process function. I use two optional to avoid refetching the record even if the fetching returned nothing.
How would you write this in Kotlin? I realize using double optional is not that clear and I could use a custom class instead, smth like
data class FetchResult<T>(val result: T, val fetched: boolean)
but I wonder if there is something built in into Kotlin to support this use case.

There is no way to do nullable of nullable in Kotlin. I think Kotlin way is avoid null in most cases. You can use sealed-classes for more expressive code.
For example:
sealed class Result<out T> {
data class Fetched<T>(val result: T): Result<T>()
data class Prefetched<T>(val result: T): Result<T>()
object None: Result<Nothing>()
}
Sealed classes provides algebraic data types support and you can make very expressive types with this powerful language feature.
You also can use Kotlin standard Result in some cases

No, there is nothing built-in in Kotlin to handle your requirements. If you are targeting Java platform you can use java.util.Optional<T> class:
fun process(id: Long, prefetchedRecord: Optional<Optional<SomeClass>>) {
...
}
Or you can try to use java.util.Optional<T> class like this:
fun process(id: Long, prefetchedRecord: Optional<SomeClass>?) {
...
}

Related

How can I circumvent Kotlin's generics type variance constraints

I am relatively new Kotlin and Generics kind of give me a headache. I have the following architecture made out of:
A few data classes
A generic interface to process data
Implementations of that processing interface for each data type
A generic processing job class containing the data to be processed and it's appropriate processor
A global (singleton) processor which implements the processing interface, takes processing jobs and just delegates the processing to the job processor. It doesn't care about the data itself at all.
The simplified code looks like this
class DataOne
class DataTwo
interface DataProcessor<in T> {
fun process(o: T)
}
class DataOneProcessor: DataProcessor<DataOne> {
override fun process(o: DataOne) = println("Processing DataOne")
}
class DataTwoProcessor: DataProcessor<DataTwo> {
override fun process(o: DataTwo) = println("Processing DataTwo")
}
class ProcessingJob<T>(val data: T, val processor: DataProcessor<T>)
object GlobalProcessor: DataProcessor<ProcessingJob<Any>> {
override fun process(job: ProcessingJob<Any>) = job.processor.process(job.data)
}
fun main() {
GlobalProcessor.process(ProcessingJob(DataOne(), DataOneProcessor()))
}
In the main function I get a compiler error
Type mismatch.
Required: ProcessingJob<Any>
Found: ProcessingJob<DataOne>
I understand why this happens: A DataProcessor of DataOne, viewed as a DataProcessor of Any could be asked to process DataTwos and for type safety this is not allowed.
Can you give me any suggestions on how/what to change to make it compile and achieve the required result? Thanks for your time!
There are two problems here.
First, Any isn't actually the top-level type. Any implies not null, but T is unconstrained, which means it can be a nullable type. In this case you can use *, or you could also specify the type as Any?.
Change the signature of the GlobalProcessor to this:
object GlobalProcessor: DataProcessor<ProcessingJob<*>> {
override fun process(job: ProcessingJob<*>): ...
The second problem is that the implementation of process can't take advantage of the generic information from the job in order to know that the job.processor and the job.data are compatible. It just sees two objects of unknown type. To let it know they share a compatible type, you need to capture that type as a type variable. We can't add a generic type parameter to the existing method, because it has to match the signature of the interface method, but we can add a new private method that introduces the generic parameter.
Here's the GlobalProcessor with both the required changes.
object GlobalProcessor: DataProcessor<ProcessingJob<*>> {
override fun process(job: ProcessingJob<*>) = processGeneric(job)
private fun <T> processGeneric(job: ProcessingJob<T>) = job.processor.process(job.data)
}

Having trouble with type erasure

I have something like this :
import kotlin.reflect.KClass
class Quantity<T> {
/* ... */
}
class Field<T : Any> {
val type: KClass<T> get() = TODO("This is initialized, don't worry about implentation details, just know that fields know their type.")
fun initValue(value: T) {
/* Do something very useful */
}
/* Other methods */
class Template<T : Any> {
fun initFieldWithValue(value: T): Field<T> {
return Field<T>().apply {
this.initValue(value)
}
}
}
}
class ComponentClass(
val fieldsTemplates: Map<String, Field.Template<*>>
) {
inner class Instance(field: Map<String, Field<*>>)
fun new(fieldValues: Map<String, Quantity<*>>): Instance {
val fields = mutableMapOf<String, Field<*>>()
for ((fieldName, template) in fieldsTemplates) {
fields[fieldName] = fieldsTemplates
.getValue(fieldName)
.initFieldWithValue(fieldValues.getValue(fieldName) /* Here a type error */)
}
return Instance(fields)
}
}
As you might guess, this is intended to work as a 'runtime way' of creating classes that own fields (Field<T> class), each one possessing a typed value (represented by a Quantity<T>).
The problem is that this code won't compile due to the fact that the quantity retrieved from fieldValues when creating the different fields of the future Instance in the new method isn't guaranteed to be of the required type for the field it is stuffed into.
The problem is that I would need a check since filling a Field<Quantity<String>> with a Quantity<Int> is obviously not a good idea, but because of the type erasure I cannot ensure that the quantities passed in are of the good type.
Any idea ? One more thought : Fields know what their type is thanks to their type attribute, but unfortunately I can't do the same for the Quantity class...
Your initFieldWithValue function is enforcing the type of the parameter to match the type known by the Template/Field. But inside your new function, your Template is a Template<*> since you retrieve it from a collection where the values are of this type.
The point of generics is to enforce compile time checks so casting can be done safely and automatically under the hood. This is only useful when your type is known at compile time. In this case, the type is not known at compile time, so the generics are preventing your code from compiling. This is what generics are supposed to do: prevent code from compiling if the compiler cannot check that they types match.
If you want this code to compile, you should change initFieldWithValue so it doesn't enforce generics. You can instead manually check the type and throw an error or exit early if it's incorrect. It will be up to your code elsewhere to ensure you aren't mixing and matching types.
Here's an example of a version that would work. The type check it does requires the Kotlin reflection library. If you're targeting JVM only, you can use the Java Class.isAssignableFrom method instead to do this check.
class Template<T : Any> {
val type: KClass<T> get() = TODO()
/**
* #throws IllegalStateException if [value] is not of the same type
* as this Template's [type].
*/
fun initFieldWithValue(value: Any): Field<T> {
if (!value::class.isSubclassOf(type)) {
error("Invalid value type for Field type of $type")
}
return Field<T>().apply {
#Suppress("UNCHECKED_CAST") // we manually checked it above
initValue(value as T)
}
}
}

Kotlin Factory Class with Generic outputs

I'm in the process of trying to port some code I wrote in Java over to Kotlin and I'm struggling mightily with some issues around generics. I quite commonly use a factory pattern in Java to return an instance of a generic interface that I want to call for a given type.
In Java I had this contract:
public Message<T extends Action> {
private List<T> actions;
..some other properties
}
And this interface:
public interface MessageConverter<T extends Action, M extends BaseModel> {
List<M> convertMessage(Message<T> message);
DataType getDataType();
}
And lastly this factory:
public class MessageConverterFactory {
//This gets populated via DI
private Map<DataType, MessageConverter> converterMap;
public <T extends Action, M extends BaseModel> MessageConverter<T, M> getMessageConverter(DataType dataType) {
return converterMap.get(dataType);
}
}
With all that in place, I was able to do things like this:
Message<T> message = mapper.readValue(messageString, type);
MessageConverter<T, M> messageConverter = messageConverterFactory.getMessageConverter(dataType);
List<M> dataModels = messageConverter.convertMessage(message);
I understand that I was abusing raw generic types in Java to an extent to make this happen, but I assumed there would be some way to still do a generic factory pattern like this.
However, no matter with I try with generic variance, star projections, etc. I cannot get Kotlin to accept any version of this code. The closest I got was down to the invocation of the generic converter's convertMessage call. It was failing because I was using star projections and attempting to restrict the type of T, but that was leading to the compiler thinking convertMessage accepts Message<Nothing>.
Is code like this possible in Kotlin? Or is there a similar alternative approach I should be using instead?
Thanks,
Jeff
The literal conversion of this to Kotlin is pretty simple, and the Java-to-Kotlin converter built in to IDEA would spit something like this out almost directly, given the equivalent Java code:
class Message<T: Action> {
private val actions: List<T> = TODO()
...
}
interface MessageConverter<T: Action, out M: BaseModel> {
fun convertMessage(message: Message<T>): List<M>
val dataType: DataType
}
class MessageConverterFactory(val converterMap: Map<DataType, MessageConverter<*, *>>) {
fun <T: Action, M: BaseModel> getMessageConverter(dataType: DataType): MessageConverter<T, M> {
return converterMap[dataType] as MessageConverter<T, M>
}
}
Note, the cast in getMessageConverter -- your Java code is doing the equivalent, without being explicit about it -- I believe the compiler would even spit out a warning about an unchecked assignment.
An alternative in Kotlin is to use an inline function with reified types to return the appropriate converter. For example, something like this:
inline fun <reified T: Action, reified M: BaseModel> converterOf(): MessageConverter<T, M> = when {
T::class == FooAction::class, M::class == BarModel::class -> TODO()
else -> error("No converter available for type ${T::class.simpleName} to ${M::class.simpleName}")
}

How to make a generic function for enumValues<T> in Kotlin?

I struggle with providing a type as parameter for a procedure that uses the enumValues<MyEnum>() function.
Got it to work with reified but using inline functions all the way is no option for me.
fun <T: Enum<Trait>> traits(
selectionState: SnapshotStateMap<Trait, Boolean>
) {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}
My enums all derive from enum class Trait. So in fact I want to pass enum class TraitFoo: Trait, enum class TraitBar: Trait and so on into the function.
Cannot use 'T' as reified type parameter. Use a class instead.
Is the compile error I receive here. Any idea of solving this? I am somewhat confused why this is not working.
Looking at the implementation of enumValues:
public inline fun <reified T : Enum<T>> enumValues(): Array<T>
I see it uses reified. That does mean the type has to be known at compile time. Therefore I can not pass a generic but need to pass an explicit type? Is that the issue?
If yes - is there another way to achieve this rather than using reified ?
If you want to be able to use T in your function as if it's a real type then it must be reified. And in order for a type parameter to be reified it must be part of an inline function. So you're going to need an inline function.
The next bit is figuring out the generics. You currently have:
<T : Enum<Trait>>
That means, due to the nature of enums, that T can't possibly be anything other than Trait. However, you have since clarified that Trait is not an enum but is actually an interface that's implemented by various enum classes. So what you really want is T to be bounded by both Enum<T> and Trait.
Given all this, I believe what you're looking for is the following:
inline fun <reified T> traits(
selectionState: SnapshotTraitMap<Trait, Boolean>
) where T : Enum<T>, T : Trait {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}

Join eq function not working with Jooq and Kotlin

I'm using:
Jooq 3.13.2
Kotlin 1.3.71
Spring boot 2.2.6.RELESE
Java 11
I was able to generate Jooq classes and execute a simple query:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.forEach { println($it[STORY.ID]) }
}
}
When I try to add a bit more complex logic by adding join, compilation is failing:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
.forEach { println($it[STORY.ID]) }
}
}
Compilation fails on following line .join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
Error:
None of the following functions can be called with the arguments supplied:
public abstract fun eq(p0: Int!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Field<Int!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: QuantifiedSelect<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Select<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
I was following this tutorial: https://blog.jooq.org/2017/05/18/10-nice-examples-of-writing-sql-in-kotlin-with-jooq/
Edit:
It looks like the issue is that STORY.CREATED_BY is type of Long, while USERS.ID is type of Integer. I'm not sure what needs to be changed to be able to fix this.
Thank you
You should probably change the type of all of these ID columns and their reference to be the same, i.e. BIGINT.
As a quick workaround, you can use Field.coerce(). I would prefer that over Field.cast(). The difference is that coerce() does not have any effect on the generated SQL (which you want to avoid to get better index usage), whereas cast() translates to the SQL CAST() function.