Why can't I access private class methods in the class's companion object in Scala? - oop

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.

Related

How to make a data class singleton in Kotlin?

Assume I have a data class:
data class SensorData(val name: String, val temp : Double)
I create this SensorData object from either an REST service or by internal setter method, whereas name is always populated and temp might be empty.
Further on, I need this SensorData object through several classes, thats I thought of using a singleton.
Obviously I need object keyword as described here, but how can I combine data class object ?
You can use companion object to keep a reference to your data object:
data class SensorData(val name: String, var temp : Double) {
companion object {
#Volatile
#JvmStatic
private var INSTANCE: SensorData? = null
#JvmStatic
#JvmOverloads
fun getInstance(name: String = "default", temp : Double = 0.0): SensorData = INSTANCE ?: synchronized(this) {
INSTANCE ?: SensorData(name, temp).also { INSTANCE = it }
}
}
}
And use it like this:
val name1 = SensorData.getInstance("name", 5.0).name
// Or with default values:
val name2 = SensorData.getInstance().name
I think you got the concept of a Singleton wrong:
"The singleton pattern is a software design pattern that restricts the instantiation of a class to one "single" instance"
It is not only meant to be used to make it public to all classes, but to limit the number of instances.
A data class is a class to store data, why should it be a Singleton?
Rethink your architecture to make it accessible where you need it.
Don't use a data class as a singleton. That's not what they are designed for. A better approach would be to create a wrapper object around your data class, which handles your SensorData-Object(s). This will also allow you to use multiple SensorData objects (maybe needed in future) or replace the current one with a new one if you poll the REST-Service a second time.
object SensorDataService {
var sensorData: SensorData? = null
}
data class SensorData(val name: String, val temp : Double)
In my opinion, you should rethink your architecture as data class is used to store data so why it should be a singleton? It is not only meant to be used to make it public to all classes but to limit the number of instances.

Kotlin: cannot access enum defined in 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.

Java allow to access Kotlin's base variable through it's child, but not Kotlin, why?

I have a class as below
open class KotlinBase {
companion object {
const val TAG = "testing"
}
}
And a child of it as
class KotlinChild : KotlinBase()
When I try to access TAG from a Java class, I could either
public class JavaOther {
String test1 = KotlinBase.TAG; // This is okay
String test2 = KotlinChild.TAG; // This is okay
}
However, when accessing from Kotlin class, I can't access through the Child.
class KotlinOther {
val test1 = KotlinChild.TAG // Compile/Syntax error
val test2 = KotlinBase.TAG // This is okay
}
Why can't my Kotlin class access the inherited variable TAG through KotlinChild?
It's a design decision allowing you to avoid ambiguities. - child classes can have their own companion objects with fields/methods having same names as those in the parent.
By restricting access to companions only through the actual class, problems with ambiguous field/method shadowing do not exist anymore.
Also, companion objects are not static members known from other languages. Although, the majority of use cases overlap.
Additionally, remember that
KotlinBase.TAG
is a shortcut for:
KotlinBase.Companion.TAG

Why I don't see companion object component of extended class?

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
}
}

Why do we use "companion object" as a kind of replacement for Java static fields in Kotlin?

What is the intended meaning of "companion object"? So far I have been using it just to replace Java's static when I need it.
I am confused with:
Why is it called "companion"?
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
To instantly create a singleton instance that is scoped to a class, I often write
:
companion object {
val singleton by lazy { ... }
}
which seems like an unidiomatic way of doing it. What's the better way?
What is the intended meaning of "companion object"? Why is it called "companion"?
First, Kotlin doesn't use the Java concept of static members because Kotlin has its own concept of objects for describing properties and functions connected with singleton state, and Java static part of a class can be elegantly expressed in terms of singleton: it's a singleton object that can be called by the class' name. Hence the naming: it's an object that comes with a class.
Its name used to be class object and default object, but then it got renamed to companion object which is more clear and is also consistent with Scala companion objects.
Apart from naming, it is more powerful than Java static members: it can extend classes and interfaces, and you can reference and pass it around just like other objects.
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes, that's the idiomatic way. Or you can even group them in non-companion objects by their meaning:
class MyClass {
object IO {
fun makeSomethingWithIO() { /* ... */ }
}
object Factory {
fun createSomething() { /* ... */ }
}
}
To instantly create a singleton instance that is scoped to a class, I often write /*...*/ which seems like an unidiomatic way of doing it. What's the better way?
It depends on what you need in each particular case. Your code suits well for storing state bound to a class which is initialized upon the first call to it.
If you don't need it to be connected with a class, just use object declaration:
object Foo {
val something by lazy { ... }
}
You can also remove lazy { ... } delegation to make the property initialize on first class' usage, just like Java static initializers
You might also find useful ways of initializing singleton state.
Why is it called "companion"?
This object is a companion of the instances.
IIRC there was lengthy discussion here: upcoming-change-class-objects-rethought
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes. Every "static" property/method needs to be placed inside this companion.
To instantly create a singleton instance that is scoped to a class, I often write
You do not create the singleton instance instantly. It is created when accessing singleton for the first time.
which seems like an unidiomatic way of doing it. What's the better way?
Rather go with object Singleton { } to define a singleton-class. See: Object Declarations
You do not have to create an instance of Singleton, just use it like that Singleton.doWork()
Just keep in mind that Kotlin offers other stuff to organize your code. There are now alternatives to simple static functions e.g. you could use Top-Level-Functions instead.
When the classes/objects with related functionalities belong together, they are like companions of each other. A companion means a partner or an associate, in this case.
Reasons for companionship
Cleaner top-level namespace
When some independent function is intended to be used with some specific class only, instead of defining it as a top-level function, we define it in that particular class. This prevents the pollution of top-level namespace and helps with more relevant auto-completion hints by IDE.
Packaging convenience
It's convenient to keep the classes/objects together when they are closely related to each other in terms of the functionality they offer to each other. We save the effort of keeping them in different files and tracking the association between them.
Code readability
Just by looking at the companionship, you get to know that this object provides helper functionality to the outer class and may not be used in any other contexts. Because if it was to be used with other classes, it would be a separate top level class or object or function.
Primary purpose of companion object
Problem: companion class
Let's have a look at the kinds of problems the companion objects solve. We'll take a simple real world example. Say we have a class User to represent a user in our app:
data class User(val id: String, val name: String)
And an interface for the data access object UserDao to add or remove the User from the database:
interface UserDao {
fun add(user: User)
fun remove(id: String)
}
Now since the functionalities of the User and implementation of the UserDao are logically related to each other, we may decide to group them together:
data class User(val id: String, val name: String) {
class UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
val userAccess = User.UserAccess()
userAccess.add(john)
}
While this is a good setup, there are several problems in it:
We have an extra step of creating the UserAccess object before we can add/remove a User.
Multiple instances of the UserAccess can be created which we don't want. We just want one data access object (singleton) for User in the entire application.
There is a possibility of the UserAccess class to be used with or extended with other classes. So, it doesn't make our intent clear of exactly what we want to do.
The naming userAccess.add() or userAccess.addUser() doesn't seem very elegant. We would prefer something like User.add().
Solution: companion object
In the User class, we just replace the two words class UserAccess with the two other words companion object and it's done! All the problems mentioned above have been solved suddenly:
data class User(val id: String, val name: String) {
companion object : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
User.add(john)
}
The ability to extend interfaces and classes is one of the features that sets the companion objects apart from Java's static functionality. Also, companions are objects, we can pass them around to the functions and assign them to variables just like all the other objects in Kotlin. We can pass them to the functions that accept those interfaces and classes and take advantage of the polymorphism.
companion object for compile-time const
When the compile-time constants are closely associated with the class, they can be defined inside the companion object.
data class User(val id: String, val name: String) {
companion object {
const val DEFAULT_NAME = "Guest"
const val MIN_AGE = 16
}
}
This is the kind of grouping you have mentioned in the question. This way we prevent the top-level namespace from polluting with the unrelated constants.
companion object with lazy { }
The lazy { } construct is not necessary to get a singleton. A companion object is by default a singleton, the object is initialized only once and it is thread safe. It is initialized when its corresponding class is loaded. Use lazy { } when you want to defer the initialization of the member of the companion object or when you have multiple members that you want to be initialized only on their first use, one by one:
data class User(val id: Long, val name: String) {
companion object {
val list by lazy {
print("Fetching user list...")
listOf("John", "Jane")
}
val settings by lazy {
print("Fetching settings...")
mapOf("Dark Theme" to "On", "Auto Backup" to "On")
}
}
}
In this code, fetching the list and settings are costly operations. So, we use lazy { } construct to initialize them only when they are actually required and first called, not all at once.
Usage:
fun main() {
println(User.list) // Fetching user list...[John, Jane]
println(User.list) // [John, Jane]
println(User.settings) // Fetching settings...{Dark Theme=On, Auto Backup=On}
println(User.settings) // {Dark Theme=On, Auto Backup=On}
}
The fetching statements will be executed only on the first use.
companion object for factory functions
Companion objects are used for defining factory functions while keeping the constructor private. For example, the newInstance() factory function in the following snippet creates a user by generating the id automatically:
class User private constructor(val id: Long, val name: String) {
companion object {
private var currentId = 0L;
fun newInstance(name: String) = User(currentId++, name)
}
}
Usage:
val john = User.newInstance("John")
Notice how the constructor is kept private but the companion object has access to the constructor. This is useful when you want to provide multiple ways to create an object where the object construction process is complex.
In the code above, consistency of the next id generation is guaranteed because a companion object is a singleton, only one object will keep track of the id, there won't be any duplicate ids.
Also notice that companion objects can have properties (currentId in this case) to represent state.
companion object extension
Companion objects cannot be inherited but we can use extension functions to enhance their functionality:
fun User.Companion.isLoggedIn(id: String): Boolean { }
The default class name of the companion object is Companion, if you don't specify it.
Usage:
if (User.isLoggedIn("34")) { allowContent() }
This is useful for extending the functionality of the companion objects of third party library classes. Another advantage over Java's static members.
When to avoid companion object
Somewhat related members
When the functions/properties are not closely related but only somewhat related to a class, it is recommended that you use top-level functions/properties instead of companion object. And preferably define those functions before the class declaration in the same file as that of class:
fun getAllUsers() { }
fun getProfileFor(userId: String) { }
data class User(val id: String, val name: String)
Maintain single responsibility principle
When the functionality of the object is complicated or when the classes are big, you may want to separate them into individual classes. For example, You may need a separate class to represent a User and another class UserDao for database operations. A separate UserCredentials class for functions related to login. When you have a huge list of constants that are used in different places, you may want to group them in another separate class or file UserConstants. A different class UserSettings to represent settings. Yet another class UserFactory to create different instances of the User and so on.
That's it! Hope that helps make your code more idiomatic to Kotlin.
Why is it called "companion"?
An object declaration inside a class can be marked with the companion keyword:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Members of the companion object can be called by using simply the class name as the qualifier:
val instance = MyClass.create()
If you only use 'object' without 'companion', you have to do like this:
val instance = MyClass.Factory.create()
In my understanding, 'companion' means this object is companion with the outter class.
We can say that companion is same as "Static Block" like Java, But in case of Kotlin there is no Static Block concept, than companion comes into the frame.
How to define a companion block:
class Example {
companion object {
fun display(){
//place your code
}
}
}
Calling method of companion block, direct with class name
Example.Companion.display