How to qualify methods as static in Scala? - scala

I have a class
class MyClass {
def apply(myRDD: RDD[String]) {
val rdd2 = myRDD.map(myString => {
// do String manipulation
}
}
}
object MyClass {
}
Since I have a block of code performing one task (the area that says "do String manipulation"), I thought I should break it out into its own method. Since the method is not changing the state of the class, I thought I should make it a static method.
How do I do that?
I thought that you can just pop a method inside the companion object and it would be available as a static class, like this:
object MyClass {
def doStringManipulation(myString: String) = {
// do String manipulation
}
}
but when I try val rdd2 = myRDD.map(myString => { doStringManipulation(myString)}), scala doesn't recognize the method and it forces me to do MyClass.doStringManipulation(myString) in order to call it.
What am I doing wrong?

In Scala there are no static methods: all methods are defined over an object, be it an instance of a class or a singleton, as the one you defined in your question.
As you correctly pointed out, by having a class and an object named in the same way in the same compilation unit you make the object a companion of the class, which means that the two have access to each others' private fields and methods, but this does not mean they are available without specifying which object you are accessing.
What you want to do is either using the long form as mentioned (MyClass.doStringManipulation(myString)) or, if you think it makes sense, you can just import the method in the class' scope, as follows:
import MyClass.doStringManipulation
class MyClass {
def apply(myRDD: RDD[String]): Unit = {
val rdd2 = myRDD.map(doStringManipulation)
}
}
object MyClass {
private def doStringManipulation(myString: String): String = {
???
}
}
As a side note, for the MyClass.apply method, you used the a notation which is going to disappear in the future:
// this is a shorthand for a method that returns `Unit` but is going to disappear
def method(parameter: Type) {
// does things
}
// this means the same, but it's going to stay
// the `=` is enough, even without the explicit return type
// unless, that is, you want to force the method to discard the last value and return `Unit`
def method(parameter: Type): Unit = {
// does things
}

You should follow scala's advice.
val rdd2 = myRDD.map(MyClass.doStringManipulation)

Write this inside the class then it will work as expected.
import MyClass._

Related

Scala: why can't I declare values in a constructor?

I would like to declare some auxiliary values inside a case class constructor, but it seems not to be correct Scala.
In short, the following piece of code is correct:
case class Something(
text1: String,
text2: String
) {
def this(datetime: LocalDateTime) {
this(
s"date: ${datetime.toLocalDate.toString()}",
s"time: ${datetime.toLocalTime.toString()}"
)
}
}
and the following is not:
case class Something(
text1: String,
text2: String
) {
def this(datetime: LocalDateTime) {
val date = datetime.toLocalDate.toString()
val time = datetime.toLocalTime.toString()
this(
s"date: $date",
s"time: $time"
)
}
}
even though the latter would be more legible and easier to maintain. (Imagine using more complex operations than just calling two methods.) Why is that?
Is there another way to write a constructor like that or a way to work around this?
In Scala first call must be to primary constructor. After that you can have as much code as you want. Read this for explanation.
Similar rule applies to Java for this and super. Not exactly same though. Read this.
The reason why this and super must be first is, that one can set fields to various values before that actual this(x, y) is called. This means object is being constructed and different values can be visible to any thread that may have reference to the object while construction is in progress.
Thanks.
In your second case you are not allowed to define variables inside constructor before this(params) call, as computing inside constructors are discouraged in scala class or case class. One way you can fix it is pass inline constructor params.
test("test case class custom constructor") {
case class Something(text1: String,text2: String) {
def this(datetime: LocalDateTime) {
this(datetime.toLocalDate.toString(), datetime.toLocalTime.toString())
//you can do whatever you want after this(x, y) is invoked
val testVal = "apple"
println(testVal)
}
}
new Something(LocalDateTime.now()).text1 shouldBe "2017-07-16"
new Something(LocalDateTime.now()).text2 should not be empty
}
Another way (Encouraged way) is define case class and then define apply inside a companion object as below (for older version maybe 2.11.8, companion object had to be defined first and only case class which seems to be fixed now - https://issues.scala-lang.org/browse/SI-3772)
test("test class with companion apply method") {
case class Something(val text1: String, val text2: String) {}
object Something {
def apply(datetime: LocalDateTime): Something = {
val x = datetime.toLocalDate.toString()
val y = datetime.toLocalTime.toString()
new Something(x, y)
}
}
Something(LocalDateTime.now()).text1 shouldBe "2017-07-16"
Something(LocalDateTime.now()).text2 should not be empty
}
scastie code - https://scastie.scala-lang.org/prayagupd/yn2bJWHkQ6Gbli5Ll6I6CQ/1
Auxiliary constructors have a constraint that it should call a previous auxiliary constructor or primary constructor on the first line of its body. The second code does not follow that rule. Hence the error.

Scala - Add member variable to class from outside

Is it possible to add a member variable to a class from outside the class? (Or mimic this behavior?)
Here's an example of what I'm trying to do. I already use an implicit conversion to add additional functions to RDD, so I added a variable to ExtendedRDDFunctions. I'm guessing this doesn't work because the variable is lost after the conversion in a rdd.setMember(string) call.
Is there any way to get this kind of functionality? Is this the wrong approach?
implicit def toExtendedRDDFunctions(rdd: RDD[Map[String, String]]): ExtendedRDDFunctions = {
new ExtendedRDDFunctions(rdd)
}
class ExtendedRDDFunctions(rdd: RDD[Map[String, String]]) extends Logging with Serializable {
var member: Option[String] = None
def getMember(): String = {
if (member.isDefined) {
return member.get
} else {
return ""
}
}
def setMember(field: String): Unit = {
member = Some(field)
}
def queryForResult(query: String): String = {
// Uses member here
}
}
EDIT:
I am using these functions as follows: I first call rdd.setMember("state"), then rdd.queryForResult(expression).
Because the implicit conversion is applied each time you invoke a method defined in ExtendedRDDFunctions, there is a new instance of ExtendedRDDFunctions created for every call to setMember and queryForResult. Those instances do not share any member variables.
You have basically two options:
Maintain a Map[RDD, String] in ExtendedRDDFunctions's companion object which you use to assign the member value to an RDD in setMember. This is the evil option as you introduce global state and open pitfalls for a whole range of errors.
Create a wrapper class that contains your member value and is returned by the setMember method:
case class RDDWithMember(rdd: RDD[Map[String, String]], member: String) extends RDD[Map[String, String]] {
def queryForResult(query: String): String = {
// Uses member here
}
// methods of the RDD interface, just delegate to rdd
}
implicit class ExtendedRDDFunctions(rdd: RDD[Map[String, String]]) {
def setMember(field: String): RDDWithMember = {
RDDWithMember(rdd, field)
}
}
Beside the omitted global state, this approach is also more type safe because you cannot call queryForResult on instances that do not have a member. The only downsides are that you have to delegate all members of RDD and that queryForResult is not defined on RDD itself.
The first issue can probably be addressed with some macro magic (search for "delegate" or "proxy" and "macro").
The later issue can be resolved by defining an additional extension method in ExtendedRDDFunctions that checks if the RDD is a RDDWithMember:
implicit class ExtendedRDDFunctions(rdd: RDD[Map[String, String]]) {
def setMember(field: String): RDDWithMember = // ...
def queryForResult(query: String): Option[String] = rdd match {
case wm: RDDWithMember => Some(wm.queryForResult(query))
case _ => None
}
}
import ExtendedRDDFunctions._
will import all attributes and functions from Companion object to be used in the body of your class.
For your usage look for delagate pattern.

Force initialization of Scala singleton object

I'm working on an automatic mapping framework built on top of Dozer. I won't go into specifics as it's not relevant to the question but in general it's supposed to allow easy transformation from class A to class B. I'd like to register the projections from a class's companion object.
Below is a (simplified) example of how I want this to work, and a Specs test that assures that the projection is being registered properly.
Unfortunately, this doesn't work. From what I can gather, this is because nothing initializes the A companion object. And indeed, if I call any method on the A object (like the commented-out hashCode call, the projection is being registered correctly.
My question is - how can I cause the A object to be initialized automatically, as soon as the JVM starts? I don't mind extending a Trait or something, if necessary.
Thanks.
class A {
var data: String = _
}
class B {
var data: String = _
}
object A {
projekt[A].to[B]
}
"dozer projektor" should {
"transform a simple bean" in {
// A.hashCode
val a = new A
a.data = "text"
val b = a.-->[B]
b.data must_== a.data
}
}
Short answer: You can't. Scala objects are lazy, and are not initialized until first reference. You could reference the object, but then you need a way of ensuring the executing code gets executed, reducing the problem back to the original problem.
In ended up doing this:
trait ProjektionAware with DelayedInit
{
private val initCode = new ListBuffer[() => Unit]
override def delayedInit(body: => Unit)
{
initCode += (() => body)
}
def registerProjektions()
{
for (proc <- initCode) proc()
}
}
object A extends ProjektionAware {
projekt[A].to[B]
}
Now I can use a classpath scanning library to initialize all instances of ProjektionAware on application bootstrap. Not ideal, but works for me.
You can force the instantiation of A to involve the companion object by using an apply() method or some other sort of factory method defined in the object instead of directly using the new A() constructor.
This does not cause the object to be initialized when the JVM starts, which I think as noted in another answer can't generally be done.
As Dave Griffith and Don Roby already noted, it cannot be done at JVM startup in general. However maybe this initialization could wait until first use of your framework?
If so, and if you don't mind resorting to fragile reflection tricks, in your --> method you could obtain reference to the companion object and get it initialize itself.
You can start at Getting object instance by string name in scala.
We could use this sort of a way to ensure that companion object gets initialized first and then the class gets instantiated.
object B {
val i = 0
def apply(): B = new B()
}
class B {
// some method that uses i from Object B
def show = println(B.i)
}
// b first references Object B which calls apply()
// then class B is instantiated
val b = B()

Inheritance and initialization in Scala

I have two Scala classes that look like this (paraphrased):
abstract class GenericParser[T] {
val lineFilter : String => Boolean
parseData()
def parseData() : T {
for( line <- .... if lineFilter(line) )
// do things
}
}
class SalesParser extends GenericParser[SalesRow] {
val lineFilter = line => !line.startsWith("//")
// ....
}
The problem is that lineFilter is null in parseData, presumably because parseData is called while the primary GenericParser constructor is still running, so the subclass hasn't fully initialized its members.
I can work around this by making lineFilter a def instead of a val, but is this expected behavior? It doesn't seem right that this problem should only become apparent after getting an NPE at runtime.
It is indeed the expected behavior, and is exactly the same problem as in this question:
Scala 2.8: how to initialize child class
You can basically copy-paste the answer form that question. Solutions include:
def or lazy val instead of val
early initialization of lineFilter
redesign of your classes to avoid the “virtual method call from superclass's constructor which accesses uninitialized subclass values” problem. For instance, why would you want to store the filter function in a val or return in from a def, while it could be implemented as a method?
abstract class GenericParser[T] {
def lineFilter(line: String): Boolean
parseData()
def parseData() : T {
for( line <- .... if lineFilter(line) )
// do things
}
}
class SalesParser extends GenericParser[SalesRow] {
def lineFilter(line: String) = !line.startsWith("//")
}

How do I declare a constructor for an 'object' class type in Scala? I.e., a one time operation for the singleton

I know that objects are treated pretty much like singletons in scala. However, I have been unable to find an elegant way to specify default behavior on initial instantiation. I can accomplish this by just putting code into the body of the object declaration but this seems overly hacky. Using an apply doesn't really work because it can be called multiple times and doesn't really make sense for this use case.
Any ideas on how to do this?
Classes and objects both run the code in their body upon instantiation, by design. Why is this "hacky"? It's how the language is supposed to work. If you like extra braces, you can always use them (and they'll keep local variables from being preserved and world-viewable).
object Initialized {
// Initalization block
{
val someStrings = List("A","Be","Sea")
someStrings.filter(_.contains('e')).foreach(s => println("Contains e: " + s))
}
def doSomething { println("I was initialized before you saw this.") }
}
scala> Initialized.doSomething
Contains e: Be
Contains e: Sea
I was initialized before you saw this.
scala> Initialized.someStrings
<console>:9: error: value someStrings is not a member of object Initialized
Initialized.someStrings
Rex has it right, I just wanted to point out a pattern I use a lot, that saves you from having to use vars, while avoiding namespace pollution by intermediate values.
object Foo {
val somethingFooNeeds = {
val intermediate = expensiveCalculation
val something = transform(intermediate)
something
}
}
If it makes you feel better, you can create some class with protected constructor and object will create singleton of this class:
sealed class MyClass protected (val a: String, b: Int) {
def doStuff = a + b
}
object MyObject extends MyClass("Hello", b = 1)
Also notice, that sealed stops other classes and objects to extend MyClass and protected will not allow creation of other MyClass instances.
But I personally don't see any problems with some code in the body of the object. You can also create some method like init and just call it:
object MyObject {
init()
def init() {
...
}
}
The body of object and class declarations IS the default constructor and any code placed in there will be executed upon first reference, so that is exactly the way to do it.