Reputation:
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!
Upvotes: 1
Views: 1002
Reputation: 9952
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.
Upvotes: 0
Reputation: 198471
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.
Upvotes: 1