I am in the process of migrating from Slick to Slick 2, and in Slick 2 you are meant to use the tupled method when projecting onto a case class (as shown here http://slick.typesafe.com/doc/2.0.0-RC1/migration.html)
The problem is when the case class has a companion object, i.e. if you have something like this
case class Person(firstName:String, lastName:String) {
}
Along with a companion object
object Person {
def something = "rawr"
}
In the same scope, the tupled method no longer works, because its trying to run tupled on the object, instead of the case class.
Is there a way to retrieve the case class of Person rather than the object, so you can call tupled properly?
You can also write
(Person.apply _).tupled
to avoid repeating the types.
This is very similar to what Alexey Romanov said, but in order to avoid lifting apply whenever you need tupled, we just add it to our companion objects.
object Person {
def something = "rawr"
def tupled = (Person.apply _).tupled
}
Now you can call Person.tupled just like you would have if it didn't have a companion object.
One workaround is define a companion object as follows:
object Person extends((String,String) => Person) {
...
}
See. https://groups.google.com/d/msg/scala-user/jyWBMz5Qslw/Bryv4ftzRLgJ
To build on some of the other comments you could do the following as well since tuple is calling the generated default apply method for the case class.
object Person {
...
def tupled = (this.apply _).tupled
}
Related
While learning Scala, I came across interesting concept of companion object. Companion object can used to define static methods in Scala. Need few clarifications in the below Spark Scala code in regard of companion object.
class BballStatCounter extends Serializable {
val stats: StatCounter = new StatCounter()
var missing: Long = 0
def add(x: Double): BballStatCounter = {
if (x.isNaN) {
missing += 1
} else {
stats.merge(x)
}
this
}
}
object BballStatCounter extends Serializable {
def apply(x: Double) = new BballStatCounter().add(x)
}
Above code is invoked using val stat3 = stats1.map(b=>BballStatCounter(b)).
What is nature of variables stats and missing declared in the
class? Is it similar to class attributes of Python?
What is the significance of apply method in here?
Here stats and missing are class attributes and each instance of BballStatCounter will have their own copy of them just like in Python.
In Scala the method apply serves a special purpose, if any object has a method apply and if that object is used as function calling notation like Obj() then the compiler replaces that with its apply method calling, like Obj.apply() .
The apply method is generally used as a constructor in a Class Companion object.
All the collection Classes in Scala has a Companion Object with apply method, thus you are able to create a list like : List(1,2,3,4)
Thus in your above code BballStatCounter(b) will get compiled to BballStatCounter.apply(b)
stats and missing are members of the class BcStatCounter. stats is a val so it cannot be changed once it has been defined. missing is a var so it is more like a traditional variable and can be updated, as it is in the add method. Every instance of BcStatCounter will have these members. (Unlike Python, you can't add or remove members from a Scala object)
The apply method is a shortcut that makes objects look like functions. If you have an object x with an apply method, you write x(...) and the compiler will automatically convert this to x.apply(...). In this case it means that you can call BballStatCounter(1.0) and this will call the apply method on the BballStatCounter object.
Neither of these questions is really about companion objects, this is just the normal Scala class framework.
Please note the remarks in the comments about asking multiple questions.
In my specific case I have a (growing) library of case classes with a base trait (TKModel)
Then I have an abstract class (TKModelFactory[T <: TKModel]) which is extended by all companion objects.
So my companion objects all inherently know the type ('T') of "answers" they need to provide as well as the type of objects they "normally" accept for commonly implemented methods. (If I get lazy and cut and paste chunks of code to search and destroy this save my bacon a lot!) I do see warnings on the Internet at large however that any form of CompanionObject.method(caseClassInstance: CaseClass) is rife with "code smell" however. Not sure if they actually apply to Scala or not?
There does not however seem to be any way to declare anything in the abstract case class (TKModel) that would refer to (at runtime) the proper companion object for a particular instance of a case class. This results in my having to write (and edit) a few method calls that I want standard in each and every case class.
case class Track(id: Long, name: String, statusID: Long) extends TKModel
object Track extends TKModelFactory[Track]
How would I write something in TKModel such that new Track(1, "x", 1).someMethod() could actually call Track.objectMethod()
Yes I can write val CO = MyCompanionObject along with something like implicit val CO: ??? in the TKModel abstract class and make all the calls hang off of that value. Trying to find any incantation that makes the compiler happy for that however seems to be mission impossible. And since I can't declare that I can't reference it in any placeholder methods in the abstract class either.
Is there a more elegant way to simply get a reference to a case classes companion object?
My specific question, as the above has been asked before (but not yet answered it seems), is there a way to handle the inheritance of both the companion object and the case classes and find the reference such that I can code common method calls in the abstract class?
Or is there a completely different and better model?
If you change TKModel a bit, you can do
abstract class TKModel[T <: TKModel] {
...
def companion: TKModelFactory[T]
def someMethod() = companion.objectMethod()
}
case class Track(id: Long, name: String, statusID: Long) extends TKModel[Track] {
def companion = Track
}
object Track extends TKModelFactory[Track] {
def objectMethod() = ...
}
This way you do need to implement companion in each class. You can avoid this by implementing companion using reflection, something like (untested)
lazy val companion: TKModelFactory[T] = {
Class.forName(getClass.getName + "$").getField("MODULE$").
get(null).asInstanceOf[TKModelFactory[T]]
}
val is to avoid repeated reflection calls.
A companion object does not have access to the instance, but there is no reason the case class can't have a method that calls the companion object.
case class Data(value: Int) {
def add(data: Data) = Data.add(this,data)
}
object Data {
def add(d1: Data, d2: Data): Data = Data(d1.value + d2.value)
}
It's difficult. However you can create an implicit method in companion object. whenever you want to invoke your logic from instance, just trigger implicit rules and the implicit method will instantiate another class which will invoke whatever logic you desired.
I believe it's also possible to do this in generic ways.
You can implement this syntax as an extension method by defining an implicit class in the top-level abstract class that the companion objects extend:
abstract class TKModelFactory[T <: TKModel] {
def objectMethod(t: T)
implicit class Syntax(t: T) {
def someMethod() = objectMethod(t)
}
}
A call to new Track(1, "x", 1).someMethod() will then be equivalent to Track.objectMethod(new Track(1, "x", 1)).
When I use ArrayBuffer, I should use:
val arr = new ArrayBuffer[Int]
but when I use Map, I should use:
val map = Map[Int, Int]()
To understand why you need to use Map[T, T]() and not new Map[T, T](...), you need to understand the how the apply method on a companion object works.
A companion object is an object that has the same name as a class along with it. This object contains, generally, contains factory methods and other methods that you need to create (easily) the objects of the class.
To make sure that one doesn't have to go through a lot of verbose code, Scala makes use of the apply method which is executed directly when you call the object as you would call a function.
So, the companion object of Map must look something like this:
object Map {
def apply[K, V](...) = new Map[K,V](...) // Or something like this
}
While the class would be something like
protected class Map[K, V](...) {
...
}
Now calling Map[String, String](...) you are actually calling the apply method of the Map companion object.
ArrayBuffer, here, does not have a companion object though. Thus, you need to create a new instance of the class yourself by directly using the constructor.
I have created a companion object for my Scala class with an apply method in it so that I can create an instance of my class without using 'new'.
object StanfordTokenizer{
def apply() = new StanfordTokenizer()
}
class StanfordTokenizer() extends Tokenizer{
def tokenizeFile(docFile: java.io.File) = new PTBTokenizer(new FileReader(docFile), new CoreLabelTokenFactory(), "").tokenize.map(x => x.word().toLowerCase).toList
def tokenizeString(str: String) = new PTBTokenizer(new StringReader(str), new CoreLabelTokenFactory(), "").tokenize.map(x => x.word.toLowerCase()).toList
}
However when I try to instantiate the StanfordTokenizer class without 'new' e.g. StandfordTokenizer.tokenizeString(str).
I get the error
value tokenizeString is not a member of object StanfordTokenizer
However, if I explicitly include the apply method like StandfordTokenizer.apply().tokenizeString(str) it does work.
I feel like I am missing something fundamental about companion objects. Can someone shed some light on this for me?
^
It's exactly as the compiler message says. tokenizeString is a member of the class StandfordTokenizer, but not its companion object. The companion object does not inherit any methods from the class. Therefore, in order to use tokenizeString, you need an instance of StandfordTokenizer in order to call it.
StandfordTokenizer.apply creates an instance of the class StandfordTokenizer, which has the method tokenizeString. It seems as though the class StandfordTokenizer holds no real information, and won't have more than one instance. If that is true, you should probably just make it an object, and you'll be able to acquire the behavior you're looking for.
object StanfordTokenizer extends Tokenizer {
def tokenizeFile(docFile: java.io.File) = ...
def tokenizeString(str: String) = ...
}
This should work as well (as a class):
StandfordTokenizer().tokenizeString(str)
StandfordTokenizer without parenthesis does not call apply, it references the object. StandfordTokenizer() does call apply, and creates a new instance of the class. This is probably the source of your confusion.
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.