Reputation: 7190
In one program of mine I got a null exception and debugging the code I found out it was because one of my String
array (java):
val FRAGMENTS = arrayOf("phong-lighting", "phong-only", "blinn-lighting", "blinn-only")
was not yet initialized when I needed it in a successive class method (java):
fun initializePrograms(gl: GL3) {
programs = Array(LightingModel.MAX, {
ProgramPairs(
ProgramData(gl, "pn.vert", FRAGMENTS[it] + ".frag"),
ProgramData(gl, "pcn.vert", FRAGMENTS[it] + ".frag"))
})
unlit = UnlitProgData(gl, "pos-transform.vert", "uniform-color.frag")
}
If I move it inside:
fun initializePrograms(gl: GL3) {
val FRAGMENTS = arrayOf("phong-lighting", "phong-only", "blinn-lighting", "blinn-only")
...
}
Then everything fine.. why?
Ps: same code and same behavious also in java
Edit: don't get confused, that init
is not the class init
, it extends the Framework method here
Edit2: initializePrograms()
doesn't get called from the super constructor. It's called from init(GL3 gl)
which override Framework.init(GL3 gl) which gets called from Framework.init(GLAutoDrawable autoDrawable), which shall be called from the Animator just once at begin which should be another thread.
Upvotes: 1
Views: 133
Reputation: 10713
If method initializePrograms
is invoked in the superclass constructor, the crash is an expected behavior. Properties of the class are initialized after object is constructed, so they are uninitialized until then.
In that case, because the arrayOf
function is an inline function, it is clearly visible on decompiled class:
public final class Test {
@NotNull
private final String[] FRAGMENTS;
...
public Test() {
super();
String[] elements$iv = new String[]{"phong-lighting", "phong-only", "blinn-lighting", "blinn-only"};
Object[] var4 = (Object[])elements$iv;
this.FRAGMENTS = (String[])var4;
}
}
notice the constructor of Test
class and how properties are initialized after call to super()
.
Note that if you would use not-inline function to initialize that property (for example listOf
) the initialization will be joined with declaration, but that is effectively the same thing, just not as explicit. In Java this field would also be initialized after constructor has finished.
public final class Test {
@NotNull
private final List FRAGMENTS = CollectionsKt.listOf(new String[]{"phong-lighting", "phong-only", "blinn-lighting", "blinn-only"});
...
}
Most likely what you're trying to achieve (considering the all caps FRAGMENTS
) is to declare then as a static field. In Kotlin you can do that for example by nesting it in a companion object
in particular class.
class Test {
...
companion object {
val FRAGMENTS = arrayOf("phong-lighting", "phong-only", "blinn-lighting", "blinn-only")
}
}
then, as you can see on decompiled class, it is declared as a static field and initialized in static
block:
public final class Test {
@NotNull
private static final String[] FRAGMENTS;
...
static {
String[] elements$iv = new String[]{"phong-lighting", "phong-only", "blinn-lighting", "blinn-only"};
FRAGMENTS = (String[])((Object[])elements$iv);
}
}
Upvotes: 1