1

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.

6
  • Isn't the class method called inside the super constructor? If it is, then the reason is that the super constructor is called before the properties are initialized. Commented Mar 24, 2017 at 16:49
  • Yeah I thought that and checked it and I don't think it does. This is a bit of a mystery to me. Commented Mar 24, 2017 at 16:59
  • I don't know much about Kotlin, can you identify the variables with keywords, either private or public, outside the method and see if it works? Commented Mar 24, 2017 at 17:01
  • @hotkey No, it doesn't.initializePrograms() gets 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. Commented Mar 24, 2017 at 17:16
  • @In-youngChoung, you can check out the parallel java code (it's referenced in the parenthesis) Commented Mar 24, 2017 at 17:17

1 Answer 1

1

Reason

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"});
   ...
}

Solution

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);
   }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.