Die Sache mit den Companion Objekten

dmike

Bekanntes Mitglied
Vorsicht ist bei case classen angebracht!

Ich bin bei folgendem Code auf die Nase gefallen

Java:
abstract class A0

case class A() extends A0

case class B() extends A0

case class C() extends A0

val list = List( A(), A(), B(), C(), C(), C() )

list filter ( _  match {case A => true; case _ => false} )

scala> list filter ( _  match {case A => true; case _ => false} )
<console>:13: error: pattern type is incompatible with expected type;
 found   : object A
 required: Product with A0
       list filter ( _  match {case A => true; case _ => false} )
                                    ^

Daran erkennt man, dass A != A() ist. Da A das Companion Objekt von A() ist erwartet der match an der Stelle ^ auch ein A()

Es muss also richtig heissen

Java:
 list filter ( _  match {case A() => true; case _ => false} )

oder alternativ1
Java:
 list filter ( _  match {case _:A => true; case _ => false} )

oder alternativ2
Java:
 list filter ( x => x  match {case A() => true; case _ => false} )

Der Unterschied zwischen A und A() wird hier noch mal deutlicher

Java:
scala> case class A()
defined class A

scala> def f(x: Any) = x match { case A => 1 ; case A() => 2 ; case _ => 3 }
f: (x: Any)Int

scala> f(A)
res0: Int = 1

scala> f(A())
res1: Int = 2

scala> f(4711)
res1: Int = 3

Oder auch

Java:
scala> case class Z(i:Int) {println(i) }                   
defined class Z  <------------------------- Das Companion Object zum Typ Z

scala> val y = Z  
y: Z.type = <function1>  <--------------- anscheinend ist y bzw Z eine Funktion mit
                                                               einem Parameter. Besitzt also implizit eine
                                                               apply(i:Int) Methode, die, ....

scala> y(1)   <---------------------------- wenn man sie aufruft, ....
1
res11: Z = Z(1)  <------------------------ ...... ein fertig instanziiertes Objekt Z liefert



scala> val x = y(1)   <-------------------- das ganze also noch einmal nur diesmal in x abgespeichert
1
x: Z = Z(1)               <-------------------- jetzt haben wir also eine _Object_  x vom Typ Z
                                                                in der Hand



Frage ist nur sollte der REPL nicht besser an der Stelle

Java:
scala> case class Z(i:Int) {println(i) }                   
defined class Z

mit


Java:
scala> case class Z(i:Int) {println(i) }                   
defined companion object Z

antworten?
 
Zuletzt bearbeitet:

Landei

Top Contributor
Das ist zwar alles richtig, aber meiner Meinung nach nicht besonders praxisrelevant. Wenn man nämlich eine Fallklasse mit leerer Konstruktor-Argumentliste hat, kann es davon (ohne Mogeleien) immer nur eine Instanz geben. Und dann kann man auch gleich Fallobjekte nehmen:
Code:
abstract class A0
 
case object A extends A0
 
case object B extends A0
 
case object C extends A0

Damit löst sich dann die ganze Konfusion in Wohlgefallen auf.
 

dmike

Bekanntes Mitglied
Das ist zwar alles richtig, aber meiner Meinung nach nicht besonders praxisrelevant. Wenn man nämlich eine Fallklasse mit leerer Konstruktor-Argumentliste hat, kann es davon (ohne Mogeleien) immer nur eine Instanz geben. Und dann kann man auch gleich Fallobjekte nehmen:
Code:
abstract class A0
 
case object A extends A0
 
case object B extends A0
 
case object C extends A0

Damit löst sich dann die ganze Konfusion in Wohlgefallen auf.

Von praxisrelevant war auch nicht die Rede :) War halt nur um zu verstehen was genau companion objekte sind (sie sind eben mehr als nur singeltons oder factories a la java). Ich hab jetzt ein besseres Verständnis dadurch bekommen. Ausserdem habe ich so auch noch per Zufall einen Bug im script runner von scala gefunden und gemeldet :D Aber ansich hast du natürlich Recht.
 

Neue Themen


Oben