How are overridden properties handled in init blocks? - kotlin

I'm trying to understand why the following code throws:
open class Base(open val input: String) {
lateinit var derived: String
init {
derived = input.toUpperCase() // throws!
}
}
class Sub(override val input: String) : Base(input)
When invoking this code like this:
println(Sub("test").derived)
it throws an exception, because at the time toUpperCase is called, input resolves to null. I find this counter intuitive: I pass a non-null value to the primary constructor, yet in the init block of the super class it resolves to null?
I think I have a vague idea of what might be going on: since input serves both as a constructor argument as well as a property, the assignment internally calls this.input, but this isn't fully initialized yet. It's really odd: in the IntelliJ debugger, input resolves normally (to the value "test"), but as soon as I invoke the expression evaluation window and inspect input manually, it's suddenly null.
Assuming this is expected behavior, what do you recommend to do instead, i.e. when one needs to initialize fields derived from properties of the same class?
UPDATE:
I've posted two even more concise code snippets that illustrate where the confusion stems from:
https://gist.github.com/mttkay/9fbb0ddf72f471465afc
https://gist.github.com/mttkay/5dc9bde1006b70e1e8ba

The original example is equivalent to the following Java program:
class Base {
private String input;
private String derived;
Base(String input) {
this.input = input;
this.derived = getInput().toUpperCase(); // Initializes derived by calling an overridden method
}
public String getInput() {
return input;
}
}
class Derived extends Base {
private String input;
public Derived(String input) {
super(input); // Calls the superclass constructor, which tries to initialize derived
this.input = input; // Initializes the subclass field
}
#Override
public String getInput() {
return input; // Returns the value of the subclass field
}
}
The getInput() method is overridden in the Sub class, so the code calls Sub.getInput(). At this time, the constructor of the Sub class has not executed, so the backing field holding the value of Sub.input is still null. This is not a bug in Kotlin; you can easily run into the same problem in pure Java code.
The fix is to not override the property. (I've seen your comment, but this doesn't really explain why you think you need to override it.)

The confusion comes from the fact that you created two storages for the input value (fields in JVM). One is in base class, one in derived. When you are reading input value in base class, it calls virtual getInput method under the hood. getInput is overridden in derived class to return its own stored value, which is not initialised before base constructor is called. This is typical "virtual call in constructor" problem.
If you change derived class to actually use property of super type, everything is fine again.
class Sub(input: String) : Base(input) {
override val input : String
get() = super.input
}

Related

Easiest way to modify value passed to inline class constructor

I'm trying to use inline classes in Kotlin to create a class inlining the String class, such that if I have an instance of my class that it will always be true for the contained string that s == s.trim().
I was initially expecting there to be a straightforward way to do this, like perhaps:
#JvmInline
value class Trimmed private constructor(val str: String) : {
constructor(s : String) : super(s.trim())
}
but that doesn't work, and neither do the other direct approaches I considered ("this(s.trim())", etc.).
This problem has turned out to be surprisingly tricky:
Kotlin seems to provide no easy way to have the primary constructor filter or modify the data that is passed to the constructor of the contained String object.
Even if I make the primary constructor private, I can't declare another constructor with the same signature (taking a single String as a parameter).
If this were a normal (non-inlined) class, I could just set the value after superclass class construction (e.g. "init { str = str.trim() }", but since it's an inline class, I can't do that. ("this=this.trim()" doesn't work either, and String objects themselves are immutable so I can't change the contents of 'str'.)
I tried making the class constructor private and creating a factory function in the same file with the same name as the class, but then I couldn't call the class constructor from within the factory function due to access restrictions.
I then tried making the factory function within the class's companion object, but then Kotlin tried to make that function call itself recursively instead of calling the class's constructor. I wasn't able to find a way to syntactially disambiguate this. I managed to work around this by creating a file-private typealias to give another name for the class so I could call the constructor from within the factory function. (Annoyingly, I couldn't declare the typealias in the companion object next to the factory function: I had to declare it outside.)
This worked, but seemed ugly:
typealias Trimmed2 = Trimmed
#JvmInline
value class Trimmed private constructor(val str: String) {
init { assert(str == str.trim()) }
companion object {
// Kotlin won't let me put the typealias here. :-(
fun Trimmed(s: String): Trimmed = Trimmed2(s.trim()) // Don't want recursion here!
}
}
Another working solution is here, using a private constructor with a dummy argument. Of course Kotlin complained that the dummy argument was unused and so I had to put in a big (why is it so big?) annotation suppressing the warning, which is, again, ugly:
#JvmInline
value class Trimmed private constructor(val str: String) {
private constructor (untrimmed: String, #Suppress("UNUSED_PARAMETER") dummy: Unit) : this(untrimmed.trim())
init { assert(str == str.trim()) }
companion object {
fun Trimmed(s: String): Trimmed = Trimmed(s, Unit)
}
}
Is there a simpler, cleaner way to do this? For instance, a syntactic way to clarify to Kotlin that the companion function is trying to call the class constructor and not itself and so avoid the need for a dummy parameter?
Goals:
Code to construct instances of the class from outside this file should look like constructing an instance of a normal class: 'Trimmed("abc")', not using some factory function with a different name (e.g. "of" or "trimmedOf") or other alternate syntax.
It should be impossible to construct the object containing an untrimmed string. Outside code, and the Trimmed class itself, should be able to trust that if a Trimmed instance exists, that its contained str will be a trimmed string.

Subclass Parameter Name Overriding Superclass Val

Experienced with Java, but fairly new to Kotlin.
When the subclass param has same name as a superclass val... Android Studio does not throw validation error stating need for #Override annotation. However, attempting to access name from within Business references the param name rather than the superclass val (which feels like an override to me).
class Business(
val name: String
) {
// ...
}
class FirstBusiness(name: String) : Business(name) {
val test = name; // name referencing param name rather than super's name
}
Of course, I can just name the param something different, but I really just want to pass the name to the superclass... otherwise excluding any storage of it in FirstBusiness.
Am I overlooking something? I'm surprised that even if I don't declare FirstBusiness param name as a val/var, it seems to be overriding Business.name. I'm assuming the param isn't truly overriding the super val as the IDE isn't complaining... but why is the param the only suggestion instead of the super val?
Edit: I do notice different (more expected from my Java experience) behavior if I do the param-passing outside of the primary constructor design like so...
class FirstBusiness : Business {
constructor(name: String) : super(name)
fun thing() {
val v = name // now references super's name
}
}
Thank you!
Just like how you would do it in Java if you have shadowed the name of a superclass's field, you can clarify it with the super keyword.
class FirstBusiness(name: String) : Business(name) {
val test = super.name
}
In your case, it's not overriding the superclass's property. What's happening is that property initializers at the property declaration sites are considered part of the primary constructor's initialization block, so the constructor parameter is closer in scope than the superclass's property.
Suppose for a moment that these classes were defined in Java, and in the superclass you simply used a field instead of a getter:
public class Business {
public String name;
public Business(String name) {
this.name = name;
}
}
Then your code where you initialize your property at its declaration site is just like initializing a field from a constructor, like this in Java:
public class FirstBusiness extends Business {
private String test;
public FirstBusiness(String name) {
super(name);
this.test = name; // It's using the parameter, not the superclass's
// property, but the superclass property isn't overridden.
}
}

learn the syntax for constructors in Kotlin

I am learning Kotlin programming language perfectly. I try to write code in different patterns and try to understand. However, I did not understand the thing. Can you help me, please?
Here it is:
open class Parent {
open val foo = 1
init {
println(foo)
}
}
class Child: Parent() {
override val foo =2
}
fun main() {
Child()
}
In this code, 0 is the output. How will this be?
This is about the order of construction — and is a subtle gotcha that's easy to fall prey to.  (I'm afraid this answer is a bit long, but the issues here are well worth understanding.)
There are a few basic principles colliding here:
Superclass initialisation happens before subclass initialisation.  This includes code in constructors, code in init blocks, and property initialisers: all of that happens for a superclass before any in a subclass.
A Kotlin property consists of a getter method, a setter method (if it's a var), and a backing field (if needed).  This is why you can override properties; it means that the accessor method(s) are overridden.
All fields initially hold 0/false/null before they get initialised to any other value.  (Normally, you wouldn't get to see that, but this is one of those rare cases.  This differs from languages like C where if you don't explicitly initialise a field it can hold random values depending on what that memory was previously used for.)
From the first principle, when you call the Child() constructor, it will start off by calling the Parent() constructor.  That will set the superclass's foo field to 1, and then get the foo property and print it out.  After that, the Child initialisation happens, which in this case is simply setting its foo field to 2.
The gotcha here is that you effectively have two foos!
Parent defines a property called foo, and that gets accessor methods and a backing field.  But Child defines its own property called foo, overriding the one in Parent — that one overrides the accessor methods, and gets its own backing field as well.
Because of that override, when the Parent's init block refers to foo, it calls the getter method which Child overrides, to get the value of Child's backing field.  And that field hasn't been initialised yet!  So, as mentioned above, it's still holding its initial value of 0, which is the value that the Child getter returns, and hence the value that Parent constructor prints out.
So the real problem here is that you're accessing the subclass field before it's been initialised.  This question shows why that's a really bad idea!  As a general rule:
A constructor/initialiser should never access a method or property that could be overridden by a subclass.
And the IDE helps you out here: if you put your code into IntelliJ, you'll see that the usage of foo is marked with the warning ‘Accessing non-final property foo in constructor’.  That's telling you that this sort of problem is possible.
Of course, there are more subtle cases that an IDE might not be able to warn you about, such as if a constructor calls a non-open method that calls an open one.  So care is needed.
There are occasions when you might need to break that rule — but they're very rare, and you should check very carefully that nothing can go wrong (even if someone comes along later and creates a new subclass).  And you should make it very clear in comments/documentation what's going on and why it's needed.
Now, let's with java understand why. In Java, it's impossible to override fields and under the hood in Kotlin is the same. When you override a property, in fact, you override a getter, not a field. For instance, you can override a property that doesn't have a field with a property that has a field. That's totally legal. However, when both a property from a superclass and an overridden property in a subclass have fields, that might lead to unexpected results. Let's see what bytecode is generated for the Kotlin class in my example. As usual, I'll look at the corresponding Java code instead for simplicity.
public class Parent {
private final int foo = 1;
public int getFoo() {return foo;}
public Parent(){
System.out.println(getFoo());
}
}
public final class Child extends Parent {
private final int foo = 2;
public int getFoo() {return foo;}
}
public class Main
{
public static void main (String[] args) {
new Child();
}
}
Note two things here. First, the foo get to is trivial, so a field and a getter correspond to the full property. Then because the property is open and can be overridden in a subclass, its usage inside the class is compiled to a getter code, not a field code. Now, the generated code for the child class. Note that the overridden property in the parent class is also compiled to a field and a getter, and now it's another field. What happens when you create an instance of the child class? At first at the parent constructor is called, the parent constructor initializes the first fulfilled with one. But inside the init section, an overridden getter is called which calls get foo from the child class. Because the field in the child class is not yet initialized, 0 is returned. That's why 0 is printed here.
Please go through following points:
Initializer Blocks i.e. init {} block are called during an instance initialization. They are called after Primary Constructor.
In above code println(foo) is placed inside init block.
Hence, the value which gets printed i.e. 0 in this case, is the value before assignment statement open val foo = 1.
If you want the output to be 1 then make following changes:
open class Parent {
open var foo : Int = 0
init {
foo = 1
println(foo)
}
}
class Child: Parent() {
override var foo =2
}
fun main() {
Child()
}
And lastly, please go through this post. This will help you in getting better understanding of this area.

Variables not initialized properly when initializing it in an overriden abstract function called from constructor or init block

I hit a problem with some Kotlin code and I found out it was related to calling a method that assigns some variables from an init block (or a secondary constructor for that matter, either reproduces the problem).
MCVE:
abstract class Shader(/*Input arguments omitted for the sake of an MCVE*/){
init{
//Shader loading and attaching, not relevant
bindAttribs()//One of the abstract methods. In my actual program, this uses OpenGL to bind attributes
//GLSL program validation
getUniforms()//Same as the previous one: abstract method using GL calls to get uniforms. This gets locations so an integer is set (the problem)
}
abstract fun getUniforms();//This is the one causing problems
abstract fun bindAttribs();//This would to if primitives or non-lateinit vars are set
}
abstract class BoilerplateShader() : Shader(){
var loc_projectionMatrix: Int = 404//404 is an initial value. This can be anything though
var loc_transformationMatrix: Int = 404
var loc_viewMatrix: Int = 404
override fun getUniforms(){
//These would be grabbed by using glGetUniformLocations, but it's reproducable with static values as well
loc_projectionMatrix = 0
loc_transformationMatrix = 1
loc_viewMatrix = 2
println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
}
//debug method, only used to show the values
fun dump(){
println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
}
}
class TextureShader() : BoilerplateShader(){
override fun bindAttribs() {
//This doesn't cause a problem even though it's called from the init block, as nothing is assigned
//bindAttrib(0, "a_position");
//bindAttrib(1, "a_texCoord0");
}
}
//Other repetitive shaders, omitted for brevity
Then doing:
val tx = TextureShader()
tx.dump()
prints:
0, 1, 2
404, 404, 404
The print statements are called in order from getUniforms to the dump call at the end. It's assigned fine in the getUniforms method, but when calling them just a few milliseconds later, they're suddenly set to the default value of (in this case) 404. This value can be anything though, but I use 404 because that's a value I know I won't use for testing in this particular MCVE.
I'm using a system that relies heavily on abstract classes, but calling some of these methods (getUniforms is extremely important) is a must. If I add an init block in either BoilerplateShader or TextureShader with a call to getUniforms, it works fine. Doing a workaround with an init function (not an init block) called after object creation:
fun init(){
bindAttribs();
getUniforms();
}
works fine. But that would involve the created instance manually calls it:
val ts = TexturedShader();
ts.init();
ts.dump()
which isn't an option. Writing the code that causes problems in Kotlin in Java works like expected (considerably shortened code, but still reproducable):
abstract class Shader{
public Shader(){
getUniforms();
}
public abstract void getUniforms();
}
abstract class BoilerplateShader extends Shader{
int loc_projectionMatrix;//When this is initialized, it produces the same issue as Kotlin. But Java doesn't require the vars to be initialized when they're declared globally, so it doesn't cause a problem
public void getUniforms(){
loc_projectionMatrix = 1;
System.out.println(loc_projectionMatrix);
}
//and a dump method or any kind of basic print statement to print it after object creation
}
class TextureShader extends BoilerplateShader {
public TextureShader(){
super();
}
}
and printing the value of the variable after initialization of both the variable and the class prints 0, as expected.
Trying to reproduce the same thing with an object produces the same result as with numbers when the var isn't lateinit. So this:
var test: String = ""
prints:
0, 1, 2, test
404, 404, 404,
The last line is exactly as printed: the value if test is set to an empty String by default, so it shows up as empty.
But if the var is declared as a lateinit var:
lateinit var test: String
it prints:
0, 1, 2, test
404, 404, 404, test
I can't declare primitives with lateinit. And since it's called outside a constructor, it either needs to be initialized or be declared as lateinit.
So, is it possible to initialize primitives from an overridden abstract method without creating a function to call it?
Edit:
A comment suggested a factory method, but that's not going to work because of the abstraction. Since the attempted goal is to call the methods from the base class (Shader), and since abstract classes can't be initialized, factory methods won't work without creating a manual implementation in each class, which is overkill. And if the constructor is private to get it to work (avoid initialization outside factory methods), extending won't work (<init> is private in Shader).
So the constructors are forced to be public (whether the Shader class has a primary or secondary constructor, the child classes have to have a primary to initialize it) meaning the shaders can be created while bypassing the factory method. And, abstraction causes problems again, the factory method (having to be abstract) would be manually implemented in each child class, once again resulting in initialization and manually calling the init() method.
The question is still whether or not it's possible to make sure the non-lateinit and primitives are initialized when calling an abstract method from the constructor. Creating factory methods would be a perfect solution had there not been abstraction involved.
Note: The absolutely best idea is to avoid declaring objects/primitives in abstract functions called from the abstract class' constructor method, but there are cases where it's useful. Avoid it if possible.
The only workaround I found for this is using by lazy, since there are primitives involved and I can convert assignment to work in the blocks.
lateinit would have made it slightly easier, so creating object wrappers could of course be an option, but using by lazy works in my case.
Anyways, what's happening here is that the value assigned to the int in the constructor is later overridden by the fixed value. Pseudocode:
var x /* = 0 */
constructor() : super.constructor()//x is not initialized yet
super.constructor(){
overridden function();
}
abstract function()
overridden function() {
x = 4;
}
// The assignment if `= 0` takes place after the construction of the parent, setting x to 0 and overriding the value in the constructor
With lateinit, the problem is removed:
lateinit var x: Integer//x exists, but doesn't get a value. It's assigned later
constructor() : super.constructor()
super.constructor(){
overridden function()
}
abstract function()
overridden function(){
x = Integer(4);//using an object here since Kotlin doesn't support lateinit with primtives
}
//x, being lateinit and now initialized, doesn't get re-initialized by the declaration. x = 4 instead of 0, as in the first example
When I wrote the question, I thought Java worked differently. This was because I didn't initialize the variables there either (effectively, making them lateinit). When the class then is fully initialized, int x; doesn't get assigned a value. If it was declared as int x = 1234;, the same problem in Java occurs as here.
Now, the problem goes back to lateinit and primitives; primitives cannot be lateinit. A fairly basic solution is using a data class:
data class IntWrapper(var value: Int)
Since the value of data classes can be unpacked:
var (value) = intWrapperInstance//doing "var value = ..." sets value to the intWrapperInstance. With the parenthesis it works the same way as unpacking the values of a pair or triple, just with a single value.
Now, since there's an instance with an object (not a primitive), lateinit can be used. However, this isn't particularly efficient since it involves another object being created.
The only remaining option: by lazy.
Wherever it's possible to create initialization as a function, this is the best option. The code in the question was a simplified version of OpenGL shaders (more specifically, the locations for uniforms). Meaning this particular code is fairly easy to convert to a by lazy block:
val projectionMatrixLocation by lazy{
glGetUniformLocation(program, "projectionMatrix")
}
Depending on the case though, this might not be feasible. Especially since by lazy requires a val, which means it isn't possible to change it afterwards. This depends on the usage though, since it isn't a problem if it isn't going to change.

Calling a class's method as default arg in constructor

I'm constructing a class and then trying to call a member method of that class as a default value for one of the constructor args.
Why isn't this valid Kotlin?
// unresolved reference: defaultText
class MyThing(val text: String = defaultText()) {
fun defaultText() = "hi"
}
It's possible using two separate constructors in both Java and Kotlin, but then I lose the conciseness of default args.
class MyThing {
private val text: String
constructor(text: String) {
this.text = text
}
constructor() {
this.text = defaultText()
}
private fun defaultText(): String {
return "hi"
}
}
The biggest problem of having a constructor's default parameter expression call a member function of the same instance is that the default arguments are evaluated before the constructor is called.
Given that, such a member function would have to run on a completely un-initialized instance of the class (because even the super constructors will work after that, see this answer about the execution order).
Usually, member functions perform some logic taking the instance state into account, and having a member function run on an empty instance might break some of that logic (e.g. all fields will hold nulls, even the backing fields of Kotlin not-null properties). Overall, even when such calls do not fail at runtime, they are likely introduce subtle bugs, so using a completely uninitialized instance is prohibited.
With regard to the secondary constructor, well, at least it runs after the super constructor initializes some part of the instance, which is thus not completely empty, but it's up to you to make sure you don't use the parts of the class that are not initialized (if you do, you may again encounter a runtime failure or introduce a bug).
I'd rather suggest using a function of a companion object (those are initialized before the class is first used) for this purpose:
class MyThing(val text: String = defaultText()) {
companion object {
fun defaultText() = "hi"
}
}
Or even a top-level function:
fun defaultText() = "hi"
class MyThing(val text: String = defaultText())