jOOQ: How to select an empty array "[]" in Kotlin - kotlin

I would like to produce SQL that is essentially the equivalent of array[] or [] using jOOQ's DSL so that it's portable between dialects.
Unfortunately in Kotlin, none of these work:
// Overload resolution ambiguity. All these functions match.
// public open fun <T : Any!> array(vararg values: TypeVariable(T)!): Field<Array<(out) TypeVariable(T)!>!> defined in org.jooq.impl.DSL
// public open fun <T : Any!> array(vararg fields: Field<TypeVariable(T)!>!): Field<Array<(out) TypeVariable(T)!>!> defined in org.jooq.impl.DSL
DSL.array()
DSL.array(null as Any?) // Produces a non-empty array
DSL.array(emptyList<Any>()) // Produces a non-empty array
Is there any way to do this, or something like an DSL.emptyArray() method?

Why passing emptyList<Any> didn't work
The Collection accepting overload of DSL.array() expects a Collection<? extends Field<T>>, i.e. a collection of column expressions, not a Collection<? extends T>, which would be a collection of bind values. We can't have both overloads for the usual type erasure reasons, so only the more generic version is offered. But you're passing a List<Any>, not a List<Field<*>>. You could change your code to:
DSL.array(emptyList<Field<*>>())
Why passing null didn't work
When you pass null, the varargs overload is resolved, which corresponds to ARRAY[NULL] in SQL, an array containing a NULL value.
How to call the varargs overload
If you want to work with the varargs overloads, then just pass an empty array:
DSL.array(arrayOf<String>())
Because array types are reified in Java, both varargs overloads exist:
array(T...): Accepting bind values
array(Field<T>...): Accepting column expressoins
Regarding array types
If you're using PostgreSQL, you'll probably have to cast that array expression explicitly to e.g. SQLDataType.VARCHAR.getArrayDataType()
DSL.array(arrayOf<String>()).cast(SQLDataType.VARCHAR.getArrayDataType())
Using bind values as an alternative
You can always use bind values or inline values as well:
DSL.value(arrayOf<String>())
DSL.inline(arrayOf<String>())
In this case, the array type is known to jOOQ, and you don't need to cast it explicitly anymore.

Related

Is it possible to pass null type in place of generic type parameter?

I am going to use the following method from Spring Data Kotlin extensions:
inline fun <reified T : Any> MongoOperations.bulkOps(bulkMode: BulkMode, collectionName: String? = null): BulkOperations
The question is: can I somehow avoid specifying T assuming I do not want to provide entity class name (that's because I will explicitly specify collectionName, and in this case class type can be null). I would like to type something like:
val ops = mongoTemplate.bulkOps<null>(BulkOperations.BulkMode.UNORDERED, collectionName = "i_know_better")
Is there a type literal for null with which I can parameterize bulkOps?
I think the short answer is no.
You seem to confuse types with values. null is a value and not a type so it cannot be used as a type in generic methods.
In your specific example, even if you could use null, looking at the code what would you expect to happen?
#Suppress("EXTENSION_SHADOWED_BY_MEMBER")
inline fun <reified T : Any> MongoOperations.bulkOps(bulkMode: BulkMode, collectionName: String? = null): BulkOperations =
if (collectionName != null) bulkOps(bulkMode, T::class.java, collectionName)
else bulkOps(bulkMode, T::class.java)
As you can see there's always T::class.java being called. What would be the result of null::class.java?
I'm unfamiliar with the Spring Data so I can't really provide an alternative, but I'd say you either need to search for another method or use an appropriate class here. The generic type is marked as T : Any so presumably it can be any non-nullable type. I wonder if Unit would work. Again, I'm not sure what this class is used for.
To answer the question in general, you can use Nothing? to represent the type that only contains the value null.
That being said, as #Fred already said, the method you're considering here explicitly states T : Any, meaning only non-nullable types are allowed. And it makes sense given that the function is accessing the class of T.

Does in require casting when retrieving items from a list?

I have the following function:
fun bar(list: MutableList<in Person>) {
for(a in list) {
println(a.getName())
}
}
The problem is that a is considered of type Any and I would need to cast to Person first. Is this how it is supposed to be, or am I doing something wrong?
In Java if I declare with extends Person I would not need to cast.
I.e. if I had:
public <T extends Person> void bar(List<T> list)
The Java method signature you gave is for a generic method (i.e. one that binds a type variable). This allows you to specify that your list must have that element type, allowing you to both retrieve and insert elements into the list safely, knowing they're of that type. You can do this in Kotlin too:
public <T extends Person> void bar(List<T> list);
is equivalent to
fun <T: Person> bar(list: MutableList<T>)
However, the Kotlin method signature you gave in your question is not generic, but has a wildcard generic argument. You can do this in Java too:
fun bar(list: MutableList<in Person>)
is equivalent to
public void bar(List<? super Person> list);
This is different to the generic method signature above. In the generic method, we can create variables of type T by taking elements out of the list, and we know that these are a subtype of Person. Since list has been bound to have element type T we also know that we can insert such variables back into the list.
With the non-generic, wildcard signature, we can't do that. In both the Java and Kotlin cases we have a method that takes any list whose element type is a supertype of Person. So, when we get elements out of the list, all we know for certain is that they are a supertype of Person, and the only type that fits this condition is Object/Any. However, the constraint on the wildcard does tell us that it should be fine to insert elements of type Person (or a subtype) into the list.
Just for completeness, the converse is also possible:
public void bar(List<? extends Person> list);
is equivalent to
fun bar(list: MutableList<out Person>)
Here, the method can take any list whose element type is a subtype of Person. We know that if we extract an element from the list, it will conform to the Person interface, so we can assign it to a variable of type Person. However, we don't know anything about what types we can insert into the list, as we don't know the exact subtype of Person the list accepts. Even though we know that a value we've just extracted from the list must be an acceptable type for insertion, I believe neither Kotlin nor Java is clever enough to infer this. You have to use the generic method signature as a "hint".
in and out are concepts not known to Java, cf. What is out keyword in kotlin, Understanding one usage of “in” keyword in Kotlin
The proper replacement for your Java code would be:
fun <T : Person> bar(list: MutableList<T>) {
for(a in list) {
println(a.getName())
}
}
(thanks to user31601 for pointing that out in the comments)

how to read kotlin type annotations

I'm coming to kotlin after working in mostly dynamically typed languages for years, so I get a lot of what I'm seeing, but I'm still tripping up a bit over reading some of the type annotations.
Most of them make sense (I've written some C++ and typescript so I'm not wholey familiar with more strictly type languages). so stuff like annotating the parameters and return types for functions, variable declaration, stuff like that makes sense.
What I'm having trouble with is the more complex annotations like looking at this explanation of the fold method when talking about higher order functions:
fun <T, R> Collection<T>.fold(
initial: R,
combine: (acc: R, nextElement: T) -> R
): R {
var accumulator: R = initial
for (element: T in this) {
accumulator = combine(accumulator, element)
}
return accumulator
}
I get that:
the Collection refers to an arbitrary collection with elements that are of type T
the fold method call takes an value of type R named initial as the first argument and a callable function labeled combine as the second argument
the callable function will be called for each element of the collection with an accumulator of type R labeled acc and the next element of the collection of type T (since it's a collection of Ts) labeled nextElement
The callable function will return a type R in the end
The fold method will return a type R in the end
And I can use it like this:
val greetings = listOf("hey", "hi", "yo", "what's up")
val personalized = greetings.fold("", { carry, current -> "${carry}\n$current, Chris." })
println(personalized)
That all makes sense, but what does the <T, R> between the fun and the Collection mean? What is that part called? (It's hard to search for an explanation when you don't know what the thing you're looking for is called :P)
And more importantly, is there a section of the documentation that specifically talks about how to read these annotations or what each are called? I've been looking through the docs and searching in general for an explanation of how to read the type annotations and I can't find anything.
It feels like a silly question, but to the uninitiated it's kind of daunting and the docs are written as if you already understand that part of the language.
As Alexey already said, these names between angled brackets after the fun keyword are called "type parameters". They are used to declare generic functions.
the Collection refers to an arbitrary collection with elements that are of type T
Here you can see that Collection and T play different roles: Collection is a well-known defined type that you are referencing, while T is just a name that you arbitrarily choose for the definition of this function.
We want the compiler to check that Collection is a type that is defined and imported, and if you make a typo there will be a compile error.
On the other hand, we don't want that for T and R, so it is necessary to mention them in a special syntactic place so that the compiler knows you're just making up arbitrary names for the sake of the function definition.
It is nice to draw a parallel between the type parameters and the method arguments. The method arguments are also arbitrary names that you define in the signature and use in the function body, as opposed to class members like properties, which you can access without declaring them as arguments.
Just like the values of the arguments are passed when you call a method, and can be different for each different invocation, the "values" of the type parameters are also given at the call site, and can be different for each invocation (they are often inferred, though, so you don't see them).
Note that the "value" of a type parameter is a type (e.g. String), not a value in the usual sense like the string "abc". You can actually specify these types explicitly on the call site if you want:
listOf(1, 2, 3).fold<Int, Int>(42) { acc, e -> acc + e }
The syntax on the call site is similar to the declaration site, it uses <>, except that it's written after the function name.
In general, these types are easily inferred by the compiler using the argument types or the return type in the context of the call site, that's why it's often unnecessary to explicitly specify them.
Difference with generics at the class level
It may seem weird that the methods in the interface List don't need to declare such type parameters, despite the fact that they use generic types:
interface MutableList<T> {
fun add(element: T): Boolean {
//....
}
}
This is because T is already "well-defined" when using it for the method declaration: it was already defined as a type parameter for the List interface itself. The mechanism is the same, but the difference is the scope of the definition: class-level type parameters are defined by the instance of the class (you can create a List<Int> or a List<String>, and this is chosen when you create your instance), while function type parameters are defined by each call to the function.
You can even combine both:
interface List<T> {
fun <R> map(transform: (T) -> R): List<R> {
//...
}
}
Here T will be determined by the list instance on which you call map, but R can be different for each call to map even on the same list instance.
<T, R> are the type parameters. Since you are familiar with C++, it's like
template <typename T, typename R>
It just happens to be placed after the fun keyword in Kotlin (and after the type name when declaring a generic class/interface/type alias) instead of before the function definition.

Type parameter cannot have any other bounds if it's bounded by another type parameter: what does this mean and how to resolve it?

I was implementing custom list class MyList<T> in kotlin. In that, I wanted to add insertSorted function, which inserts a new element into the list in sorted order. For that, T must implement comparator. So the prototype of that function will be fun <C> insertSorted(ele: C) where C:T, C:Comparable<T> But this is giving me Type parameter cannot have any other bounds if it's bounded by another type parameter error. I am not understanding what this error is. Also, this question did not help me much.
PS: The type I am passing to that function is declared as class MyClass : Comparator<MyClass>. So the bound where C:T, C:Comparator<T> is valid I guess.
For the meaning of the error, see this question:
Why can't type parameter in Kotlin have any other bounds if it's bounded by another type parameter?
But if your custom list contains elements of type T and you want to compare them, then T should implement Comparable<T>.
So this should be all you need:
class MyList<T: Comparable<T>> {
fun insertSorted(ele: T) {
}
}

Kotlin's reflection : Unknown type parameter

I am running some experiments on Kotlin's reflection.
I am trying to get a reflection object of a generic class with its argument.
In Java, that would be a ParameterizedType.
The way to get such a thing using Java's reflection API is a bit convoluted: create an anonymous subclass of a generic class, then get its super-type first parameter.
Here's an example:
#Suppress("unused") #PublishedApi
internal abstract class TypeReference<T> {}
inline fun <reified T> jGeneric() =
((object : TypeReference<T>() {}).javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
When I println(jGeneric<List<String?>>()), it prints java.util.List<? extends java.lang.String>, which is logical considering that Kotlin's List uses declaration-site out variance and that Java types have no notion of nullability.
Now, I would like to achieve the same kind of result, but with the Kotlin reflection API (that would, of course, contain nullability information).
Of course, List<String>::class cannot work since it yields a KClass. and I am looking for a KType.
However, when I try this:
inline fun <reified T> kGeneric() =
(object : TypeReference<T>() {})::class.supertypes[0].arguments[0].type
When I println(kGeneric<List<String?>>()), it prints [ERROR : Unknown type parameter 0], which is quite... well, anticlimactic ;)
How can I get, in Kotlin, a KType reflecting List<String> ?
To create a KType instance in Kotlin 1.1, you have two options:
To create a simple non-nullable type out of a KClass, where the class is either not generic or you can substitute all its type parameters with star projections (*), use the starProjectedType property. For example, the following creates a KType representing a non-nullable type String:
val nonNullStringType = String::class.starProjectedType
Or, the following creates a KType representing a non-nullable type List<*>:
val nonNullListOfSmth = List::class.starProjectedType
For more complex cases, use the createType function. It takes the class, type arguments and whether or not the type should be nullable. Type arguments are a list of KTypeProjection which is simply a type + variance (in/out/none). For example, the following code creates a KType instance representing List<String>:
val nonNullStringType = String::class.starProjectedType
val projection = KTypeProjection.invariant(nonNullStringType)
val listOfStrings = listClass.createType(listOf(projection))
Or, the following creates the type List<String>?:
val listOfStrings = listClass.createType(listOf(projection), nullable = true)
Both starProjectedType and createType are defined in package kotlin.reflect.full.
We're planning to introduce the possibility of getting a KType instance simply from a reified type parameter of an inline function which would help in some cases where the needed type is known statically, however currently it's not entirely clear if that's possible without major overhead. So, until that's implemented, please use the declarations explained above.