Delegation to instance fields/whatever

class PorterConfiguration(val file: File) : Configuration by config {
	lateinit var config: FileConfiguration private set

…Oh, wait. Nope. Kotlin didn’t like that. Let’s try again…

class PorterConfiguration(val file: File) : Configuration {
	lateinit var config: FileConfiguration private set

	//<editor-fold desc="...since Kotlin won't let me use "Configuration by config"...">
	// @formatter:off
	@Suppress("KDocMissingDocumentation")
	override fun isSet(path: String?): Boolean = config.isSet(path)
	@Suppress("KDocMissingDocumentation")
	override fun isVector(path: String?): Boolean = config.isVector(path)
	@Suppress("KDocMissingDocumentation")
	override fun getFloatList(path: String?): MutableList<Float> = config.getFloatList(path)
	@Suppress("KDocMissingDocumentation")
	override fun getVector(path: String?): Vector = config.getVector(path)
	@Suppress("KDocMissingDocumentation")
	override fun getVector(path: String?, def: Vector?): Vector = config.getVector(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun getLong(path: String?): Long = config.getLong(path)
	@Suppress("KDocMissingDocumentation")
	override fun getLong(path: String?, def: Long): Long = config.getLong(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun getItemStack(path: String?): ItemStack = config.getItemStack(path)
	@Suppress("KDocMissingDocumentation")
	override fun getItemStack(path: String?, def: ItemStack?): ItemStack = config.getItemStack(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun isList(path: String?): Boolean = config.isList(path)
	@Suppress("KDocMissingDocumentation", "UsePropertyAccessSyntax")
	override fun setDefaults(defaults: Configuration?) = config.setDefaults(defaults)
	@Suppress("KDocMissingDocumentation", "UsePropertyAccessSyntax")
	override fun getDefaultSection(): ConfigurationSection = config.getDefaultSection()
	@Suppress("KDocMissingDocumentation")
	override fun isInt(path: String?): Boolean = config.isInt(path)
	@Suppress("KDocMissingDocumentation")
	override fun getBoolean(path: String?): Boolean = config.getBoolean(path)
	@Suppress("KDocMissingDocumentation")
	override fun getBoolean(path: String?, def: Boolean): Boolean = config.getBoolean(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun getColor(path: String?): Color = config.getColor(path)
	@Suppress("KDocMissingDocumentation")
	override fun getColor(path: String?, def: Color?): Color = config.getColor(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun isItemStack(path: String?): Boolean = config.isItemStack(path)
	@Suppress("KDocMissingDocumentation")
	override fun createSection(path: String?): ConfigurationSection = config.createSection(path)
	@Suppress("KDocMissingDocumentation")
	override fun createSection(path: String?, map: MutableMap<*, *>?): ConfigurationSection = config.createSection(path, map)
	@Suppress("KDocMissingDocumentation")
	override fun isDouble(path: String?): Boolean = config.isDouble(path)
	@Suppress("KDocMissingDocumentation")
	override fun getBooleanList(path: String?): MutableList<Boolean> = config.getBooleanList(path)
	@Suppress("KDocMissingDocumentation")
	override fun isColor(path: String?): Boolean = config.isColor(path)
	@Suppress("KDocMissingDocumentation")
	override fun getList(path: String?): MutableList<*> = config.getList(path)
	@Suppress("KDocMissingDocumentation")
	override fun getList(path: String?, def: MutableList<*>?): MutableList<*> = config.getList(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun getLongList(path: String?): MutableList<Long> = config.getLongList(path)
	@Suppress("KDocMissingDocumentation")
	override fun isConfigurationSection(path: String?): Boolean = config.isConfigurationSection(path)
	@Suppress("KDocMissingDocumentation", "UsePropertyAccessSyntax")
	override fun getRoot(): Configuration = config.getRoot()
	@Suppress("KDocMissingDocumentation")
	override fun getOfflinePlayer(path: String?): OfflinePlayer = config.getOfflinePlayer(path)
	@Suppress("KDocMissingDocumentation")
	override fun getOfflinePlayer(path: String?, def: OfflinePlayer?): OfflinePlayer = config.getOfflinePlayer(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun getCharacterList(path: String?): MutableList<Char> = config.getCharacterList(path)
	@Suppress("KDocMissingDocumentation")
	override fun contains(path: String?): Boolean = config.contains(path)
	@Suppress("KDocMissingDocumentation")
	override fun contains(path: String?, ignoreDefault: Boolean): Boolean = config.contains(path, ignoreDefault)
	@Suppress("KDocMissingDocumentation")
	override fun isString(path: String?): Boolean = config.isString(path)
	@Suppress("KDocMissingDocumentation")
	override fun getDoubleList(path: String?): MutableList<Double> = config.getDoubleList(path)
	@Suppress("KDocMissingDocumentation", "UsePropertyAccessSyntax")
	override fun getName(): String = config.getName()
	@Suppress("KDocMissingDocumentation")
	override fun getIntegerList(path: String?): MutableList<Int> = config.getIntegerList(path)
	@Suppress("KDocMissingDocumentation")
	override fun getConfigurationSection(path: String?): ConfigurationSection = config.getConfigurationSection(path)
	@Suppress("KDocMissingDocumentation")
	override fun get(path: String?): Any = config.get(path)
	@Suppress("KDocMissingDocumentation")
	override fun get(path: String?, def: Any?): Any = config.get(path, def)
	@Suppress("KDocMissingDocumentation", "UsePropertyAccessSyntax")
	override fun getCurrentPath(): String = config.getCurrentPath()
	@Suppress("KDocMissingDocumentation")
	override fun getDouble(path: String?): Double = config.getDouble(path)
	@Suppress("KDocMissingDocumentation")
	override fun getDouble(path: String?, def: Double): Double = config.getDouble(path, def)
	@Suppress("KDocMissingDocumentation", "UsePropertyAccessSyntax")
	override fun getDefaults(): Configuration = config.getDefaults()
	@Suppress("KDocMissingDocumentation")
	override fun getByteList(path: String?): MutableList<Byte> = config.getByteList(path)
	@Suppress("KDocMissingDocumentation")
	override fun isOfflinePlayer(path: String?): Boolean = config.isOfflinePlayer(path)
	@Suppress("KDocMissingDocumentation", "UsePropertyAccessSyntax")
	override fun getParent(): ConfigurationSection = config.getParent()
	@Suppress("KDocMissingDocumentation")
	override fun getStringList(path: String?): MutableList<String> = config.getStringList(path)
	@Suppress("KDocMissingDocumentation")
	override fun getKeys(deep: Boolean): MutableSet<String> = config.getKeys(deep)
	@Suppress("KDocMissingDocumentation")
	override fun getInt(path: String?): Int = config.getInt(path)
	@Suppress("KDocMissingDocumentation")
	override fun getInt(path: String?, def: Int): Int = config.getInt(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun options(): ConfigurationOptions = config.options()
	@Suppress("KDocMissingDocumentation")
	override fun getMapList(path: String?): MutableList<MutableMap<*, *>> = config.getMapList(path)
	@Suppress("KDocMissingDocumentation")
	override fun set(path: String?, value: Any?) = config.set(path, value)
	@Suppress("KDocMissingDocumentation")
	override fun isBoolean(path: String?): Boolean = config.isBoolean(path)
	@Suppress("KDocMissingDocumentation")
	override fun addDefaults(defaults: MutableMap<String, Any>?) = config.addDefaults(defaults)
	@Suppress("KDocMissingDocumentation")
	override fun addDefaults(defaults: Configuration?) = config.addDefaults(defaults)
	@Suppress("KDocMissingDocumentation")
	override fun getValues(deep: Boolean): MutableMap<String, Any> = config.getValues(deep)
	@Suppress("KDocMissingDocumentation")
	override fun <T : ConfigurationSerializable?> getSerializable(path: String?, clazz: Class<T>?): T = config.getSerializable(path, clazz)
	@Suppress("KDocMissingDocumentation")
	override fun <T : ConfigurationSerializable?> getSerializable(path: String?, clazz: Class<T>?, def: T): T = config.getSerializable(path, clazz, def)
	@Suppress("KDocMissingDocumentation")
	override fun isLong(path: String?): Boolean = config.isLong(path)
	@Suppress("KDocMissingDocumentation")
	override fun addDefault(path: String?, value: Any?) = config.addDefault(path, value)
	@Suppress("KDocMissingDocumentation")
	override fun getString(path: String?): String = config.getString(path)
	@Suppress("KDocMissingDocumentation")
	override fun getString(path: String?, def: String?): String = config.getString(path, def)
	@Suppress("KDocMissingDocumentation")
	override fun getShortList(path: String?): MutableList<Short> = config.getShortList(path)
	// @formatter:on
	//</editor-fold>

Dumb Kotlin. This was totally worth the time I put into it due to the lack of by config support.

Since methods are generated inside the class, why can’t I delegate to variables/fields also declared inside the class?

I tried to use the search here, but I didn’t know what to look for, so if this has been posted before then please let me know.

It looks like delegation would be perfect here, but Kotlin for some god-forsaken reason thinks I don’t deserve the auto-generated methods, so it forces me to implement around 100 methods like THAT. (I haven’t double-checked, but it looks like around 100? It’s still a lot.)

Is there any way to get around this, other than shoving that variable into the constructor?

1 Like

With lateinit there are some issues, what would happen if a delegated to method is called before the lateinit variable is set?
There might also be some unexpected behavior if the delegated to object changes during the lifetime of PorterConfiguration.

For your use case I’d suggest to just expose the inner config object.

Otherwise you can try to refactor your code so that PorterConfiguration gets created after config is.

Then it would throw an exception, like any other lateinit variable.

Yeah, private set seems more appropriate for this than delegation.

I still think this should be a feature though.

Probably secondary constructor enough here?
Something like this:

class PorterConfiguration(config: Configuration) : Configuration by config {
  constructor(file: File) : this(FileConfiguration(file))

Not sure about lateinit though but maybe a way to make lateinit var of PorterConfiguration itself.