Class companion object vs. case class itself - scala

I read this statement:
By using User.getClass, you are referring to the class companion
object that Scala by default creates for the case class, and not the
case class itself.
To get the class object of the case class, use
classOf[User].
Where could I come unstuck by using the class of the companion object? I would have thought - showing my ignorance here - they would be the same.

Java has something called static methods
public class Foo {
private int a:
public Foo(a) { this.a = a; }
public int getA() { return a; }
static public String getB() { return "B"; }
}
it is like a method but not attached to an instance
var foo = new Foo(10);
foo.getA(); // method attached to foo, its value depends on foo
Foo.getB(); // method attached to class but not particular instance
These static methods are used for storing globals (not recommended), or stateless functions not depending on object - like e.g. factories and other utilities. These methods can access private/protected members of the instances, and instances can access private/protected static methods - so you can limit visibility as if they were inside the object, even though they aren't (Java's reflection treats their methods as if they had null as this).
In Scala we didn't want to have the distinction for static and non-static methods so we decided to do the following:
create a separate object where such methods could be stored
make sure that this object could access instances members and vice-versa
have a similar name to distinct this object from other objects
That's how we arrived at companion object.
class Foo(val a: Int)
object Foo {
val b = "B"
}
val foo = new Foo(10)
foo.a // this is normal method
foo.getClass // this would return Foo
class[Foo] // same as above
Foo.getClass // this would return Foo$
classOf[Foo.type] // same as above
getClass is method that you can call on any object - since foo and Foo have different classes they would return different values for getClass.
Any value can describe their type with .type so foo.type would be the type of foo variable (Foo) and Foo.type would be the type of Foo object which is companion of Foo class (and would be called Foo$ in bytecode).
From the reason why companion object exist, it follows that Foo and its companion does not have the same (instance) methods, so they cannot have the same interface, and so they cannot be of the same type.
When it comes to case classes they just automatically create a companion object (if it doesn't exist) and generate some methods inside it based on their constructor: e.g. apply, unapply.

Generally, class A and its companion object A define different (unrelated) static types, namely A and A.type
class A
object A
implicitly[A <:< A.type] // doesn't compile
implicitly[A.type <:< A] // doesn't compile
val a: A.type = new A // doesn't compile, we can't assign a class instance to an object variable
val a1: A = A // doesn't compile, we can't assign an object to a class variable
Similarly, they have different runtime classes (different representations in bytecode), namely A and A$
classOf[A] == Class.forName("A") // true
classOf[A.type] == Class.forName("A$") // true
classOf[A].isAssignableFrom(classOf[A.type]) // false
classOf[A.type].isAssignableFrom(classOf[A]) // false
Sometimes, when there is a reason, companions can agree in types (although such design decision is made quite rarely). Example: https://github.com/apache/spark/blob/v3.3.1/sql/catalyst/src/main/scala/org/apache/spark/sql/types/LongType.scala#L56
class A
object A extends A
// implicitly[A <:< A.type] // doesn't compile
implicitly[A.type <:< A] // compiles
classOf[A].isAssignableFrom(classOf[A.type]) // true
classOf[A.type].isAssignableFrom(classOf[A]) // false
// val a: A.type = new A // doesn't compile
val a1: A = A // compiles
or
trait B
class A extends B
object A extends B
val b: B = new A
val b1: B = A

Related

Cannot call use class name directly to map type after adding a companion project

When we have a case class, we call map the type with the name of the type, e.g.:
case class Foo(value: String)
val value = Some("Yay!")
val foo = value.map(Foo)
But if we also provide a companion object, this stops working value.map(Foo) and looks like this works: value.map(Foo(_)). Why?
case class Foo(value: String)
object Foo {}
val value = Some("Yay!")
val foo = value.map(Foo)
println(foo)
ScalaFiddle.scala:5: error: type mismatch;
found : ScalaFiddle.this.Foo.type
required: scala.this.Function1[lang.this.String,?]
val foo = value.map(Foo)
If you don't define object Foo at all, then the synthetic companion object has the following declaration:
<synthetic> object Foo
extends scala.runtime.AbstractFunction1[String,Foo]
with Serializable
But if you define your own object Foo as follows
case class Foo(v: String)
object Foo {}
then the declaration of the Foo object changes accordingly to:
object Foo extends scala.AnyRef with Serializable
and it no longer extends Function1.
The method apply(v: String): Foo is still automatically generated on Foo, but it no longer implements the Function1[String, Foo] interface. If you declare the companion object like this:
object Foo extends (String => Foo) { ... }
then you again can use it in expressions like value.map(Foo).
The value.map(Foo(_)) syntax always works, because it's just a shortcut for
value.map(x => Foo.apply(x))
and the closure doesn't care at all about what interfaces are implemented by Foo, it cares only about the existence of the apply method.

Get static methods of a class nested in an object using Java reflection

I want to get the list of methods in a nested companion object using Java reflection. This is A.B in the example below.
object A {
object B {
def foo: Int = 4
}
class B {}
def bar: Int = 5
}
class A {}
// This works, `bar` is printed.
println(classOf[A].getMethods.map(_.getName).mkString("\n"))
// This doesn't work, `foo` is not printed.
println(classOf[A.B].getMethods.map(_.getName).mkString("\n"))
Seems like getting the list of methods on the outer companion object A works, but not on the nested one.
Is there any way to write a method that would take a Class[_] and get all the methods defined on the companion object whether it's nested or not?
classOf[A] and classOf[A.B] are not the classes of the companion objects, so they don't have these methods. A.type and B.type sortof are but they aren't class types in Scala. As pedrofurla points out, you can do this to reach them as java Class objects:
scala> A.getClass.getDeclaredMethods
res17: Array[java.lang.reflect.Method] = Array(public int A$.bar())
scala> A.B.getClass.getDeclaredMethods
res18: Array[java.lang.reflect.Method] = Array(public int A$B$.foo())
I came up with the following code, which makes an assumption that the companion's class name can be determined by appending $ to the class name.
This allows calling a method on the companion given the class of a corresponding type, regardless of whether the companion is nested or not:
def getCompanion(clazz: Class[_]) = {
Class.forName(clazz.getName + "$").getField("MODULE$").get(())
}
def companionMethod(clazz: Class[_], methodName: String) = {
getCompanion(clazz).getClass.getMethod(methodName).invoke(companion)
}
// Print all companion methods:
println(getCompanion(classOf[A.B]).getMethods.map(_.getName).mkString("\n"))
println(companionMethod(classOf[A], "bar") == 5)
println(companionMethod(classOf[A.B], "foo") == 4)

Restrict Construction of Scala Class

Given:
class Foo(x: Int) {}
object Foo {
def apply(x: Int) = new Foo(x)
}
Besides marking Foo's constructor as private, how can I present a warning or compile-time failure when calling new Foo(...)?
In other words, I'd like to restrict (either by compile-time warning or error) construction of Foo to Foo.apply.
Is this possible?
In scala there are two idiomatic ways how to achieve that.
Constructor private to the class and companion object.
Factory has access to constructor, while anyone else doesn't:
class Foo private[Foo](val x: Int)
object Foo {
def apply(x:Int) = new Foo(x)
}
val foo = new Foo(1) // cannot compile
val foo1 = Foo(1) //compiles fine
Sealed abstract class.
In scala sealed class can be extended only in the same source file it is defined.
I suggest to make Foo sealed abstract class and return anonymous child of Foo in object's apply method.
sealed abstract class Foo(val x:Int)
object Foo {
def apply(x:Int):Foo = new Foo(x) {}
}
In this case Foo can be created nowhere except the file where it is defined.
UPD: Actually, this question was already discussed on stackoverflow.
UPD2: Added brief overview of both methods.

Use cases of Covarient/Contravarient Annotations in Scala

In Scala, it's possible to specify whether a function or class is covarient or contravarient in the following manner
class Foo[+arg] // covarient
class Bar[-arg] // contravarient
What are the real world uses of this feature?
I know the compiler runs checks to make sure that the stated entity is actually covarient or otherwise, but what is the benefit of even adding such annotations?
The simplest case where your probably already using it without knowing it is the scala collections.
class A()
class B() extends A
case class Container[T](elem : T)
val listOfA:List[A] = List[B](new B(),new B())
val containerOfA:Container[A] = Container[B](new B()) // fails
Imagine you have the following hierarchy:
class A
class B extends A
Covariance. Covariant type can be used as return type:
class Foo[+arg] { // Covariant
def getArg(): arg = ???
}
def testCovariant(): Unit = {
val fooB = new Foo[B]
val foo: Foo[A] = fooB
// returns only objects of class derived from A
// so it is safe
val a: A = foo.getArg()
}
So you can use any of Foo[DerivedClass]where Foo[BaseClass] is used, because anywhere Foo[BaseClass].getArg is called BaseClass is expected as result and any DerivedClass can be returned and assigned to it.
Contravariance. Contravariant type can be used as method parameter type:
class Bar[-arg] { // Contravariant
def setArg(p: arg): Unit = ???
}
def testContravariant(): Unit = {
val barA = new Bar[A]
val bar: Bar[B] = barA
// can set B to bar which is actually Bar[A]
// but Bar[A].setArg(p: A) can accept any object
// of type derived from A
// so it is safe
bar.setArg(new B)
}
Again. You can use any of Bar[DerivedClass] where Bar[BaseClass] is used, because anywhere Bar[DerivedClass].setArg(p: DerivedClass) is called DerivedClass is expected as argument and any Bar[BaseClass] can be used in this context, because you can always pass DerivedClass to Bar[BaseClass].setArg(p: BaseClass).

"new" keyword in Scala

I have a very simple question - when should we apply the new keyword when creating objects in Scala? Is it when we try to instantiate Java objects only?
Use the new keyword when you want to refer to a class's own constructor:
class Foo { }
val f = new Foo
Omit new if you are referring to the companion object's apply method:
class Foo { }
object Foo {
def apply() = new Foo
}
// Both of these are legal
val f = Foo()
val f2 = new Foo
If you've made a case class:
case class Foo()
Scala secretly creates a companion object for you, turning it into this:
class Foo { }
object Foo {
def apply() = new Foo
}
So you can do
f = Foo()
Lastly, keep in mind that there's no rule that says that the companion apply
method has to be a proxy for the constructor:
class Foo { }
object Foo {
def apply() = 7
}
// These do different things
> println(new Foo)
test#5c79cc94
> println(Foo())
7
And, since you mentioned Java classes: yes -- Java classes rarely have
companion objects with an apply method, so you must use new and the actual
class's constructor.
Is it when we try to instantiate java objects only?
Not at all. There is two general cases when you ommit new in scala.
With singleton objects (that are oftenly used to store static functions and as a kind of factory similar to what you may seen in java):
scala> object LonelyGuy { def mood = "sad" }
defined module LonelyGuy
scala> LonelyGuy
res0: LonelyGuy.type = LonelyGuy$#3449a8
scala> LonelyGuy.mood
res4: java.lang.String = sad
With a case classes (actually, underneath there are class + object = companion pattern, e.g. having class and object with the same name):
scala> case class Foo(bar: String)
defined class Foo
scala> Foo("baz")
res2: Foo = Foo(baz)
So when you work with a simple classes, rules are the same as with Java.
scala> class Foo(val bar: String)
defined class Foo
scala> new Foo("baz")
res0: Foo = Foo#2ad6a0
// will be a error
scala> Foo("baz")
<console>:8: error: not found: value Foo
Foo("baz")
Bonus, there is a anonymous classes in scala, which can be constructed like this:
scala> new { val bar = "baz" }
res2: java.lang.Object{val bar: java.lang.String} = $anon$1#10ee5b8
scala> res2.bar
res3: java.lang.String = baz
Is it when we try to instantiate Java objects only?
With Scala 3 (which should be released mid 2020, eight years later), based on Dotty: never.
Scala 3 will drop "new", as in this thread
Creator applications allow to use simple function call syntax to create instances
of a class, even if there is no apply method implemented.
Example:
class StringBuilder(s: String) {
def this() = this(s)
}
StringBuilder("abc") // same as new StringBuilder("abc")
StringBuilder() // same as new StringBuilder()
Creator applications generalize a functionality provided so far only for case classes, but the mechanism how this is achieved is slightly different.
Instead of an auto-generated apply method, we add a new possible interpretation to a function call f(args).