Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access function before calling superclass constructor in Kotlin data class

I'm using data classes in Kotlin to significantly reduce the amount of Java code I would otherwise have to write.

However, in one of my Java classes, I'm not sure what to do to achieve the same result in Kotlin.

My Java class looks a bit like this:

public class DataObject {

    private int mId;
    private String mName;

    public DataObject(int id, String name) {
        mId = id;
        mName = name;
    }

    public DataObject(Context context, int id) {
        mId = id;
        Cursor cursor = ...
        cursor.moveToFirst();
        mName = cursor.getString(...);
        cursor.close();
    }

    public int getId() {
        return mId;
    }

    public String getName() {
        return mName;
    }

}

I've tried to rewrite it in Kotlin, and so far I have this:

data class DataObject(val id: Int, val name: String) {

    constructor(context: Context, id: Int) : this(id, fetchName(context))

    private fun fetchName(context: Context): String {
        val cursor = ...
        cursor.moveToFirst()
        val name = cursor.getString(...)
        cursor.close()
        return name
    }

}

But my IDE (Android Studio) is underlining the part where I call fetchName(context) in my constructor in red. It displays the following message:

Cannot access fetchName before superclass constructor has been called

How should I resolve this issue?

like image 860
Farbod Salamat-Zadeh Avatar asked Jul 20 '16 12:07

Farbod Salamat-Zadeh


2 Answers

Another approach is to use companion object. This will allow you to call the function outside of the data class as well (maybe not useful in your particular case)

data class DataObject(val id: Int, val name: String) {

  constructor(context: Context, id: Int) : this(id, fetchName(context))

  companion object {

    fun fetchName(context: Context): String {
      val cursor = ...
      ...
      return name
    }
  }
}
like image 86
Alexander Larin Avatar answered Nov 11 '22 04:11

Alexander Larin


You can only use member functions on a fully constructed objects. One way to work around that is to use private extension function or simply a function to fetch name:

private fun Context.fetchName(): String {
    ///...
    return cursor.getString(1)
}

data class DataObject(val id: Int, val name: String) {
    constructor(context: Context, id: Int) : this(id, context.fetchName())
}

Although I do think that using Cursor is a bit too heavy job for constructor. I'd use separate Factory like so:

data class DataObject(val id: Int, val name: String) {
    object FromCursorFactory {
        fun create(id: Int, context: Context): DataObject {
            val name = context.fetchName()
            return DataObject(id, name)
        }
    }
}

Further reading:

  • Is doing a lot in constructors bad?
  • Why is it considered bad practice to call a method from within a constructor?
like image 19
miensol Avatar answered Nov 11 '22 05:11

miensol