what's the difference between these classes in Kotlin? - class

I'm a beginner in Kotlin!
Can we explain the difference between these classes in Kotlin
class Person(val name: String, val age: Int)
class Person(name: String, age: Int)
class Person(var name: String,var age: Int)
And how I add getter and setter for data class in Kotlin?

First you should try to read the difference in the manual:
https://kotlinlang.org/docs/reference/data-classes.html
https://kotlinlang.org/docs/reference/classes.html
But lets try to explain this:
class Person(val name: String, val age: Int)
The Kotlin compiler will generate for both constructor arguments corresponding fields storing the values and will generate respecting getters. The values are immutable because of the keyword val so there will not be any setters.
class Person(name: String, age: Int)
The arguments are only passed to the constructor but not stored as fields. So there will also be no getters and setters.
class Person(var name: String, var age: Int)
Like in the first example the values are stored in generated fields. But the values are mutable because of the keyword var so the compiler will generate getters and setters.
data is an additional (optional) keyword to put in front of the class declaration. This will in addition to the getters and setters generate a toString method printing the values of all attributes with their names and a hashCode method taking every value into account. As getters and setters are generated for data classes you don't need to add them manually.
Kotlin is a lot about reducing the manual work required to do by the developer in Java to be done by the compiler of Kotlin.

Related

Scala - Domain Objects with lots of fields

This might be a stupid question but I am relatively new to Scala so please bear with me. I am trying to model a domain object for a Spark job in Scala, which reflects the data structure of the source record and contains more than 100 fields. I am trying to figure out the best way to model this as I don't feel comfortable simply adding all the fields to a single case class. I thought about grouping closely associated fields into nested case classes but then I read in a few places that nesting case classes is not recommended. I would appreciate some input on what would be the best approach.
Edit: In response to Alvaro's comments:
So in essence we are saying that this is not recommended:
case class Product(name: String,
desc: String,
productGroup: String) {
case class ProductPack(packType: String,
packQuantity: Int,
packQuantityUnit: String,
packUnitPrice: Float)
}
While this would be fine:
case class Product(name: String,
desc: String,
productGroup: String,
productPack: ProductPack) {
}
case class ProductPack(packType: String,
packQuantity: Int,
packQuantityUnit: String,
packUnitPrice: Float) {
}
Your update is correct.
Another alternative: If a case class mostly makes sense in the context of another concept, sometimes I define the case class inside a companion to the concept:
case class Product(
name: String,
desc: String,
productGroup: String
productPack: Product.Pack
)
object Product {
case class Pack(
packType: String,
packQuantity: Int,
packQuantityUnit: String,
packUnitPrice: Float
)
}
That should also be fine. The class is contained in an object, but it is not "nested" in the Product class.

Scala adding an extra function to a Class

I encountered the following code while checking through a Scala code. I'm finding it difficult to understand what it does.
class Foo(val name: String, val age: Int, val sex: Symbol)
object Foo {
def apply(name: String, age: Int, sex: Symbol) = new Foo(name, age, sex)
}
Does it add a constructor method to the Class Foo which was already defined?
Is it possible to add extra methods to classes which are already defined using this syntax?
Does it add a constructor method to the Class Foo which was already
defined?
It adds syntax sugar to the class. Meaning, you can create an instance of Foo like this:
val foo = Foo()
Instead of
val foo = new Foo()
Is it possible to add extra methods to classes which are already
defined using this syntax?
In that regards, apply is special as the compiler knows it and expands Foo() to Foo.apply. This means that any other method you want to invoke, you'll have to call the Foo static object, but they will not apply to the Foo instance.
If you want to externally add methods to Foo, you can do so via an implicit class:
implicit class RichFoo(foo: Foo) extends AnyVal {
def fooDetails(): String = s"{Name: ${foo.name}, Age: ${foo.Age}"
}
Now you can call it on an instance of Foo:
val f = Foo()
println(f.fooDetails())
In the case, you can think of Foo.apply() as a static method.
Realistically, objects in Scala are implemented as Singleton instances.
Here's the documentation on that.
You can invoke any class or object instance in Scala if it has an apply method. What you're doing here is adding a constructor method to Foo's companion object so that when you call it, it will instantiate an instance of Foo.
It is not possible to add methods to an instance with this method. For that, you might be interested in the Scala Pimp My Library pattern which is implemented using implicits.
// the following are equivalent, given your code above
val x = new Foo("Jason", 29, 'Male)
val y = Foo.apply("Jason", 29, 'Male)
val z = Foo("Jason", 29, 'Male)
Please read about companion object: http://docs.scala-lang.org/tutorials/tour/singleton-objects.html hope this helps
It simplifies object creation for this type. Other way will be to create case class.
Looks like as duplicate to me:
Scala: companion object purpose
This pattern is commonly know as static factory methods. The code you provided is not very useful, but consider these additional factory methods (think of them as "named constructors"):
class Foo(val name: String, val age: Int, val sex: Symbol)
object Foo {
def apply(name: String, age: Int, sex: Symbol) = new Foo(name, age, sex)
def newMaleFoo(name:String,age:int) = new Foo(name,age,'male)
def newPeterFoo(age:int) = new Foo("Peter",age,'male)
}

How to not override a val of a parent class?

please take a look at the following code:
scala> sealed abstract class Person(val name: String)
defined class Person
scala> case class Student(id: Int, name: String) extends Person(name)
<console>:8: error: overriding value name in class Person of type String;
value name needs `override' modifier
case class Student(id: Int, name: String) extends Person(name)
^
This might be a trivial question, but after searching the web for quite some time, I wasn't able to figure out how to simply pass the string that Student's constructor will be provided as name to the Person's constructor. I don't want to override anything. What am I doing wrong?
Thank you very much in advance!
All constructor parameters of a case class are vals. That's the whole point. Roughly speaking, it is what gives you the ability to enjoy the benefits cases classes provide compared to regular classes: copying, extraction, pattern matching, etc.
If you want Student to be a case class, you should override name. Theoretically, you can avoid overriding it by giving the val a different name: case class Student(id: Int, studentName: String) extends Person(studentName) - this works, but just doesn't make very much sense - you end up having two different member vals whose values are always identical.
Alternatively, if there is an actual reason why you don't want to override name (I can't imagine what one could possibly be, but if ...), then Student should not be a case class: class Student(val id: Int, name: String) extends Person(name).

Scala - How to get constructore fields values in reflection?

I'm pretty new to scala and struggling a bit with reflection.
Given the below class:
class Person (name: String) {
.....
}
and the given instance:
val p = new Person ("MyName")
How can i retrieve the value "MyName" in reflection?
BTW - I tried with java reflection using getClass.getDeclaredFields(), but without luck...
Thanks!
name is not a member of the class in your example, it's just a function parameter of the constructor. The difference in scala in rather subtle, because the whole class is defined inside the constructor body, so, it is, effectively, a closure, and you can use the parameters everywhere, but still, there is a difference.
class Person(val name: String) or class Person(var name: String) declares a class with an instance member (either final or writable) name.
class Person(name: String) has no instance variables, name is just a parameter to the constructor.
Case classes are special, as they treat all constructor parameters as vals by default, this is "syntactic sugar": case class Person(name: String) really means `case class Person(val name: String).
I think you should add modifier var or val when defining constructor.
i.e,
class Person (var name: String) {
.....
}
and to retrieve value "MyName", you can do,
val p= new Person("MyName");
and Name is: p.name

How to define accessor method for default constructor parameter?

Trying to define an accessor method for default constructor parameter, i.e.:
class Person (age: Int) {
def age: Int = this.age
}
Which obviously results in a compiler error: ambiguous reference to overloaded definition, both method age in class Person of type => Int and value age in class Person of type Int match expected type Int
Is there a way in this context to distinguish between the member method name and auto-generated member value name?
Of course it's possible to change the name of either identifier, but is there a way in this scenario of actually specifying which identifier is referred to?
Just put "val" in front of constructor parameters that you want to expose as instance properties.
Use
class Person (val age: Int)
if you just want a getter or
class Person (var age: Int)
if you also want a setter.
The answers above are great wrt the uniform access principle. If you have or need Java style getters and setters you can also use the BeanProperty annotation.
class Person(#scala.reflect.BeanProperty var age: Int)
This will result in the following methods being created:
def getAge: Int = age
def setAge(age: Int) = this.age = age
If you instead use the BeanProperty for a val instead of a var, the setter won't be created, only the getter.
One other caveat, the setter method cannot be called from inside Scala. Instead, you should use the standard Scala convention of uniform access to set the value.
Just for completeness and to expand on the previous answers, there is also the technique covered here.
To summarize, I would always begin with an immutable value:
class Person (val age: Int)
Then, if you figure out you need to mutate the value (or you know it in advance), switch to:
class Person (var age: Int)
Then, if you need to validate or do some other computation on get or set, rename your variable and build accessors that mimic your original naming, no need to refactor the rest of the code:
class Person(var _age: Int)
{
def age =
{
println("age requested")
_age
}
def age_=(newAge: Int) =
{
assert(newAge > 0)
println(s"age changed from ${_age} to $newAge")
_age = newAge
}
}
Of course, you can simplify either setter or getter if you don't need operations there.
Kudos to all other answers, which are indeed correct and came much sooner.