Consider an abstract class defining two properties
abstract class A {
def a: Int
def b: Int
// real A has additional members
}
which is the base class for various case classes such as
case class Foo(a: Int, b: Int) extends A
case class Bar(a: Int, b: Int) extends A
// and many more
Goal: I would finally like to be able to create instances of the aforementioned case classes in two ways, namely
val b1 = Bar(1, 2)
val b2 = Bar(1) has 2
assert(b1 == b2) // must hold
Approach: It therefore seems reasonable to define a helper class that defines has and that allows me to partially construct As
case class PartialA(f: Int => A) {
def has(b: Int) = f(b)
}
Problem: The current machinery doesn’t allow for calls like Bar(1) because this is actually an invocation of Bar.apply(1), that is, of the method apply as defined by the compiler-generated object Bar.
It would be great if I could force the compiler to generate the Bar object as object Bar extends PartialAConstructor, where
abstract class PartialAConstructor{
def apply(a: Int, b: Int): A // abstract, created when the compiler creates
// object Bar
def apply(a: Int) = PartialA((b: Int) => apply(a, b))
}
However, it doesn’t seem to be possible to influence the generation of companion objects of case classes.
Desired properties:
-
Case classes:
Foo,Baretc. should remain case classes because I would like to use the compiler-generated goodies such as structural equality,copyand automatically generated extractors. -
“Full” structural equality: Defining the case classes as
case class Bar(a: Int)(val b: Int)is not an option, because the compiler-generated
equalsmethod only considers the first list of arguments, and thus the following would hold erroneously:assert(Foo(1)(0) == Foo(1)(10)) -
As little code repetition as possible: For example, it is of course possible to define a
def Bar(a: Int) = PartialA((b: Int) => Bar(a, b))but that would have to be done for every case class extending
A, that, isFoo,Baretc.
You could heavily rely on currrying (and on the fact that
Foo.apply, as any method, will automatically get promoted to a function) and on a little helper to enhance syntax:Then you can do:
If you really want to use your
hasmethod (instead of just directly applying the function), throw in an implicit classes on top of that:and now you can do: