I'm new to scala, and is trying to follow the tutorial on the documentation. I understand that this is used to 'access' a class' methods or fields, but on this code block, this is called as without any 'option' but it default to call the 'toString' method.
Here's the code block i'm talking about
class Person(var firstName: String, var lastName: String) {
println("the constructor begins")
// 'public' access by default
var age = 0
// some class fields
private val HOME = System.getProperty("user.home")
// some methods
override def toString(): String = s"$firstName $lastName is $age years old"
def printHome(): Unit = println(s"HOME = $HOME")
def printFullName(): Unit = println(this)
printHome()
printFullName()
println("you've reached the end of the constructor")
}
Output in REPLL:
scala> val p = new Person("Kim", "Carnes")
the constructor begins
HOME = /Users/al
Kim Carnes is 0 years old
you've reached the end of the constructor
p: Person = Kim Carnes is 0 years old
Thanks to Luis. His answer:
println calls the toString method of whatever is passed to it. So the object itself was passed to the println function which then called toString to it. Does that makes sense?
Basically, println(this) has the same output when you call println(p).
Related
I have a case class for configuration parameters which is populated (using NO external library) before starting the actual application.
I pass this config object through out the application and in too many places.
Now the question is can this object be made global so I can refer it across the application as the values are going to be constant.
case class ConfigParam() extends Serializable {
var JobId: Int = 0
var jobName: String = null
var snapshotDate: Date = null
}
val configParam = ???
val ss = getSparkSession(configParam) //Method call...
Using ConfigParam as a global object could have bad implications for you. First of all, it will make harder to test any function which is using that global object.
Maybe you could just pass ConfigParam as an implicit argument?
For example, let's say you've got 3 functions:
def funA(name: String)(implicit configParam: ConfigParam): String = ???
def funB(number: Int)(implicit configParam: ConfigParam): String = ???
//you don't have to explicitily pass config param to funA or funB
def funC(name: String)(implicit configParam: ConfigParam): String = funA(name) + funB(100)
implicit val configParam = ??? //you need to initialise configParams as implicit val
funC("somename") //you can now just call funC without explicitly passing configParam
//it will be also passed to all function calls inside funC
//as long as they've got implicit parameter list with ConfigParam
Another solution could be to use some kind of dependency-injection framework, like guice.
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
I am learning the scala and I have try with the following code.
object Demo7 {
def main(args: Array[String]): Unit = {
class Person(val fullName: String) {
println(s"This is the primary constructor. Name is ${fullName}")
val initial = fullName.substring(0, 1) // Computed during initialization
//def this(firstName: String, lastName: String) = this(s"$firstName $lastName")
}
new Person("Tek Tuk")
new Person("Tek Tuk").fullName
}
}
then I run I get the same returned result as each call.
for my understanding this line
new Person("Tek Tuk").fullName
Shouldn't compile, anyone can explain me why this line get compile and return the same result as the first line?
Thank you.
If you're asking why you're allowed to access the fullName field of your Person class, that's because you've declared it as a val in the parameter list.
This is the same as declaring it a public final field in Java. If you want it to be private, just remove the val part, i.e.
class Person(fullName: String) {
(...)
}
As for why both calls "return" the same thing - they don't.
new Person("Tek Tuk") returns an instance of Person.
new Person("Tek Tuk").fullName returns "Tek Tuk" - a String. You created another instance of Person with the same fullName and you called fullName on it.
Both, however, print "This is the primary constructor. Name is Tek Tuk", because you called the same constructor in both cases and you have a println that prints this in the constructor.
I'm reading a book "Scala in action" to learn scala. On page 59, the author provide following code. But when I run it, it doesn't compile.
class Person(var firstName:String, var lastName:String, private var _age:Int) {
def age = _age
def age_ = (newAge: Int) = _age = newAge //Error
}
It reports:
<console>:3: ';' expected but '=' found.
def age_ = (newAge: Int) = _age = newAge}
This book use scala 2.10. I'm using scala 2.11.
Does scala change the usage of setter method in 2.11?
I'm not sure what the context of def age_ = (newAge: Int) = _age = newAge or what the author is trying to demonstrate with that line. Parameters of the constructor are public by default so removing private allows you to use the setter for free.
scala> class Person(var firstName:String, var lastName:String, var _age:Int) {}
defined class Person
scala> val bob = new Person("Bob", "Smith", 42)
bob: Person = Person#290d210d
scala> bob._age = 43
bob._age: Int = 43
scala> bob._age
res9: Int = 43
It looks like the only problem is the missprint ' ' ('space') simbol of the errored line between 'underscore' and 'equals'.
The right code is:
def age_= (newAge: Int) = _age = newAge //NO Error
Lets remove syntax sugar (plus abit classic formatting) and we'll have more clear method that is really the setter for "variable" age "backed" to private var _age
def age_=(newAge: Int): Unit = {
_age = newAge
}
Think about such variables as if it is virtual-like: this setter with previously defined getter but possibly with no storage at all. For instance, both uses HTTP requests (GET & PUT) to store/retrieve the value).
So, the first '=' is really the part of the method name age_= that is the syntax Scala uses to define setter for age.
I was wondering if there is a shorter version of
var longVariableName: MyType = MyTyp("Value")
longVariableName = longVariableName.addSomething("added")
case class MyType(value: String) {
def addSomething(add: String): MyType = ???
}
Maybe something like
var longVariableName: MyType = MyType("Value")
longVariableName = _.addSomething("extended")
Would be so nice :)
Thank you
I guess the easiest way would be:
val longVariableName = MyTyp("Value")
.addSomething("added")
.addSomethingElse("other")
.addSomeMore("stuff")
As long as each method returns the base type (i.e. "Builder" pattern), you can further chain calls.
In this way, you use a value (not a variable) and given that each method call returns a new instance of the case class, it's immutable, with no side-effect.
Furthermore, case classes support a builder-like pattern with the copy method, which allows to "add" information down the road in an immutable way.
Something like this:
case class Player(name:String, rank:Option[String] = None) {
def withRank(rank:Int)= this.copy(rank=Some(s"top${100-rank}%"))
}
val player = Player("sparky").withRank(5)
(Or multi-line)
val player = Player("sparky")
.withRank(5)
You can define a + method for your case class:
case class MyType(value: String) {
def +(add: String) = MyType(value + add)
}
var longVariableName: MyType = MyType("Value")
longVariableName += "extended"
You can use the copy method without defining anything else.
case class MyType(value: String, otherValue: String, otherOthervalue: String)
val longName = MyType("Value","OtherValue","OtherOtherValue")
val longerName = longName.copy(value=longName.value+"extended")