Kotlin type inference for multiple possible types? - kotlin

I have a function that takes parameter metadata of two possible types: Metadata1 or Metadata2. I'm trying to write a utility function that can be used for both since there is a ton of code reuse. Both of them have a list of DataPoint objects, each of which has name() method.
I thought in my code Kotlin would use type inference to know that dataPoints can only be one of two types that both have DataPoint.name() method, but I'm getting "unresolved reference: name". How can I make this function generic enough to apply to both Metadata1 and Metadata2?
var dataPoints: List<Any>
if (metadata is Metadata1) {
dataPoints = metadata.metadata1().dataPoints()
} else {
dataPoints = (metadata as Metadata2).metadata2().dataPoints()
}
if (data.size > 1) {
textView.test = dataPoints.fold("")
{ x, dataPoint ->
x + dataPoint.name() + " \n" // unresolved reference: name
}
}

This isn't unique to Kotlin, statically typed OOP languages work like this.
Your dataPoints is of type List<Any> and Any does not have a name() function. You're not showing a lot of code so I can't tell what kind of objects you have.
This is about run-time vs compile-time. The compiler can't predict what types you're going to put into your List<Any> at runtime and so the only functions you can call on its members are functions that belong to the Any class. Imagine if that list contained an object that didn't have a name() function. If the compiler allowed you to call name() then you'd have a run-time crash. This is why you get a compiler-time error when you try.
If you have two different types of objects that goes in the list, one way would be to make an interface that they both implement with shared methods in the interface. Which would look something like this:
interface Name {
fun name()
}
Change dataPoints to List<Name>, have your data classes implement that, and now dataPoint.name() compiles because the only objects allowed in the list are objects of type Name with a name() function.
var dataPoints: List<Name>
if (metadata is Metadata1) {
dataPoints = metadata.metadata1().dataPoints()
} else {
dataPoints = (metadata as Metadata2).metadata2().dataPoints()
}
if (data.size > 1) {
textView.test = dataPoints.fold("")
{ x, dataPoint ->
x + dataPoint.name() + " \n" // Compiles now
}
}
You have a similar problem with your Metadata1 and Metadata2 classes, they should probably implement an interface or extend a super class.

Related

Kotlin Native Initialize Array of Struct

In Kotlin/Native, what is the correct way to create and initialize an array of a structure? My code interfaces with a C library that defines the relevant structures as:
typedef struct VkDeviceQueueCreateInfo {
...
} VkDeviceQueueCreateInfo;
typedef struct VkDeviceCreateInfo {
...
uint32_t queueCreateInfoCount;
const VkDeviceQueueCreateInfo* pQueueCreateInfos;
...
} VkDeviceCreateInfo;
I've created wrapper classes DeviceQueueCreateInfo and DeviceCreateInfo. The Kotlin bindings are generated as classes inheriting from CStructVar and used like this:
class DeviceQueueCreateInfo(...) {
// Allocates in `scope` and fills a `VkDeviceQueueCreateInfo`
fun toRaw(scope: MemScope): VkDeviceQueueCreateInfo = ...
}
class DeviceCreateInfo(val queueCreateInfos: List<DeviceQueueCreateInfo>) {
// Allocates in `scope` and fills a `VkDeviceCreateInfo`
fun toRaw(scope: MemScope) = with(scope) {
alloc<VkDeviceCreateInfo>().also {
it.queueCreateInfoCount = queueCreateInfos.size.toUInt()
it.pQueueCreateInfos = ??? // Allocate array of struct in `scope`
}
}
}
I've added a ??? to the code to show where I'm having trouble. Kotlin NativePlacement has allocArray<T>(length: Int), so that was obviously my first stop:
it.pQueueCreateInfos = allocArray(queueCreateInfos.size)
And then to initialize them I tried:
it.pQueueCreateInfos = allocArray<VkDeviceQueueCreateInfo>(queueCreateInfos.size)
.also { arr ->
queueCreateInfos.forEachIndexed { index, x -> arr[index] = x.toRaw(scope) }
}
However, this fails to compile with error No set method providing array access at arr[index] = x. I wrote the following code which compiles and runs as expected:
val floats = listOf(1f, 2f, 3f)
allocArray<FloatVar>(floats.size).also { arr ->
floats.forEachIndexed { index, x -> arr[index] = x }
}
The code is identical apart from the type used, leading me to believe that I was perhaps trying to assign to an rvalue. I went looking for VkDeviceQueueCreateInfoVar only to find this:
Also, any C type has the Kotlin type representing the lvalue of this type, i.e., the value located in memory rather than a simple immutable self-contained value. Think C++ references, as a similar concept. For structs (and typedefs to structs) this representation is the main one and has the same name as the struct itself, for Kotlin enums it is named ${type}Var, for CPointer it is CPointerVar, and for most other types it is ${type}Var.
This states that for structs, the lvalue representation has the same name as the struct (no Var suffix)... so VkDeviceQueueCreateInfo should represent an assignable lvalue, and I'm confused as to why I am unable to assign values to my array. It occurs to me that Kotlin's assignment does something very different to a C assignment, but I had assumed there would be an idiomatic way to perform a structure assignment.
I've looked through the other overloads and methods in NativePlacement to find one that allows me to initialize the values in the newly created array, and I found allocArray<T>(length: Long, initializer: T.(index: Long)->Unit), but this seems to suffer from the same problem.
How do I allocate and initialize an array of structures through cinterop?

Generic variance type parameter(Kotlin)

I do not fully understand how variance in Generics work. In the code below the classes are as follows Any -> Mammals -> Cats. Any is the supertype, there is a parameter called from in the copy function
From what I understand about the out and in keywords, out allows reference to any of it's subtype, can only be produced not consumed.
in allows reference to any of it's supertype, can only be consumed not produced.
However in the copytest function we are instantiating the function copy. I gave it a catlist1 argument in the from parameter. Since the parameter has an out keyword wouldn't it mean that we can only input parameters that are a subtype of catlist2?
To top of my confusion I have seen many conflicting definitions, for instance , In Kotlin, we can use the out keyword on the generic type which means we can assign this reference to any of its supertypes.
Now I am really confused could anybody guide me on how all of these works? Preferably from scratch, thanks!
class list2<ITEM>{
val data = mutableListOf<ITEM>()
fun get(n:Int):ITEM = data[n]
fun add(Item:ITEM){data.add(Item)}
}
fun <T> Copy(from: list2<out T>, to:list2<T>){
}
fun copytest(){
val catlist1 = list2<Cat>()
val catlist2 = list2<Cat>()
val mammallist = list2<Mammal>()
Copy(catlist1,mammallist)
}
I think maybe you're mixing up class-declaration-site generics and use-site generics.
Class-declaration-site generics
Defined at the class declaration site with covariant out, it is true you cannot use the generic type as the type of a function parameter for any functions in the class.
class MyList<out T>(
private val items: Array<T>
) {
fun pullRandomItem(): T { // allowed
return items.random()
}
fun addItem(item: T) { // Not allowed by compiler!
// ...
}
}
// Reason:
val cowList = MyList<Cow>(arrayOf(Cow()))
// The declaration site out covariance allows us to up-cast to a more general type.
// It makes logical sense, any cow you pull out of the original list qualifies as an animal.
val animalList: MyList<Animal> = cowList
// If it let us put an item in, though:
animalList.addItem(Horse())
// Now there's a horse in the cow list. That doesn't make logical sense
cowList.pullRandomItem() // Might return a Horse, impossible!
It is not logical to say, "I'm going to put a horse in a list that may have the requirement that all items retrieved from it must be cows."
Use-site generics
This has nothing to do with the class level restriction. It's only describing what kind of input the function gets. It is perfectly logical to say, "my function does something with a container that I'm going to pull something out of".
// Given a class with no declaration-site covariance of contravariance:
class Bag<T: Any>(var contents: T?)
// This function will take any bag of food as a parameter. Inside the function, it will
// only get things out of the bag. It won't put things in it. This makes it possible
// to pass a Bag of Chips or a Bag of Pretzels
fun eatBagContents(bagOfAnything: Bag<out Food>) {
eat(bagOfAnything.contents) // we know the contents are food so this is OK
bagOfAnything.contents = myChips // Not allowed! we don't know what kind of stuff
// this bag is permitted to contain
}
// If we didn't define the function with "out"
fun eatBagContentsAndPutInSomething(bagOfAnything: Bag<Food>) {
eat(bagOfAnything.contents) // this is fine, we know it's food
bagOfAnything.contents = myChips // this is fine, the bag can hold any kind of Food
}
// but now you cannot do this
val myBagOfPretzels: Bag<Pretzels> = Bag(somePretzels)
eatBagContentsAndPutInSomething(myBagOfPretzels) // Not allowed! This function would
// try to put chips in this pretzels-only bag.
Combining both
What could be confusing to you is if you saw an example that combines both of the above. You can have a class where T is a declaration site type, but the class has functions where there are input parameters where T is part of the definition of what parameters the function can take. For example:
abstract class ComplicatedCopier<T> {
abstract fun createCopy(item: T): T
fun createCopiesFromBagToAnother(copyFrom: Bag<out T>, copyTo: Bag<in T>) {
val originalItem = copyFrom.contents
val copiedItem = createCopy(originalItem)
copyTo.contents = copiedItem
}
}
This logically makes sense since the class generic type has no variance restriction at the declaration site. This function has one bag that it's allowed to take items out of, and one bag that it's allowed to put items into. These in and out keywords make it more permissive of what types of bags you can pass to it, but it limits what you're allowed to do with each of those bags inside the function.

Access Implementation's property on variable of type Interface

I'm trying to access the delegate of the property (id) of a class (FooImpl). The problem is, this class implements an interface (Foo), and the property in question overrides a property of this interface. The delegate only exists in the class (not that it could exist in the interface).
The problem is that using the :: operator on a variable of type Foo always returns the property of Foo, not that of the actual instance. The problem in code:
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
interface Foo {
val id: Int
}
class FooImpl(
id: Int,
) : Foo {
override val id: Int by lazy { id }
}
val <T> KProperty<T>.hasDelegate: Boolean
get() = apply { isAccessible = true }.let { (it as KProperty0<T>).getDelegate() != null }
fun main() {
val foo: Foo = FooImpl(1)
println("foo::id.hasDelegate = ${foo::id.hasDelegate}")
println("(foo as FooImpl)::id.hasDelegate = ${(foo as FooImpl)::id.hasDelegate}")
}
This prints:
foo::id.hasDelegate = false
(foo as FooImpl)::id.hasDelegate = true
But this requires compile-time knowledge of the correct implementation. What I'm looking for is accessing the correct propert without having to specify FooImpl there.
The information is present at runtime because the least (!) intrusive workaround I have found so far is adding fun idProp(): KProperty0<*> to Foo and override fun idProp() = ::id to FooImpl and accessing the property using that.
Is there any better way than that?
I came up with this, but I don't know if there's a better way. The problem to work around is that getDelegate() has to return an actual instance of the delegate, so you need an instance of the class to be able to retrieve a delegate instance. It would really be nice if there was a hasDelegate property built in. Your version of hasDelegate will crash from the cast on unbound KProperty1's, which is all we have to work with when the specific class is unknown.
So to retrieve the delegate instance, we need to do search the class instance's member properties by name, which gives us a KProperty with covariant class type of the super-class type. Since it's covariant, we can call a consuming function like getDelegate() without casting to the invariant type. I think this logically should be safe, since we are passing an instance that we know has the matching type for the ::class that we retrieved the property with.
#Suppress("UNCHECKED_CAST")
fun <T: Any> KProperty1<T, *>.isDelegated(instance: T): Boolean =
(instance::class.memberProperties.first { it.name == name } as KProperty1<T, *>).run {
isAccessible = true
getDelegate(instance) != null
}
fun main() {
val foo: Foo = Foo2()
println("foo::id.hasDelegate = ${Foo::id.isDelegated(foo)}")
}
The problem here is that the owner of the property is resolved on compile time, not on runtime. When you do foo::id then foo (so FooImpl) become its bound receiver, but owner is still resolved to Foo. To fix this we wound need to "cast" property to another owner. Unfortunately, I didn't find a straightforward way to do this.
One solution I found is to use foo::class instead of foo::id as it resolves KClass on runtime, not on compile time. Then I came up with almost exactly the same code as #Tenfour04.
But if you don't mind using Kotlin internals that are public and not protected with any annotation, you can use much cleaner solution:
val KProperty0<*>.hasDelegate: Boolean
get() = apply { isAccessible = true }.getDelegate() != null
fun KProperty0<*>.castToRuntimeType(): KProperty0<*> {
require(this is PropertyReference0)
return PropertyReference0Impl(boundReceiver, boundReceiver::class.java, name, signature, 0)
}
fun main() {
val foo: Foo = FooImpl(1)
println(foo::id.castToRuntimeType().hasDelegate) // true
}
We basically create a new instance of KProperty, copying all its data, but changing the owner to the same type as its bound receiver. As a result, we "cast" it to the runtime type. This is much simpler and it is also cleaner because we separated property casting and checking for a delegate.
Unfortunately, I think Kotlin reflection API is still missing a lot of features. There should be hasDelegate() function, so we don't have to provide receivers, which is not really needed to check if property is delegated. It should be possible to cast KProperty to another type. It should be possible to create bound properties with some API call. But first of all, it should be possible to do something like: Foo::id(foo), so create KProperty of the runtime type of foo. And so on.

Specifying a function with templates that takes and returns an arbitrary class

I'm interested in defining a function that given a class variable, generates and a new instance of the class object with a randomly selected member attribute mutated.
Context: Consider an instance, circle1, of some class, Circle, has attributes color and radius. These attributes are assigned values of red and 5, respectively. The function in question, mutate, must accept circle1 as an argument, but reject non-class arguments.
For other data types, templates provide an answer in this context. That is, templates may be used to specify generic instances of functions that can accept arguments of multiple types.
How can a generic function that accepts (and returns) an instance of any class be defined using templates?
In general, if you need to restrict what a template can take, you use template constraints. e.g.
import std.traits : isIntegral;
auto foo(T)(T t)
if(isIntegeral!T)
{
...
}
or
import std.functional : binaryFun;
auto foo(alias pred, T, U)(T t, U u)
if(is(typeof(binaryFun!pred(t, u.bar())) == bool)
{
...
}
As long the condition can be checked at compile time, you can test pretty much anything. And it can be used for function overloading as well (e.g. std.algorithm.searching.find has quite a few overloads all of which are differentiated by template constraint). The built-in __traits, the eponymous templates in std.traits, and is expressions provide quite a few tools for testing stuff at compile time and then using that information in template constraints or static if conditions.
If you specifically want to test whether something is a class, then use an is expression with == class. e.g.
auto foo(T)(T t)
if(is(T == class))
{
...
}
In general though, you'll probably want to use more specific conditions such as __traits(compiles, MyType result = t.foo(22)) or is(typeof(t.foo(22)) == MyType). So, you could have something like
auto mutate(T)(T t)
if(is(T == class) &&
__traits(compiles, t.color = red) &&
__traits(compiles, t.radius = 5))
{
...
}
If the condition is something that you want to reuse, then it can make sense to create an eponymous template - which is what's done in Phobos in places like std.range.primitives and std.range.traits. For instance, to test for an input range, std.range.primitives.isInputRange looks something like
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r = R.init; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
Then code that requires an input range can use that. So, lots of functions in Phobos have stuff like
auto foo(R)(R range)
if(isInputRange!R)
{
...
}
A more concrete example would be this overload of find:
InputRange find(alias pred = "a == b", InputRange, Element)
(InputRange haystack, Element needle)
if(isInputRange!InputRange &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
{
...
}
Ali Çehreli's book, Programming in D, has several relevant chapters, including:
http://ddili.org/ders/d.en/templates.html
http://ddili.org/ders/d.en/cond_comp.html
http://ddili.org/ders/d.en/is_expr.html
http://ddili.org/ders/d.en/templates_more.html

Scala class inheritance

Tagged as homework.
I'm having trouble in the object oriented world while trying to implement a class.
I'm implenting various functions to take action on lists, that I'm using to mock a set.
I'm not too worried about my logic on how to find union, for example, but really just the structure.
For eg:
abstract class parentSet[T] protected () {
def union(other:parentSet[T]):parentSet[T]
}
Now I want a new class extending parentSet:
class childSet[T] private (l: List[T]) extends parentSet[T] {
def this() = this(List())
private val elems = l
val toList = List[T] => new List(l)
def union(other:parentSet[T]):childSet[T] = {
for (i <- this.toList) {
if (other contains i) {}
else {l :: i}
}
return l
}
}
Upon compiling, I receive errors such that type childSet isn't found in def union, nor is type T to keep it parametric. Also, I assume my toList isn't correct as it complains that it isn't a member of the object; to name a few.
Where in my syntax am I wrong?
EDIT
Now I've got that figured out:
def U(other:parentSet[T]):childSet[T] = {
var w = other.toList
for (i <- this.toList) {
if (!(other contains i)) {w = i::w}
}
return new childSet(w)
}
Now, I'm trying to do the same operations with map, and this is what I'm working on/with:
def U(other:parentSet[T]):MapSet[T] = {
var a = Map[T,Unit]
for (i <- this.toList) {
if (!(other contains i)) {a = a + (i->())}
}
return new MapSet(elems + (a->()))
}
I still want to use toList to make it easily traversable, but I'm still getting type errors while messing with maps..
This code has a few problems:
It seems that you are not realizing that List[T] is an immutable type, meaning you cannot change its value once created. So if you have a List[T] and you call the :: method to prepend a value, the function returns a new list and leaves your existing one unchanged. Scala has mutable collections such as ListBuffer which may behave more like you expect. So when you return l, you're actually returning the original list.
Also, you have the order wrong in using ::. It should go i :: l, since :: is a right-binding function (because it ends with a :).
Lastly, in your union method you are doing (other contains i). Maybe it's just the Scala syntax that's confusing you, but this is the same as doing (other.contains(i)) and clearly contains is not a defined method of parentSet. It is a method on the List[T] type, but you're not calling contains on a list.
You tagged this as homework so I'm not going to fix your code, but I think you should
Look at some examples of correct Scala code involving lists, try here for starters
Play around in the Scala REPL and try creating and working with some lists, so you get a feel for how immutable collections work.
To answer your direct question, even though childSet is inheriting parentSet the original method specify parentSet as the return type and not childSet. You can either only use parentSet as the type OR you could specify the return type to be anything that inherits parentSet.