Kotlin hierarchy: Storing child class in parent var - kotlin

Having a parent class named Shading, which is abstract and a child class named GradientShading, in Java it was so easy to store a child object into a variable of the parent type:
Shading act=null;
act=new GradienShading();
In kotlin I don't know how to do it, because this gives compilation error:
lateinit var act: Shading
act = GradienShading()
Type mismatch. Required: Shading Found: GradienShading
How can I achieve this in Kotlin?

Presumably you've not set up the type hierarchy correctly. Are you sure Shading in fact is a supertype of GradientShading?
The following compiles just fine on my machine.
open class Shading
class GradientShading: Shading()
class Example {
lateinit var act: Shading
fun test() {
act = GradientShading()
}
}

Related

Kotlin compile error using self generic type bound

Suppose I have the following code to simulate a state machine in Kotlin:
sealed interface State {
object A : State
object B: State
object C: State
object D: State
}
interface StateMachine<Self: StateMachine<Self, *>, T: State>
fun <S : StateMachine<S, State.A>> S.transitionX() = object : StateMachine<S, State.B> {}
fun <S: StateMachine<S, State.B>> S.transitionQ() = object : StateMachine<S, State.B> {}
object Start: StateMachine<Start, State.A>
fun main() {
val stateMachine = Start.transitionX().transitionQ()
}
However, this doesn't compile because
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public fun <S : StateMachine<TypeVariable(S), State.B>> TypeVariable(S).transitionQ(): StateMachine<TypeVariable(S), State.B> defined in root package in file Main.kt
which is probably because of the Self generic constraint.
Ideally, stateMachine should have a type StateMachine<StateMachine<Start, State.A>, State.B.
I was wondering if there's any way to fix the generic constraints so that this does compile? Note: I am aware that the Self generic parameter isn't actually needed for this state machine, but I'm just interested to see if this is actually possible.
I have tried a few different changes to the generic type bounds, but the closest I could get resulted in stateMachine just having a type of StateMachine<Start, State.B>, which isn't quite what I want. Other changes I've made have just caused the Kotlin Finite Bound Restriction error.
Any help is appreciated, thanks!
I don't know what you're trying to do with the self type, so it's hard to say whether these solutions will actually work for your use case.
You don't need to involve new generics in your function itself, only within its receiver and return type. So you can use * types to represent Self. This of course assumes that the Self type isn't needed outside its own private implementation, like if you had a fun copy(): Self. It's impossible to define an implementation of your interface using an anonymous object, since it has to have a class name to be able to describe its own self type. So you either need to define it with a named object outside the function, or by defining a class inside the function and returning an instance of it.
fun StateMachine<*, State.A>.transitionX(): StateMachine<*, State.B> {
class Impl: StateMachine<Impl, State.B>{
}
return Impl()
}
You could define explicit interfaces for all the possible children and use those. Since State is sealed, this is possible.
interface AStateMachine: StateMachine<AStateMachine, State.A>
interface BStateMachine: StateMachine<BStateMachine, State.B>
interface CStateMachine: StateMachine<CStateMachine, State.C>
interface DStateMachine: StateMachine<DStateMachine, State.D>
fun AStateMachine.transitionX() = object : BStateMachine {}
fun BStateMachine.transitionQ() = object : CStateMachine {}

Subtypes not being recognized in Subclasses

I have the following code setup;
abstract class GenericQuestionEditor() {
protected abstract var data: GenericQuestionData
}
but then when I create EditorSimple() it throws an error when I try to set data to DataSimple(), why?
class EditorSimple(): GenericQuestionEditor() {
override var data = DataSimple()
}
my GenericQeustionData and DataSimple() are setup like this;
abstract class GenericQuestionData {}
class DataSimple: GenericQuestionData() {}
it doesn't complain if I create this function in GenericQuestionEditor()
fun test() {
data = DataSimple()
}
Why do I get an error on data in EditorSimple()? It should recognize it as a subtype and it should be allowed as I understand.
I feel like the answer is found in the kotlin documentation but i'm not sure how to configure it in this case since they are not passed values or part of a collection.
You need to specify the type explicitly:
class EditorSimple(): GenericQuestionEditor() {
override var data: GenericQuestionData = DataSimple()
}
Without the type annotation, the type of data would be inferred to be DataSimple, which doesn't match the type of its super class' data. Even though the types are related, you can't override writable a property with a subtype. Imagine if I did:
class SomeOtherData: GenericQuestionData()
val editor: GenericQuestionEditor = EditorSimple()
editor.data = SomeOtherData() // data is of type GenericQuestionData, so I should be able to do this
But, editor actually has a EditorSimple, which can only store DataSimple objects in data!

::property.isInitialized cannot differentiate between method and property with same name

I'm creating a builder (for Java compat), where context is both a private property and public method.
private lateinit var context: Context
fun context(appContext: Context) = apply {
context = appContext
}
fun build(): MySdk {
// this::context fails to compile because it cannot differentiate between the
// method `context()` vs property `context`
require(this::context.isInitialized) {
"context == null"
}
But I get a compilation issue for ::context.isInitialized, because it cannot differentiate between the method context() vs property context
Does Kotlin have a workaround for this? or am I forced to use unique property/method names?
This is a case of overload resolution ambiguity and the kotlin compiler is unable to identify whether you are using the property or the method.
This is because of callable references (::) . Internally when you are using the callable references it calls a method.
Callable references : References to functions, properties, and
constructors, apart from introspecting the program structure, can also
be called or used as instances of function types.
The common supertype for all callable references is KCallable, where R is the return value type, which is the property type for properties, and the constructed type for constructors.
KCallable<out R> // supertype for all callable references
So, for function the type is KFunction and for properties the type is KProperty
interface KFunction<out R> : KCallable<R>, Function<R> (source)
interface KProperty<out R> : KCallable<R> (source)
When you use a function like :
fun context(appContext: Context) = apply {
context = appContext
}
It can be used as a Function reference
::context // This is a Function reference i.e. KFunction
When you use a property reference, like
private lateinit var context: Context
fun something(){
::context // this is a property reference, KProperty
}
A property reference can be used where a function with one parameter is expected:
val strs = listOf("a", "bc", "def")
println(strs.map(String::length))
So, its not that Kotlin forces you to use different property and function names("although it is not recommended"). Its just that its unable to differentiate in this case as
Both are KCallable and have the same name
A property reference can be used where a function with one parameter is expected
You can resolve the ambiguity between the property and the method by giving the expected type:
val prop: kotlin.reflect.KProperty0<*> = this::context
Alas, prop.isInitialized then gives a compilation error:
This declaration can only be called on a property literal (e.g. 'Foo::bar')
So this doesn't appear to be possible currently. OTOH, since the error shows isInitialized is already handled specially by the compiler, it's likely possible to fix; I suggest reporting it on http://youtrack.jetbrains.com/ (after searching for duplicates).

Getting class of lateinit property in Kotlin

Is it somehow possible to get ::class.java from Kotlin lateinit property before it is initialized?
Logically it should work - I'm trying to obtain a class not a value, but in reality it fails with uninitialized property access exception.
Note that the property I'm trying to get class of is in generic class and its type is one of generic parameters:
abstract class MVIFragment<
out INTERACTOR : MVIInteractor<UINTERFACE>,
UINTERFACE : MVIUIInterface,
MODEL : MVIViewModel
>
: Fragment(), MVIUIInterface, KodeinAware {
lateinit var viewModel: MODEL
I need the class to create an instance of ViewModel
viewModel = ViewModelProviders.of(this).get(viewModel::class.java)
Of course I can't do:
viewModel = ViewModelProviders.of(this).get(MODEL::class.java)
Any solution for that?
Due to type erasure, generic types are not known at runtime. That's just how Java/JVM works, and Kotlin doesn't attempt to magically work around it. (Unlike Scala, which has implicit magic which works magically, except when it doesn't.)
You will have to pass it along from some context where the type is statically determined, e.g.
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
}
Container(String::class.java)
You can use an inline function with reified types to hide this ugliness,
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
companion object {
inline operator fun <reified T : Any> invoke() = Container(T::class.java)
}
}
Container<String>()
which really compiles to the same thing. (The <String> can be omitted if type inference can determine it from context.)
In your case, it won't be possible to do this trick in the base (abstract) class; it has to be done on the concrete types.

Java allow to access Kotlin's base variable through it's child, but not Kotlin, why?

I have a class as below
open class KotlinBase {
companion object {
const val TAG = "testing"
}
}
And a child of it as
class KotlinChild : KotlinBase()
When I try to access TAG from a Java class, I could either
public class JavaOther {
String test1 = KotlinBase.TAG; // This is okay
String test2 = KotlinChild.TAG; // This is okay
}
However, when accessing from Kotlin class, I can't access through the Child.
class KotlinOther {
val test1 = KotlinChild.TAG // Compile/Syntax error
val test2 = KotlinBase.TAG // This is okay
}
Why can't my Kotlin class access the inherited variable TAG through KotlinChild?
It's a design decision allowing you to avoid ambiguities. - child classes can have their own companion objects with fields/methods having same names as those in the parent.
By restricting access to companions only through the actual class, problems with ambiguous field/method shadowing do not exist anymore.
Also, companion objects are not static members known from other languages. Although, the majority of use cases overlap.
Additionally, remember that
KotlinBase.TAG
is a shortcut for:
KotlinBase.Companion.TAG