In Scala, I have a case class:
case class MonthSelectionInfo(monthSelection: MonthSelection.Value, customMonth:Int = 0, customYear:Int = 0) {
def this(monthSelection: MonthSelection.Value) = {
this(monthSelection, 0, 0)
}
}
object MonthSelection extends Enumeration {
type MonthSelection = Value
val LastMonth, ThisMonth, NextMonth, CustomMonth = Value
}
When I have an instance of the case class, I have to use
myMonthSelectionInfo.monthSelection
and
myMonthSelectionInfo.eq(newMonthSelection)
to get & set the MonthSelection instance contained within.
Is there any nice Scala way to format the getter & setter to look more like regular Java POJOs? e.g.
myMonthSelectionInfo.setMonthSelection(newMonthSelection)
There is #BeanProperty annotation to generate getters and setters for fields.
case class MonthSelectionInfo(#reflect.BeanProperty var monthSelection: MonthSelection.Value)
scala> val ms = MonthSelectionInfo(MonthSelection.LastMonth)
ms: MonthSelectionInfo = MonthSelectionInfo(LastMonth)
scala> ms.setMonthSelection(MonthSelection.ThisMonth)
sscala> ms.getMonthSelection
res4: MonthSelection.Value = ThisMonth
In object oriented programming, getters and setters are something that most would agree have some real world benefits. Unfortunately, they can sometimes be annoying to write. They usually do not consist of a lot of code , but when you have the write the same thing over and over and over it gets old really fast. In my experience, most getters and setters are very much alike so it stands to reason that there must be a “better” way to accomplish the same result.
This link may help you.
We can use #BeanProperty in scala 2.11
import scala.beans.BeanProperty
case class Employee(#BeanProperty id: Long, #BeanProperty name: String, #BeanProperty age: Long)
Related
For example, how is this:
class Cat(name: String, val age: Int) {
def this() = this("Garfield", 20)
}
val someCat = new Cat
someCat.age
res0: Int = 20
Different from:
class Cat(name: String = "Garfield", val age: Int = 20)
val someCat = new Cat
someCat.age
res0: Int = 20
Note:
I have seen answers to other questions(e.g here) that discuss the differences between Java & Scala in the implementation for auxiliary constructors. But I am mostly trying to understand why do we need them in Scala, in the first place.
Auxiliary constructors are good for more than just supplying defaults. For example, here's one that can take arguments of different types:
class MyBigInt(x: Int) {
def this(s: String) = this(s.toInt)
}
You can also hide the main constructor if it contains implementation details:
class MyBigInt private(private val data: List[Byte]) {
def this(n: Int) = this(...)
}
This allows you to have data clearly be the backing structure for your class while avoiding cluttering your class with the arguments to one of your auxiliary constructors.
Another use for auxiliary constructors could be migrating Java code to Scala (or refactoring to change a backing type, as in the example above) without breaking dependencies. In general though, it is often better to use a custom apply method in the companion object, as they are more flexible.
A recurring use case I noticed is, as Brian McCutchon already mentioned in his answer "For example, here's one that can take arguments of different types", parameters of Option type in the primary constructor. For example:
class Person(val firstName:String, val middleName:Option[String], val lastName: String)
To create a new instance you need to do:
val person = new Person("Guido", Some("van"), "Rossum")
But with an auxiliary constructor, the whole process will be very pleasant.
class Person(val firstName:String, val middleName:Option[String], val lastName: String){
def this(firstName:String, middleName:String, lastName: String) = this(firstName, Some(middleName), lastName)
}
val person = new Person("Guido", "van", "Rossum")
Give the simple class
class MyClass {
private var myVar: String = _
}
How can I generate the setters and getters for myVar?
The Code | Generate menu shows:
Override Methods...
Implement Methods...
Delegate Methods...
Copyright
equals() and hashCode()
toString()
Companion object
IntelliJ version: 14.1.5
OS: OS X 10.10.5
#Zoltán is right - getters and setters are not common in Scala because:
Scala encourages immutability
Scala already generates them for you when make a field - they just aren't named according to the Java beans convention (You can encourage Scala to not generate these methods by being really restrictive in who can see and modify the field - think final private[this] val).
Because of #2, it is possible to go from var someField to private var _someField, def someField = this._someField and def someField_=(value: String) = { this._someField = value } and not have consumers update their code. In other words, the change is source compatible (though I believe it is not binary compatible).
If you need Java bean style getters and setters simply annotate the field with #BeanProperty and scalac will generate the getter and setter for you:
import scala.beans.BeanProperty
class MyClass {
#BeanProperty
var myVar: String = _
}
Note that in order to get the is getters and setters for a boolean property you need to use BooleanBeanProperty instead.
You can use the Scala Bean Property
import scala.beans.BeanProperty
class MyClass {
#BeanProperty var myVar: String = _
}
#BeanProperty - Generates getters and setters for a property. (Or
just a getter if the bean is a val)
I'm attempting to write some code that tracks changes to a record and applies them at a later date. In a dynamic language I'd do this by simply keeping a log of List[(String, Any)] pairs, and then simply applying these as an update to the original record when I finally decide to commit the changes.
I need to be able to introspect over the updates, so a list of update functions isn't appropriate.
In Scala this is fairly trivial using reflection, however I'd like to implement a type-safe version.
My first attempt was to try with shapeless. This works well if we know specific types.
import shapeless._
import record._
import syntax.singleton._
case class Person(name:String, age:Int)
val bob = Person("Bob", 31)
val gen = LabelledGeneric[Person]
val updated = gen.from( gen.to(bob) + ('age ->> 32) )
// Result: Person("Bob", 32)
However I can't figure out how to make this work generically.
trait Record[T]
def update( ??? ):T
}
Given the way shapeless handles this, I'm not sure if this would even be possible?
If I accept a lot of boilerplate, as a poor mans version I could do something along the lines of the following.
object Contact {
sealed trait Field[T]
case object Name extends Field[String]
case object Age extends Field[Int]
}
// A typeclass would be cleaner, but too verbose for this simple example.
case class Contact(...) extends Record[Contact, Contact.Field] {
def update[T]( field:Contact.Field[T], value:T ) = field match {
case Contact.Name => contact.copy( name = value )
case Contact.Age => contact.copy( age = value )
}
}
However this isn't particularly elegant and requires a lot of boilerplate. I could probably write my own macro to handle this, however it seems like a fairly common thing - is there a way to handle this with Shapeless or a similar macro library already?
How about using the whole instance of the class as an update?
case class Contact(name: String, age: Int)
case class ContactUpdate(name: Option[String] = None, age: Option[Int] = None)
object Contact {
update(target: Contact, delta: ContactUpdate) = Contact(
delta.name.getOrElse(target.name)
target.age.getOrElse(delta.age)
)
}
// also, optionally this:
object ContactUpdate {
apply(name: String) = ContactUpdate(name = Option(name))
apply(age: Int) = ContactUpdate(age = Option(age))
}
I think, if you want the really type-safe solution, this is the cleanest and most readable, and also, possibly the least pain to implement, as you don't need to deal with Records, lenses and individual field descriptors, just ContactUpdate(name="foo") creates an update, and updates.map(Contact.update(target, _)) applies them all in sequence.
In Java, I do a lot of data integration work. One thing that comes up all the time is mapping data between multiple systems. So i'm constantly doing things like this
public enum DataField{
Field1("xmlField", "dbField", "system1Field";
private String xml;
private String db;
private String sys;
private DataField(String xml, String db, String sys){
this.xml = xml;
this.db = db;
this.sys = sys;
}
public getXml(){
return this.xml;
}
public static DataField valueOfXml(String xml){
for (DataField d : this.values()){
if (d.xml.equals(xml)){ return d;}
}
}
bla, bla bla
}
What this allows me to do is put the field name DataField in all my messaging and be able to map what that field is called in multiple systems. So in my XML, it may be firstname, in my database, it may be called first_name but in my external interface system, it may be called first. This pattern pulls all of that together very nicely and makes messaging in these types of systems very easy in a tight, type safe way.
Now I don't remember why Scala changed the enumeration implementation but I remember it made sense when I read it. But the question is, what would I use in Scala to replace this design pattern? I hate to lose it because it is very useful and fundamental to a lot of systems I write on a given day.
thanks
I managed to make up this kind-of replacement for your case:
sealed class DataField(val xml: String, val db: String, val sys: String)
object DataField {
case object Field1 extends DataField("xmlField1", "dbField1", "system1Field")
case object Field2 extends DataField("xmlField2", "dbField2", "system2Field")
case object Field3 extends DataField("xmlField3", "dbField3", "system3Field")
val values = List(Field1, Field2, Field3)
def valueOfXml(xml: String) =
values.find(_.xml == xml).get
}
The annoying thing is that we have to manually create the values list. In this case however, we can do some macro hacking to reduce the boilerplate a bit:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object Macros {
def caseObjectsFor[T]: List[T] = macro caseObjectsFor_impl[T]
def caseObjectsFor_impl[T: c.WeakTypeTag](c: Context): c.Expr[List[T]] = {
import c.universe._
val baseClassSymbol = weakTypeOf[T].typeSymbol.asClass
val caseObjectSymbols = baseClassSymbol.knownDirectSubclasses.toList.collect {
case s if s.isModuleClass && s.asClass.isCaseClass => s.asClass.module
}
val listObjectSym = typeOf[List.type].termSymbol
c.Expr[List[T]](Apply(Ident(listObjectSym), caseObjectSymbols.map(s => Ident(s))))
}
}
Then we can do this:
val values = Macros.caseObjectsFor[DataField]
instead of manually listing all the case objects.
For this to work, it is essential that the base class is declared as sealed.
You could always do what I do, and keep writing the enums in Java.
Out of 62 .java files in my source tree, 61 are enums, and the other one is a package-info.java.
Suppose I have the following
class SimpleClass (myInt: Int, myString: String) {
}
What is wrong with the following?
val mySimple = new SimpleClass(1, "hi")
println(mySimple.myInt)
If you want the contructor parameters to be available as fields of the class, you have to declare them as vals or vars:
class SimpleClass (val myInt: Int, val myString: String) {
}
The java equivalent of your Scala definition is:
public class SimpleClass {
public SimpleClass( int myInt, String myString ) {
}
}
No wonders it doesn't work...
Hey dude, that's your 17th scala question and you are still troubled by the very basics of the language. Perhaps you should take an afternoon and read some of tutorial on-line (or some book) to consolidate your knowledge. I can suggest:
http://www.codecommit.com/blog/scala/roundup-scala-for-java-refugees
http://www.ibm.com/developerworks/java/library/j-scala02198/index.html (see listings 11-13)
For the full POJO experience™, including equality, hashCodes and sane implementation of toString... You'll want case classes:
case class SimpleClass(myInt: Int, myString: String)
val mySimple = SimpleClass(1, "hi")
println(mySimple.myInt)
Parameters to a case class are automatically made into vals. You can explicitly make them vars if you wish, but this this sort of thing is typically frowned upon in Scala - where immutable objects are favoured.
The problem is that you are calling the SimpleClass.myInt getter method but you didn't define a getter method anywhere. You need to define the SimpleClass.myInt getter method or even better yet, get Scala to automatically define it for you:
class SimpleClass(val myInt: Int, myString: String) {}