Is the below Scala class is mutable or immutable?
I believe that its immutable as I can't edit the variables or access them once its created but whats making me doubt myself is the fact that it returns the current instance of a variable using its functions. It also does not have final in front of it which is further making me doubt myself.
class person(name:String, dob:String){
def getName = name
def getDob = dob
def display() = {
println("Name "+name+" dob: "+dob)
}
}
Thanks,
You have a misconception with the term Immutable:
I believe that its immutable as I can't edit the variables or access
them once its created
That's the definition of a private thing (method, variable, ...). Immutability refers to the fact that you cannot mutate state, that is, you can't change the value of something unless you create a new instance of it.
Let's see it with an example:
trait Foo{
def myMutableValue: Int
}
class Clazz extends Foo{
var myMutableValue = 1
def changeState(): Int = {
myMutableValue += 1
myMutableValue
}
}
val bar = new Clazz
bar.changeState() // myMutableValue = 2
bar.changeState() // myMutableValue = 3
bar.changeState() // myMutableValue = 4
bar.myMutableValue // myMutableValue = 4
With that example, in your instance of Clazz (bar) you're changing the state of a class attribute, in this case myMutableValue is changing its value every time I invoke changeState.
Please note that the class is public by default and changeState is also public and that doesn't means that is immutable.
Now, let's see an immutable approach:
trait Foo{
def myMutableValue: Int
}
class Clazz extends Foo{
val myMutableValue = 1
def changeState(): Int = myMutableValue + 1
}
val instance = new Clazz
instance.changeState() // myMutableValue = 2
instance.changeState() // myMutableValue = 2
instance.changeState() // myMutableValue = 2
instance.myMutableValue // 1
With this approach, every call to changeState will evaluate to 2, no matter how many times I call the function. That is, because we're dealing with an immutable value (val myMutableValue = 1). Every invocation of changeState will perform the evaluation and return a copy of that value. You're not modifying in any way the value of myMutableValue.
Please take a look to this and this.
Also, please take a look at your code, you have some errors:
By convention, class name should be capitalized (Person instead of person).
You don't need to reassign your class values with def (def getNameand def getDob). You can use class values as is.
Lastly:
It also does not have final in front of it which is further making me
doubt myself.
Again, you're talking about different things. final, as in Java, is a modifier to prevent your class to be extended. It doesn't relate in any way to immutability In adition, if you want to prevent mutability in your subclass you have to make all their members final (see this).
Since your example is coded in Scala you have all the tools that the language itself offers at your disposal (e.g. val, sealed, final)
Please note that I've used a trait to explain the possible use of def.
EDIT: about final modifier and immutability
Thanks to #Silvio Mayolo and #puhlen for the comments and clarification about final
Related
I have a working Scala application in production that is using a object which has several methods defined inside it.
There are new requirements for this application where I will have to rewrite (override) few of the methods from that object while reusing the definitions of remaining methods from that object.
How can I create a new object inheriting the original one so that I can override the definitions of a few selected methods?
A Scala object cannot inherit from another Scala object so the obvious way is not possible.
If you can modify the original object then create a class that implements all the functionality and make the original object inherit from that class. Your new object can then inherit from the same class and override the methods that you want to change. However this will create two copies of any values in the base class, so it is not suitable for an object that contains a lot of data or does any one-off initialisation.
If you cannot modify the original object then you will have to copy all the methods of the first object in your new object. vals can be copied directly. defs can be copied using eta expansion:
def v = Original.v // This is a simple value
def f = Original.f _ // This is a function value
Using def rather than val here will avoid storing multiple copies of the original values and will prevent lazy values from being computed until they are needed.
Using eta expansion will make f a function value rather than a method which may or may not be a problem depending on how it is used. If you require f to be a method then you will have to duplicate the function signature and call the original f:
def f(i: Int) = Original.f(i) // This is a method
My suggestion would be to move the code/logic to a trait or abstract class and have both objects extend these.
On the upside this would also give you better testability.
Another more hacky approach could be to not use the class/type system at all and jsut forward the methods using a new singleton objec:
scala> object A {def foo: String = "foo" ; def bar:Int = 0}
defined object A
scala> object B { def foo = A.foo; def bar = "my new impl" }
defined object B
scala> A.foo
res3: String = foo
scala> B.foo
res4: String = foo
scala> A.bar
res5: Int = 0
scala> B.bar
res6: String = my new impl
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.
Consider the following case:
trait A {
protected val mydata = ???
def f(args) = ??? //uses mydata
}
class B
class C
class D(arg1: String) extends B with A {
override val mydata = ??? /// some calculation based on arg1
}
class E(arg1: String) extends C with A{
override val mydata = ??? /// some calculation based on arg1
}
A must be a trait as it is used by different unrelated classes. The problem is how to implement the definition of mydata.
The standard way (suggested in many places would be to define mydata as def and override it in the children. However, if f assumes mydata never changes then it can cause issues when some child extends with a function which changes between calls instead of with a val.
Another way would be to do:
trait A {
protected val mydata = g
protected def g()
}
The problem with this (beyond adding another function) is that if g depends on construction variables in the child then these must become members of the child (which can be a problem for example if the data is large and given in the construction):
class D(arg1: Seq[String]) {
def g() = ??? // some operation on arg1
}
If I leave the val in the trait as abstract I can reach issues such as those found here).
What I am looking for is a way to define the value of the val in the children, ensuring it would be a val and without having to save data for late calculations. Something similar as to how in java I can define a final val and fill it in the constructor
The standard way (suggested in many places would be to define mydata as def and override it in the children... If I leave the val in the trait as abstract I can reach issues such as those found here).
This is a common misunderstanding, shown in the accepted answer to the linked question as well. The issue is implementing as a val, which you require anyway. Having a concrete val which is overridden only makes it worse: abstract one can at least be implemented by a lazy val. The only way to avoid the issue for you is to ensure mydata is not accessed in a constructor of A or its subtypes, directly or indirectly, until it's initialized. Using it in f is safe (provided f is not called in a constructor, again, which would be an indirect access to mydata).
If you can ensure this requirement, then
trait A {
protected val mydata
def f(args) = ??? //uses mydata
}
class D(arg1: String) extends B with A {
override val mydata = ??? /// some calculation based on arg1
}
class E(arg1: String) extends C with A{
override val mydata = ??? /// some calculation based on arg1
}
is exactly the correct definition.
If you can't, then you have to live with your last solution despite the drawback, but mydata needs to be lazy to avoid similar initialization order issues, which would already give the same drawback on its own.
New to scala and trying to get the hang of the class system. Here's a simple set up:
sealed trait Shape{
def sides:Int
}
final case class Square() extends Shape {
def sides() = 4
}
final case class Triangle() extends Shape {
def sides() = 3
}
Now, I want to create a function that takes anything of type shape, which we know will have a sides() method implemented, and make use of that method.
def someFunction(a: Shape)={
val aShape = a()
aShape.sides()
}
But this hits an error at val aShape = a(), as there's no type a.
I realize that in this example, it's excessive to create someFunction, since sides() can be accessed directly from the objects. But my primary question is in the context of someFunction - I'd like to pass a class to a function, and instantiate an object of that class and then do something with that object. Thanks for your help.
What are you trying to do with that line of code? You already have a shape, the one passed in called a. Just remove that line and call a.sides().
Stylistically, there are several problems. First of all, class names should start with a capital letter. Second, sides seems like an immutable property, not a mutating method, so it should be declared and overridden with no parentheses. You also need override modifiers in your subclass. Last, you can do without the empty braces: {4} should just be 4.
There is several methods to do this. One is a complex one using reflection, second is little bit simplier, using a builder and third is most straightforward for your use case.
Just change definition of someFunction to
def someFunction(a: ()=>Shape)={
val aShape = a()
aShape.sides
}
so someFunction(Square) return 4 and someFunction(Triangle) returns 3 . Note this work only with case classes because real thing, we are passing here is not class itself, but it's auto-generated companion object
But more often there no need to define classes, you could write inside any context except top level thing just like
def square() = new Shape{
def sides() = 4
}
def triangle() = new Shape{
def sides() = 3
}
Next thing: methods with empty parameter list are generally reading as method that have side effects. So it is more convenient to define your type like
sealed trait Shape{
def sides:Int
}
and if you define your builders like
def square = new Shape{
def sides = 4
}
def triangle = new Shape{
def sides = 3
}
you should use them as someFunction(square _) telling, that you gonna use method call and not the value it's returning
And last thing is: if you really need the code, that creates some object, but it could contain complex computations, resource handling or some probable exception, so you want to hold over it's execution until it' really needed, you could use call-by-name parameters which is equivalent to R , which i assume you are familiar with
Unless shape has an apply function, you cannot call () on a shape object.
If you want to assign aShape to a, simply write val aShape = a.
But since I do not see the added value, you might as well call the sides function directly on a:
def someFunction(a:shape) = {
val sides = a.sides
// use sides
}
This is the closest translation for what you wrote:
sealed trait Shape {
def sides: Int
}
case object Square extends Shape {
override val sides = 4
}
case object Triangle extends Shape {
override val sides = 3
}
def someFunction(a: Shape) =
val shapeSides = a.sides
Some notes:
Classes in scala should be CamelCase
Your subclasses have no instance members, so you can use a singleton object
You if you have a: Shape it means that a is a Shape, and you haven't defined anything that would let you call () on it.
You can omit braces when there's only one expression inside
You can override a def with val if it's static
Search results so far have led me to believe this is impossible without either a non-primary constructor
class Foo { // NOT OK: 2 extra lines--doesn't leverage Scala's conciseness
private var _x = 0
def this(x: Int) { this(); _x = x }
def x = _x
}
val f = new Foo(x = 123) // OK: named parameter is 'x'
or sacrificing the name of the parameter in the primary constructor (making calls using named parameters ugly)
class Foo(private var _x: Int) { // OK: concise
def x = _x
}
val f = new Foo(_x = 123) // NOT OK: named parameter should be 'x' not '_x'
ideally, one could do something like this:
class Foo(private var x: Int) { // OK: concise
// make just the getter public
public x
}
val f = new Foo(x = 123) // OK: named parameter is 'x'
I know named parameters are a new thing in the Java world, so it's probably not that important to most, but coming from a language where named parameters are more popular (Python), this issue immediately pops up.
So my question is: is this possible? (probably not), and if not, why is such an (in my opinion) important use case left uncovered by the language design? By that, I mean that the code either has to sacrifice clean naming or concise definitions, which is a hallmark of Scala.
P.S. Consider the case where a public field needs suddenly to be made private, while keeping the getter public, in which case the developer has to change 1 line and add 3 lines to achieve the effect while keeping the interface identical:
class Foo(var x: Int) {} // no boilerplate
->
class Foo { // lots of boilerplate
private var _x: Int = 0
def this(x: Int) { this(); _x = x }
def x = _x
}
Whether this is indeed a design flaw is rather debatable. One would consider that complicating the syntax to allow this particular use case is not worthwhile.
Also, Scala is after all a predominantly functional language, so the presence of vars in your program should not be that frequent, again raising the question if this particular use case needs to be handled in a special way.
However, it seems that a simple solution to your problem would be to use an apply method in the companion object:
class Foo private(private var _x: Int) {
def x = _x
}
object Foo {
def apply(x: Int): Foo = new Foo(x)
}
Usage:
val f = Foo(x = 3)
println(f.x)
LATER EDIT:
Here is a solution similar to what you originally requested, but that changes the naming a bit:
class Foo(initialX: Int) {
private var _x = initialX
def x = _x
}
Usage:
val f = new Foo(initialX = 3)
The concept you are trying to express, which is an object whose state is mutable from within the object and yet immutable from the perspective of other objects ... that would probably be expressed as an Akka actor within the context of an actor system. Outside the context of an actor system, it would seem to be a Java conception of what it means to be an object, transplanted to Scala.
import akka.actor.Actor
class Foo(var x: Int) extends Actor {
import Foo._
def receive = {
case WhatIsX => sender ! x
}
}
object Foo {
object WhatIsX
}
Not sure about earlier versions, but In Scala 3 it can easily be implemented like follows:
// class with no argument constructor
class Foo {
// prive field
private var _x: Int = 0
// public getter
def x: Int = _x
// public setter
def x_=(newValue: Int): Unit =
_x = newValue
//auxiliary constructor
def this(value: Int) =
this()
_x = value
}
Note
Any definition within the primary constructor makes the definition public, unless you prepend it with private modifier
Append _= after a method name with Unit return type to make it a setter
Prepending a constructor parameter neither with val nor with var, makes it private
Then it follows:
val noArgFoo = Foo() // no argument case
println(noArgFoo.x) // the public getter prints 0
val withArgFoo = Foo(5) // with argument case
println(withArgFoo.x) // the public getter prints 5
noArgFoo.x = 100 // use the public setter to update x value
println(noArgFoo.x) // the public getter prints 100
withArgFoo.x = 1000 // use the public setter to update x value
println(withArgFoo.x) // the public getter prints 1000
This solution is exactly what you asked; in a principled way and without any ad hoc workaround e.g. using companion objects and the apply method.