Using parent class object to instantiate a child class object in Scala? - scala

For example, there are two scala class called A and B.
class A{
val aVariable:String="a"
}
class B(val newVariable:String) extends A{
def newMethod(): Unit ={
}
}
The problem is how to use an A object to instantiate a B object with its variable?
For example, a function take an A object and a string to create a B object
val bObject:B=BuildFunc(new A(),"string")
And if A contains much variables, is there a way to avoid setting each of manually?
It seems in Java this could be done by code like super(aObject), is there equivalent method in Scala?

There's multiple solutions here. For example, one would be defining A's promoting the A's constructor parameters into fields:
class A(val foo: String)
class B(override val foo: String, val baz: String) extends A(foo)
If you can't change A's definition though then maybe this will help:
class A {
val foo: String = "foo"
}
class B(override val foo: String, val baz: String) extends A
Hope that helps.

Related

How to pass instance of case class as argument to function used inside map in spark

I have this case class like this:
case class Data(a: String, b: String, c: String);
and this dataset like this:
val dataset: Dataset<SomeDataset>;
and function inside companion object (to prevent task not serializable exception)
object MyObj {
def doSomething(value: SomeDataset, data: Data //instance of case class) {...}
}
I would like to do something like this:
val data = Data(...) //instance of case class
dataset.map { doSomething(_, data) }
After this I am getting Task not serializable exception from spark.
If i remove second argument from doSomething function it works find.
I tried even to make Data case class extends Serializable interface and it still does not work.
Like this:
case class Data(a: String, b: String, c: String) extends Serializable
How do i make this working?
One of the differences between case classes and classes in Scala is that case classes extend Serializable interface out of the box:
scala> case class FirstClass()
// defined case class FirstClass
scala> val f = FirstClass()
val f: FirstClass = FirstClass()
scala> f.isInstanceOf[Serializable]
val res1: Boolean = true
scala> class SecondClass
// defined class SecondClass
scala> val s = new SecondClass()
val s: SecondClass = SecondClass#y978y4f
scala> s.isInstanceOf[Serializable]
val res2: Boolean = false
So now, spark can take care of serializing your object through nodes (instances of your case classes), but you're also trying to do some operation on them. Spark needs to serialize your operation as well, since it needs to be done on different nodes. Now this post might help you find out some scenarios that TaskNotSerializableException could happen, my guess is that doSomething is a method, so spark cannot serialize it. So it might help if you could define it as a function:
object MyObj {
val doSomething: (SomeDataset, Data) => SomeOtherData = {...}
}

How can I extend an abstract class with an optional member in Scala?

I have an abstract base class, Foo, whose constructor I'd like to have an optional parameter. If none is provided, I'll just give it a None value.
A source Foo will not have parents, so I'd just like to construct them without a list of parents (leave default value for parent list)
A derived Foo might have provided parents, so I'd like to mimic the signature of the Foo base class.
Below is my attempt:
abstract class Foo(val id: String, var parentIds: Option[List[String]]=None) { }
case class SourceFoo(override val id: String)
extends Foo(id, parentIds=None) { }
case class DerivedFoo(override val id: String,
override var parentIds: Option[List[String]])
extends Foo(id, parentIds) { }
I'm getting a compiler error that a mutable variable cannot be overridden (referencing the parentIds in the DerivedFoo constructor.
This list is subject to change, so I don't want to make it a val (which removes my compiler issues).
This is a very basic OO issue, so it must be simpler than I seem to be making it. How can I achieve my desired behavior idiomatically?
I managed to fix this after reading the documentation:
The constructor parameters of case classes are treated as public values and can be accessed directly.
Since my base class is abstract, I can simply extend it with default, val construction.
I simply need to specify that parentIds is a var in the DerivedFoo constructor.
abstract class Foo(id: String, parentIds: Option[List[String]]=None) { }
case class SourceFoo(id: String) extends Foo(id) { }
case class DerivedFoo(id: String, var parentIds: Option[List[String]]=None)
extends Foo(id, parentIds) { }
Here is another probably better way to go about it. Explictly acknowledge the difference between class parameters and class members. You also can make them private members if you like following this block of code.
abstract class Foo(identifier: String, parentIdentifiers: Option[List[String]]) {
val id = identifier
var parentIds = parentIdentifiers
}
case class SourceFoo(override val id: String) extends Foo(id, parentIdentifiers = None) { }
case class DerivedFoo(identifier: String, parentIdentifiers: Option[List[String]]) extends Foo(identifier, parentIdentifiers) { }
After that, you can create DerivedFoo and refer to the members as you are probably expecting, and you won't have two members with different names.
REPL output:
scala> DerivedFoo("1", Some(List("200","201","202")))
res0: DerivedFoo = DerivedFoo(1,Some(List(200, 201, 202)))
scala> res0.parentIds
res1: Option[List[String]] = Some(List(200, 201, 202))
scala> res0.parentIds = Some(List("800", "801", "802"))
res0.parentIds: Option[List[String]] = Some(List(800, 801, 802))
I think you can achieve your goal by changing the name of the parameter in the abstract class as follows.
abstract class Foo(val id: String, var parentIdentifiers: Option[List[String]]) {
parentIdentifiers = None
}
case class SourceFoo(override val id: String)
extends Foo(id, parentIdentifiers = None) { }
case class DerivedFoo(override val id: String,
var parentIds: Option[List[String]])
extends Foo(id, parentIds) { }
For the mutation, you can import scala.collection.mutable and use mutable.ListBuffer instead of List.
I assume of course, that you won't change the parentIds of a DerivedFoo instance from Some to None.
This will allow you use vals but still have mutable state.
But I wouldn't say mutable state is idiomatic Scala.
You usually use immutable val and List, and just copy the object whenever you want to change the list.
val fooA = SourceFoo("a")
val fooB = DerivedFoo("b", "a" :: Nil)
val fooB2 = fooB.copy(parentIds = fooB.parentIds :+ "x")
So to be more idiomatic, the simplest you can do is
sealed abstract class Foo(val id: String, val parentIdsOpt: Option[List[String]])
case class SourceFoo(override val id: String)
extends Foo(id, None)
case class DerivedFoo(override val id: String, val parentIds: List[String])
extends Foo(id, Some(parentIds))
Which is pretty close to what you had.
Note that DerivedFoo.parentIds isn't Option anymore, because DerivedFoo always has parents, so you don't have to deal with Option. (You still have to deal with empty list, though)
Also note the sealed keyword on the trait, which is not required, but recommended if you want to match on an instance of the abstract class or trait. (You can use sealed only if you own all the sub-classes, which seems to be the case in your example)

scala: how to update super class attributes

I am new to scala and have problem to update attributes.
I have a class that inherits from an abstract class as follows:
abstract class A(x:type1,y:type1){
val z:Option[type1]= None
def void:type2
}
class B extends A(x,y){
def this(x:type1,y:type1,z_:type1)= {this(x,y) val z=Some(z_)}
def void:type2 = ???
}
If I call new B(test,test,test) it doesn't update the value of z which remains None all the time.
What is the reason for this behavior?
With val you create immutable fields/variables. Declaring another one in the subclass. If you want to update it use var, in the superclass and assignment in the subclass. This should work:
abstract class A(x:type1,y:type1){
var z:Option[type1]= None
def void:type2
}
class B extends A(x,y){
def this(x:type1,y:type1,z_:type1)= {this(x,y) z=Some(z_)}
def void:type2 = ???
}

Scala: lock extended class

I'd like to "lock" a class, which is extended from a trait. Is it possible in Scala?
For example I have:
trait A {
val boris: String
val john: String
val number: Int
}
class B extends A {
// do something with these values
}
but can I ensure, that in class B no new values will be added if those aren't declared in trait A?
Thanks for your answers.
You cannot.
But if you simply mark the trait as sealed and provide a default implementation:
sealed trait A { val boris: String }
final class B(val boris: String) extends A {}
then people are free to create implicit value classes that make it look like new functionality has been added (except without actually creating the class):
implicit class MyB(val underlying: B) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B("fish")).sirob // "hsif"
You can also let the classes take a type parameter as a marker if you want to keep them straight at compile-time (though not runtime):
sealed trait A[T] { val boris: String }
final class B[T](val boris: String) extends A[T] {}
implicit class MyB(val underlying: B[Int]) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B[Int]("fish")).sirob // "hsif"
(new B[Char]("fish")).sirob // error: value sirob is not a member of B[Char]
So you could--especially with 2.10--simply lock everything and let users enrich the original interface this way.
I'm not sure if this covers your intended use case, though; it doesn't provide any inheritance.
Based on your example and my guess at what you are actually trying to do, you may want to consider just using case classes.
Extending a case class is generally avoided (I think it will spit out deprecation warnings if you try), so that will prevent people from wanting to extend your class in order to add functionality.
Translating your example into a case class:
case class A (boris: String, john: String, number: Int)
Then instead of extending A to change its values, you'd just make a new instance, e.g.
val a2 = someOtherA.copy(john="Doe")

Using scala constructor to set variable defined in trait

If I understand correctly, traits are the closest thing to Java interfaces and class constructors automatically set the variables.
But what if I have a class that extends a trait and has a constructor which sets a variable from the trait, so something like:
trait Foo {
var foo: String
}
class Bar (foo: String) extends Foo { /* ... */ }
Where I want the foo string of the trait been set when I make a Bar object.
The compiler seems to give me errors about this. What is the correct way to achieve this?
trait Foo { var foo: String = _ }
class Bar(foo0: String) extends Foo { foo = foo0 }
The trait declares an uninitialized var; the class then sets it equal to the input parameter.
Alternatively,
trait Foo {
def foo: String
def foo_=(s: String): Unit
}
class Bar(var foo: String) extends Foo {}
declares the getter/setter pair corresponding to a foo, which are set by the class.
Bar must define the abstract var foo in Foo (would be the same for a val). This can be done in the constructor
class Bar(var foo: String) extends Foo{...}
(of course, it could be done in the body of Bar too). By default, constructor parameters will be turned to private val if need be, that is if they are used outside the initiailization code, in methods. But you can force the behavior by marking them val or var, and possibly control the visibility as in
class X(protected val s: String, private var i: Int)
Here you need a public var to implement Foo.