0
votes

Let's say I have a Kotlin interface:

interface Dog {
    fun walk()
}

I want to create an Kotlin object of this class with slight modifications, like so:

val poodle : Dog = object : Dog {

    override fun walk() {
        ...
    }
}

However, I also want to add a what is equivalent to a private static final field in Java to this object, like so (this is a working example in Java):

Dog poodle = new Dog() {

    private static final String POODLE_FASHION = ...

    @Override
    public walk() {
        ...
    }
}

I read that a private const val is equivalent to this in Kotlin. I tried to do the following (this is an example in Kotlin that is NOT working):

val poodle : Dog = object : Dog {

    private const val POODLE_FASHION = ...

    override fun walk() {
        ...
    }
}

When I did this, I got the following error in Android Studio: Const 'val' are only allowed on top level or in objects.

Could someone explain why the Java version works, but the Kotlin version doesn't? How do I do this for Kotlin (I tried companion object already, but got the error Modifier 'companion' is not applicable inside 'local class')? Note I don't want to do the following because I want POODLE_FASHION to live inside val poodle as I am going to create other Dog objects with slight modification as well (val pug, val chihuahua, etc.):

private const val POODLE_FASHION = ...

val poodle : Dog = object : Dog {

    override fun walk() {
        ...
    }
}

Thanks!

2

2 Answers

1
votes
val poodle : Dog = object : Dog {

    private const val POODLE_FASHION = ...

    override fun walk() {
        ...
    }
}

In this example, there's really no reason at all POODLE_FASHION needs to be static or const. It can just be a normal val, and it won't cost you anything extra.

That said, it sounds like you ought to have a Poodle class, not an object.

0
votes

Note the difference between an object expression and an object declaration.

  • val poodle = object: Dog { ... } is an object expression. It creates an anonymous object. It's the equivalent of writing Dog poodle = new Dog() { ... } in Java.
  • object Poodle: Dog { ... } is an object declaration. It creates a singleton object, and is roughly equivalent to creating a Java class that is limited to only having one instance.

The Kotlin documentation states that const val properties must be "top-level, or member of an object declaration or a companion object." (https://kotlinlang.org/docs/reference/properties.html#compile-time-constants). They are not valid in object expressions.

The following object declaration should work fine:

object Poodle : Dog {
    private const val POODLE_FASHION = ...

    override fun walk() {
        ...
    }
}

One important reason for the distinction is that an object expression doesn't declare a new type (though, in Java terms, it does result in an anonymous class).

  • val poodle = object: Dog { ... } creates a variable of type Dog. There is no such type as Poodle.
  • object: Poodle: Dog { ... } creates an object of type Poodle. This is a new type which is a subtype of Dog.

This difference is important, because in Kotlin a const val property always belongs to a type. MyClass.MY_CONST_VAL is valid, but accessing it as MyClass().MY_CONST_VAL is an error and would not work. As a result, a const val property on an anonymous object would always be effectively private to that object.

I can't see a technical reason why it wouldn't be possible to allow const val properties on anonymous objects (static final compile-time constant fields are allowed in Java inner classes), but their usefulness would be severely limited and it just isn't part of the Kotlin language spec.