I have an abstract class:
abstract class Vec2t
and an extending class:
class Vec2 : Vec2t
Vec2t has the following companion object:
companion object {
#JvmField val length = 2
}
But when I type Vec2.length, then it's marked as unresolved reference...
Why? What am I missing?
In Kotlin, a companion object is just a specially marked object inside your class. You can omit its name, and it will get the default name of Companion, and you also get the convenience of being able to use the MyClass.myProperty syntax instead of MyClass.Companion.myProperty to access its members. It is, however, still just a nested object.
Imagine how things would work if it was a regular nested object instead of a companion:
abstract class Vec2t {
object LengthKeeper {
val length = 2
}
}
class Vec2 : Vec2t()
You could access the length via Vec2t.LengthKeeper.length, but of course you couldn't access it as Vec2.LengthKeeper.length, because the Vec2 class does not have a nested object called LengthKeeper.
Marking a variable inside the companion object #JvmStatic does generate a static variable for length inside Vec2t in the bytecode, but you can only access that from Java, where writing the following does in fact work with your code:
Vec2 v = new Vec2();
int length = Vec2.getLength();
As for solving this in Kotlin, if you really have to access the property of the base class through Vec2 with that syntax, you'll probably have to do something like this:
class Vec2 : Vec2t() {
companion object {
val length get() = Vec2t.length
}
}
Related
I'm trying to create a Map that contains generic-parameterized types. For example:
abstract class Foo {
companion object {
val fooInjectors = HashMap<Class<T: Foo>, Injector<T: Foo>>()
}
}
The idea is to have fooInjectors (which would be static in Java or in a companion object in Kotlin) contain a cache of sub-classes of Foo and their corresponding Injector.
Unfortunately, I can't get this to compile. I'd very much appreciate it if someone would help me figure out the syntax for this!
As far as I know, you are trying to do something that is impossible in Kotlin. The companion object is a singleton and it doesn't make sense to generify a singleton as there will not be any further objects created hence generic types are irrelevant. So you can't generify the property you declared because it's in the companion object.
However, one way you could make this working is using a backing function. This backing function should annotate with declaration-site variance.
This simply means we tell the compiler that we only return a type T from the method (and don't consume). That allows us to use subtypes and the supertype of the T if required. This is called covariance.
You can look at the docs to understand it further - https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance
Here's what I meant.
interface Injector<T>
class InjectorImpl<T> : Injector<T>
abstract class Foo {
companion object {
val fooInjectors = createMap<Foo>()
private fun <T> createMap(): HashMap<Class<out T>, Injector<out T>> {
return HashMap()
}
}
}
class Bar: Foo()
object Runner {
#JvmStatic
fun main(args: Array<String>) {
Foo.fooInjectors[Bar::class.java] = InjectorImpl<Bar>()
Foo.fooInjectors[Foo::class.java] = InjectorImpl<Bar>()
}
}
I have a class which impliments both the java.io.Serializable and android.os.Parcelable.
These classes require companion objects of:
companion object CREATOR : Parcelable.Creator<MyClass> {
override fun createFromParcel(parcel: Parcel): MyClass
...
}
and
companion object {
private val serialVersionUid: Long = 123
}
The trouble is that I can't have both these companion objects because that causes a only one companion object per class exception.
How can I have two companion objects with different names in the same class?
May be you misunderstood Java examples.
public static Parcelable.Creator<SDFileDir> CREATOR = ...;
public static long serialVersionUid = 123;
In Java - yes, it is separated static object. You can place any count of static fields in class.
In Kotlin there should be only one static object (it is called Companion here). But it is like one more class here. So all new static fields should be inside of it.
companion object {
#JvmField
val CREATOR: Parcelable.Creator<SDFileDir> = ...
val serialVersionUid: Long = 123
}
There is one more thing: annotation #JvmField to work with Java correctly.
I can suggest two solutions to this problem:
As #Ircover said - You can declare the CREATOR (which is simply a static field in Java) inside your companion object alongside your constants, but you'll need to mark in with #JvmField annotation to work as inteded (as it is called from Java)..
You do not necessarily need the companion object for the constant value, it (it won't work with serialVersionUid in your case, as it MUST be inside the class for Java serialization to work) can be moved to a separate object, to a companion object of another class or even inside any .kt file body (outside the class)..
In fact, companion object in kotlin doesn't correspond to static object in Java, they merely share similar funtionality.
In Java, there are only two concepts involved: the class and its static object.
In Koltin, we are dealing with three concepts: the class, the companion object, and the property of the companion object.
The way we access the property of the companion object is the same as accessing the static object in Java, but in Kotlin, there is an extra layer between the class and the inner property, that is the companion object.
In your case, you are not demanding two companion objects, but two properties of one companion object, so just place these two properties in one companion object.
According to Kotlin documentation:
Members of the companion object can be called by using simply the
class name as the qualifier.
Why does it not seem to work here?
class Foo {
companion object {
enum class Type { A, B, C }
}
}
class Bar {
val typeA = Foo.Companion.Type.A // works
val typeB = Foo.Type.B // error: "Unresolved reference: Type"
}
Comparing the two qualified type names, Foo.Type.A and Foo.Companion.Type.A , the former would rather mean a type declared directly inside the Foo's scope.
The latter form, therefore, is used to disambiguate types declared inside a type from ones declared inside its nested types and object declarations (including the companion object).
class Foo {
class Bar // Foo.Bar
companion object {
class Bar // Foo.Companion.Bar
}
object Baz {
class Bar // Foo.Baz.Bar
}
}
As Pawel noted, nested types and object declarations are not members and have different resolution rules than those of functions and properties.
The documentation for companion objects has the following example
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Here Factory is the name of the companion object. It then goes on to say:
The name of the companion object can be omitted, in which case the name Companion will be used:
However there is no example that I can see that uses the name of the companion object.
Since you can only have one companion object per class (otherwise you get a Only one companion object is allowed per class error) the name feels like some pretty useless syntactic sugar to me.
What can the name of the companion object actually be used for?
Why would one bother to use any name for it?
You can use the name of the companion like:
MyClass.create() // not via companion name
MyClass.Companion.create() // via default companion name
MyClass.Factory.create() // via companion name
The name is maybe not that important for Kotlin, because you can just access the method without knowing that there is a companion object (line one above). It is more like a personal style, if you want to make the access to such functions more explicit.
But for java interop it makes a difference, because you have to access the function via the companion name:
MyClass.Factory.create(); // with named companion
MyClass.Companion.create(); // with unnamed comanion
Well, companion objects in Kotlin are not just syntactic sugar. They are actually a type. They are able to do much more thing, and need not to be see as just replacement of static.
You can actually extend class or implement an interface. See an example below.
open class Super {
open fun sayHello() {
println("Hello")
}
}
class Some {
companion object Child : Super() {
override fun sayHello() {
super.sayHello()
println("Hello from companion object")
}
}
}
fun main() {
Some.Child.sayHello()
}
If you do not use an explicit name, the companions name is Companion, thus it can be omitted, like you already quoted.
Sometimes you may want to have an explicit name in your calls, which would be MyClass.Factory.create() in your example. For namespace reasons maybe.
I don't see a many reasons to name a companion object, either. Except if you care about Java interop with your Kotlin code. Then, you need to explicitly write the companions name.
Another reason you might care about the name is, when you define an extension function on it:
fun MyClass.Companion.ext() = "myext"
In this case, it can be clearer when it has a name like Factory, on which specific factory methods are added via extension.
However there is no example that I can see that uses the name of the companion object.
class Person(val name: String) { companion object Loader {
fun fromJSON(jsonText: String): Person = ... }
}
>>> person = Person.Loader.fromJSON("{name: 'Dmitry'}") >>> person.name
Dmitry
>>> person2 = Person.fromJSON("{name: 'Brent'}") >>> person2.name
Brent
I'm working on a homework assignment for my object oriented design class, and I'm running into trouble with Scala's companion objects. I've read in a few places that companion objects are supposed to have access to their companion class's private methods, but I can't seem to get it to work. (Just as a note, the meat of the assignment had to do with implementing a binary search tree, so I'm not just asking for answers...)
I have an object that is supposed to create an instance of my private class, BstAtlas (Bst is also defined in the Atlas object, took it out for clarity):
object Atlas {
def focusRoom(newRoom:Room,a:Atlas):Atlas = a.helpFocusRoom(newRoom);
abstract class Atlas {
...
protected def helpFocusRoom(n:Room):Atlas;
...
}
private class BstAtlas(bst:Bst) extends Atlas {
...
protected def helpFocusRoom(newRoom:Room):Atlas = ...
// uses some of bst's methods
...
}
}
But when I go to compile, I get the following error:
Question23.scala:15: error: method
helpFocusRoom cannot be accessed in
Atlas.Atlas
a.helpFocusRoom(newRoom);
The function helpFocusRoom needs to be hidden, but I don't know how to hide it and still have access to it inside of the companion object.
Can anyone tell me what I'm doing wrong here?
The problem is that classes and companion objects can't be nested like that. To define a companion object, you need to define the class outside of the object's body but in the same file.
Companion objects should be next to their real object, not containing it:
object Example {
class C(val i: Int = C.DefaultI) { }
object C { protected val DefaultI = 5 }
}
scala> (new Example.C).i
res0: Int = 5
scala> Example.C.DefaultI
<console>:11: error: value DefaultI cannot be accessed in object Example.C
Example.C.DefaultI
Alternatively, you can alter the scope of the protected keyword to include the enclosing object:
object Example {
def value = (new D).hidden
class D(val i: Int = 5) {
protected[Example] def hidden = i*i
}
}
scala> Example.value
res1: Int = 25
but here you ought not name the outer object the same thing as the inner class or you'll have trouble referring to it from within the class.