Scala - use companion object as shorthand argument to function accepting block - scala

I have a set of model objects and a set of wrapper objects to give them extra functionality.
I'd like to be able to convert collections of model objects to wrapper objects concisely, using the same shorthand that allows you to write List("x", "y", "z").foreach(println), like this:
class Model
class ModelWrapper(val m: Model)
object ModelWrapper { def apply(model: Model) = new ModelWrapper(model) }
val m1 = new Model; val m2 = new Model; val m3 = new Model
List(m1, m2, m3).map(ModelWrapper)
So that ModelWrapper, passed as an argument, is converted to ModelWrapper(_), a call on the companion object.
However, when I try this, I get a type mismatch error like this:
<console>:14: error: type mismatch;
found : ModelWrapper.type (with underlying type object ModelWrapper)
required: Model => ?
List(m1, m2, m3).map(ModelWrapper)
However, if I make ModelWrapper a case class, and remove the companion object, it works. I don't want to make it a case class as the behaviour it's adding does not fit well with the overall way in which case classes work. Two wrapper classes with the same model class as a parameter are not necessarily equal, for example.
What I'd like to know is, what is the difference between the case class and companion object in this case? Can I get what I want without using a case class?

Your companion object must be a function:
object ModelWrapper extends Function1[Model, ModelWrapper] { def apply(model: Model) = new ModelWrapper(model) }
Or may be you'll prefer this abbreviation:
object ModelWrapper extends (Model => ModelWrapper) { def apply(model: Model) = new ModelWrapper(model) }

For some reason, these works:
List(m1, m2, m3).map(ModelWrapper(_))
List(m1, m2, m3).map(ModelWrapper.apply)
It seems for case classes, since the companion object is created by the compiler and not you, it knows you are referring to ModelWrapper.apply. When there is a companion, it thinks you are referring to the companion.

Related

Find a decent alternative to forced explicit type annotation?

While testing some code that I recently created i figured that some passages are not compiling without explicit type annotation. I tried to minimize the problem in the following code snippet:
case class Base[E,S](al:Set[E],sts:Set[MidState[S]],ss:MidState[S],
d:Map[(MidState[S],E),MidState[S]],aS:Set[MidState[S]])
case class Edge[E,S](state_1: MidState[S],l:E ,state_2: MidState[S])
sealed trait MidState[S] extends BaseState[S]
sealed case class State[S](l:S)
extends MidState[S]
case object FailureState extends MidState[Nothing]
Base has a companion object with an apply method defined as follows:
object Base {
def apply [E,S](edges:Set[Edge[E,S]],ss:MidState[S],
aS:Set[MidState[S]],partialMode:Boolean): Base[E,S]
When i am trying to instantiate Base with this apply method i cannot get around an explicit type annotation for aS:
val aS : Set[MidState[String]] = (State("C") :: Nil).toSet
val base = Base(edges,State("A"),aS,partialMode = true)
If i erase the explicit type annotation for aS, aS is of type Set[State[S]] and not Set[MidState[S]] which it needs to be for the apply method. Is there any better solution to avoid this explicit type annotation despite inserting (State("C") :: Nil).toSet directly into the apply method?
The first thing you could do is to remove all the :: Nil and .toSet and : ... noise:
val aS = Set[MidState[String]](State("C"))
This is actually quite common: for example, it frequently occurs as the first argument in folds, where one has to explicitly write Set[Int]() or Set.empty[Int] in order to get the types right.
If this is still too noisy, just add appropriate factory methods to MidState:
object MidState {
def apply[S](s: S): MidState[S] = State(s)
}
and then invoke the factory method that constructs the right type of object right away:
val bS = Set(MidState("C"))
Andrey Tyukin introduced a solution by adding factory-methods to the MidState class which works fine. However, I solved the issue by adding a type-restriction to the apply-method ,so the signature changed from:
object Base {
def apply [E,S](edges:Set[Edge[E,S]],ss:MidState[S],
aS:Set[MidState[S]],partialMode:Boolean): Base[E,S]
to:
object Base {
def apply [E,S](edges:Set[Edge[E,S]],ss:MidState[S],
aS:Set[_ <: MidState[S]],partialMode:Boolean): Base[E,S]
Now we can pass any Set aS which contains elements that are subtypes of MidState, which is exactly what I was looking for.

Scala companion objects are not singleton

I have following two classes.
class A (name: String) {
}
object A {
}
According to definition of Singleton, we can have only one object of that type. However I am able to create two different objects of type A using following piece of code.
object B {
def main(args: Array[String]): Unit = {
val a = new A("Vinod")
println(a)
val b = new A("XYZ")
println(b)
}
}
can someone please explain me, where my understanding is not correct?
An object by itself is a singleton. It has its own class and no other instance of the same class exist at runtime.
However, the pattern you describe here is different: object A is not an instance of class A unless you make it so using object A extends A. You could make it the only instance of class A by making class A a sealed class, but this is unnecessary in almost all cases.
If you really want the singleton pattern, drop the class and use only object A, all of its members will be "static" in the sense of Java.
Note that the actual type of object A can be referred to as A.type, which by default is completely unrelated to type A if class A exists. Again, A.type could be a subtype of A if you explicitly make it so.
The companion object is not an instance of the companion class. They're not even the same type.
class A
object A {
var state = 0
def update() :Unit = state = state + 1
}
val abc :A = new A //instance of class A
val xyz :A.type = A //2nd reference to object A
// both reference the same singleton object
xyz.update() //res0: Unit = ()
A.state //res1: Int = 1
abc.state //Error: value state is not a member of A$A2521.this.A
the companion object can be thought of as the static space of a class. if you want to make A a singleton you can make it an object rather than a class
new A refers to class A (which is not a singleton), not to object A. You can easily check it: if you remove class A, the new A lines will no longer compile.
Also note that objects aren't necessarily singletons: they can be nested inside classes or traits, in this case there is one for each instance of the outer type.

Scala collection whose elements can construct sibling instances using named parameters and default values?

I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.

Support generic deserialization from a List[(String, Any)] in Scala

This is a follow up to the following question, which concerned serialization: How best to keep a cached list of member fields, one each for a family of case classes in Scala
I'm trying to generically support deserialization in the same way. One straightforward attempt is the following:
abstract class Serializer[T](implicit ctag: ClassTag[T]) {
private val fields = ctag.runtimeClass.getDeclaredFields.toList
fields foreach { _.setAccessible(true) }
implicit class AddSerializeMethod(obj: T) {
def serialize = fields.map(f => (f.getName, f.get(obj)))
}
def deserialize(data: List[(String, Any)]): T = {
val m = data toMap
val r: T = ctag.runtimeClass.newInstance // ???
fields.foreach { case f => f.set(r, m(f.getName)) }
r;
}
}
There are a couple of issues with the code:
The line with val r: T = ... has a compile error because the compiler thinks it's not guaranteed to have the right type. (I'm generally unsure of how to create a new instance of a generic class in a typesafe way -- not sure why this isn't safe since the instance of Serializer is created with a class tag whose type is checked by the compiler).
The objects I'm creating are expected to be immutable case class objects, which are guaranteed to be fully constructed if created in the usual way. However, since I'm mutating the fields of instances of these objects in the deserialize method, how can I be sure that the objects will not be seen as partially constructed (due to caching and instruction reordering) if they are published to other threads?
ClassTag's runtimeClass method returns Class[_], not Class[T], probably due to the fact generics in Scala and Java behave differently; you can try casting it forcefully: val r: T = ctag.runtimeClass.newInstance.asInstanceOf[T]
newInstance calls the default, parameterless constructor. If the class doesn't have one, newInstance will throw InstantiationException. There's no way around it, except for:
looking around for other constructors
writing custom serializers (see how Gson does that; BTW Gson can automatically serialize only classes with parameterless constructors and those classes it has predefined deserializers for)
for case classes, finding their companion object and calling its apply method
Anyhow, reflection allows for modifying final fields as well, so if you manage to create an immutable object, you'll be able to set its fields.

How to design immutable model classes when using inheritance

I'm having trouble finding an elegant way of designing a some simple classes to represent HTTP messages in Scala.
Say I have something like this:
abstract class HttpMessage(headers: List[String]) {
def addHeader(header: String) = ???
}
class HttpRequest(path: String, headers: List[String])
extends HttpMessage(headers)
new HttpRequest("/", List("foo")).addHeader("bar")
How can I make the addHeader method return a copy of itself with the new header added? (and keep the current value of path as well)
Thanks,
Rob.
It is annoying but the solution to implement your required pattern is not trivial.
The first point to notice is that if you want to preserve your subclass type, you need to add a type parameter. Without this, you are not able to specify an unknown return type in HttpMessage
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String):X
}
Then you can implement the method in your concrete subclasses where you will have to specify the value of X:
class HttpRequest(path: String, headers: List[String])
extends HttpMessage(headers){
type X = HttpRequest
def addHeader(header: String):HttpRequest = new HttpRequest(path, headers :+header)
}
A better, more scalable solution is to use implicit for the purpose.
trait HeaderAdder[T<:HttpMessage]{
def addHeader(httpMessage:T, header:String):T
}
and now you can define your method on the HttpMessage class like the following:
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String)(implicit headerAdder:HeaderAdder[X]):X = headerAdder.add(this,header) }
}
This latest approach is based on the typeclass concept and scales much better than inheritance. The idea is that you are not forced to have a valid HeaderAdder[T] for every T in your hierarchy, and if you try to call the method on a class for which no implicit is available in scope, you will get a compile time error.
This is great, because it prevents you to have to implement addHeader = sys.error("This is not supported")
for certain classes in the hierarchy when it becomes "dirty" or to refactor it to avoid it becomes "dirty".
The best way to manage implicit is to put them in a trait like the following:
trait HeaderAdders {
implicit val httpRequestHeaderAdder:HeaderAdder[HttpRequest] = new HeaderAdder[HttpRequest] { ... }
implicit val httpRequestHeaderAdder:HeaderAdder[HttpWhat] = new HeaderAdder[HttpWhat] { ... }
}
and then you provide also an object, in case user can't mix it (for example if you have frameworks that investigate through reflection properties of the object, you don't want extra properties to be added to your current instance) (http://www.artima.com/scalazine/articles/selfless_trait_pattern.html)
object HeaderAdders extends HeaderAdders
So for example you can write things such as
// mixing example
class MyTest extends HeaderAdders // who cares about having two extra value in the object
// import example
import HeaderAdders._
class MyDomainClass // implicits are in scope, but not mixed inside MyDomainClass, so reflection from Hiberante will still work correctly
By the way, this design problem is the same of Scala collections, with the only difference that your HttpMessage is TraversableLike. Have a look to this question Calling map on a parallel collection via a reference to an ancestor type