Scala how to append or remove item in Seq - scala

I have following classes
case class User(userId: Int, userName: String, email: String,
password:
String) {
def this() = this(0, "", "", "")
}
case class Team(teamId: Int, teamName: String, teamOwner: Int,
teamMembers: Seq[User]) {
def this() = this(0, "", 0, Nil)
}
I would like to add or User in teamMembers: Seq[User]. I tried couple of ways as:
Team.teamMembers :+ member
Team.teamMembers +: member
Nothing works :). Pleas advice me how can I add or remove item from teamMembers: Seq[User].
Thanks in advance!

You didn't mention which Seq do you use.
If it's scala.collection.mutable.Seq you can add to this Seq.
But, most changes that you use immutable.Seq which is Scala's default. This means you cannot add to a it, but you can create a new one with all items + new item.
With scala out of the box you can do it like this -
val team =Team(0,"", 0, Seq[User]())
val member = User(0, "","", "")
val teamWithNewMemebr = team.copy(teamMembers = team.teamMembers :+ member)
But this becomes pretty ugly if you have a lot of nesting or you have to do it a lot.
To overcome this complicated syntax you can use libraries like scalaz, monocle which provides you Lenses
Here's a good sample of how to use Lenses http://eed3si9n.com/learning-scalaz/Lens.html

Create an operation that returns a new Team with the member added, e.g.
The problem with your other code I think is you are trying to change an immutable variable. The teamMember field in the case class team is an immutable val and so changing it with an operation will not change what is contained in it - it will just return a new sequence with the value appended, but won't affect the one in the case class Team.
case class Team(teamId: Int, teamName: String, teamOwner: Int, teamMembers: Seq[User]) {
def this() = this(0, "", 0, Nil)
// Operation returns a new Team object which has all elements of the previous team plus an additional member appended to the team members.
def addMember(member: User) : Team = Team(teamId, teamName, teamOwner, teamMembers :+ member)
}

From the doc for the plus (+) operator:
[use case] A copy of the sequence with an element prepended
so + will yield a new collection with your additional element prepended. Are you using this new collection.

Well... all the parameter attributes in the case classes are immutable by default.
This is done with the purpose of promoting thread-safe programming. Also, one major thing that should be noticed is that this in a way also promotes the original idea of OOP ( the one similar to Smalltalk, before being transformed by Java OOP ).
Well... Separation of state and behaviour. So... basically kind of the ideal situation where Separation of state and behaviour meets thread-safety.
My personal taste for doing this would be - Have state in the case class, and move all behaviour to companion object.
case class User( userId: Int, userName: String, email: String, password: String )
object User {
def apply(): User = User( 0, "", "", "" )
}
case class Team( teamId: Int, teamName: String, teamOwner: Int, teamMembers: Seq[ User ] )
object Team {
def apply(): Team = Team( 0, "", 0, Nil )
// since addMember is a behavior, it belongs here.
// Also... since we are immutable... addMember name does not make much sense...
// Let's call it withMember
def withMember( team: Team, user: User ): Team = {
team.copy( teamMembers = team.teamMembers :+ user )
}
}
Now, you will have to use it like this,
val user = User()
val team = Team()
val teamWithMember = Team.withMember( team, user )
But... In case... ( like in a really rare case ), if you "really" want ( control your desires man... control ) to have it mutable then
case class Team( teamId: Int, teamName: String, teamOwner: Int, var teamMembers: Seq[ User ] )
object Team {
def apply(): Team = Team( 0, "", 0, Nil )
// since addMember is a behavior, it belongs here.
// Now we can keep name addMember
def addMember( team: Team, user: User ): Unit = {
team.teamMembers = team.teamMembers :+ user
}
}
And use it like this,
val user = User()
val team = Team()
team.addMember( user )

Related

Break flatMap after first Some occurence

abstract class Node(id: Long, name: String) {
def find(id: Long) = if (this.id == id) Some(this) else None
}
case class Contact(id: Long, name: String, phone: String) extends Node(id, name)
case class Group(id: Long, name: String, entries: Node*) extends Node(id, name) {
override def find(id: Long): Option[Node] = {
super.find(id) orElse entries.flatMap(e => e.find(id)).headOption
}
}
val tree =
Group(0, "Root"
, Group(10, "Shop", Contact(11, "Alice", "312"))
, Group(20, "Workshop"
, Group(30, "Tyres", Contact(31, "Bob", "315"), Contact(32, "Greg", "319"))
, Contact(33, "Mary", "302"))
, Contact(1, "John", "317"))
println(tree.find(32))
Tree data is built from Contacts and Groups (w/ sub-Groups and Contacts). I want to find a node with specific id. Currently I traverse Group's members using:
entries.flatMap(e => e.find(id)).headOption
but it isn't optimal because I check all child entries instead of break upon first finding.
I'd appreciate your help in magic Scala Wold. Thanks.
You want collectFirst, which will select the first matching element and wrap it in Some, or None if it's not found. You can also turn entries into a view, to make the evaluation lazy.
entries.view.map(_.find(id)).collectFirst { case Some(node) => node }
It will work with your original code, as well:
entries.view.flatMap(_.find(id)).headOption
Another way to approach this problem could be providing traverse support for the data structure. Overall it's a tree so it can be traversed easily. Please check the code below:
sealed abstract class Node(val id: Long, val name: String) extends Traversable[Node] {
def foreach[U](f:Node => U) = this match {
case x: Contact => f(x)
case x: Group => f(x); x.entries.foreach(_ foreach f)
}
}
case class Contact(override val id: Long, override val name: String, phone: String) extends Node(id, name) {
override def toString = (id, name, phone).toString
}
case class Group(override val id: Long, override val name: String, entries: Node*) extends Node(id, name) {
override def toString = (id, name).toString + entries.map(_.toString).mkString
}
val tree =
Group(0, "Root"
, Group(10, "Shop", Contact(11, "Alice", "312"))
, Group(20, "Workshop"
, Group(30, "Tyres", Contact(31, "Bob", "315"), Contact(32, "Greg", "319"))
, Contact(33, "Mary", "302"))
, Contact(1, "John", "317"))
println(tree) // (0,Root)(10,Shop)(11,Alice,312)(20,Workshop)(30,Tyres)(31,Bob,315)(32,Greg,319)(33,Mary,302)(1,John,317)
println(tree find {_.id == 32}) //Some((32,Greg,319))
println(tree map {_.name }) //List(Root, Shop, Alice, Workshop, Tyres, Bob, Greg, Mary, John)
The good thing is that now you can use of all the benefits of Traversable[Node] trait. The problem on the other hand is that I had to override toString method in case classes. So I guess there is still room for improvement.

Adding functionality before calling constructor in extra constructor

Is it possible to add functionality before calling constructor in extra constructor in scala ?
Lets say, I have class User, and want to get one string - and to split it into attributes - to send them to the constructor:
class User(val name: String, val age: Int){
def this(line: String) = {
val attrs = line.split(",") //This line is leading an error - what can I do instead
this(attrs(0), attrs(1).toInt)
}
}
So I know I'm not able to add a line before sending to this, because all constructors need to call another constructor as the first statement of the constructor.
Then what can I do instead?
Edit:
I have a long list of attributes, so I don't want to repeat line.split(",")
I think this is a place where companion object and apply() method come nicely into play:
object User {
def apply(line: String): User = {
val attrs = line.split(",")
new User(attrs(0), attrs(1).toInt)
}
}
class User(val name: String, val age: Int)
Then you just create your object the following way:
val u1 = User("Zorro,33")
Also since you're exposing name and age anyway, you might consider using case class instead of standard class and have consistent way of constructing User objects (without new keyword):
object User {
def apply(line: String): User = {
val attrs = line.split(",")
new User(attrs(0), attrs(1).toInt)
}
}
case class User(name: String, age: Int)
val u1 = User("Zorro,33")
val u2 = User("Zorro", "33")
Ugly, but working solution#1:
class User(val name: String, val age: Int){
def this(line: String) = {
this(line.split(",")(0), line.split(",")(1).toInt)
}
}
Ugly, but working solution#2:
class User(val name: String, val age: Int)
object User {
def fromString(line: String) = {
val attrs = line.split(",")
new User(attrs(0), attrs(1).toInt)
}
}
Which can be used as:
val johny = User.fromString("johny,35")
You could use apply in place of fromString, but this will lead to a confusion (in one case you have to use new, in the other you have to drop it) so I prefer to use different name
Another ugly solution:
class User(line: String) {
def this(name: String, age: Int) = this(s"$name,$age")
val (name, age) = {
val Array(nameStr,ageStr) = line.split(",")
(nameStr,ageStr.toInt)
}
}
But using a method of the companion object is probably better.

Scala Auxilliary Constructor behavior

In the book "Scala for the impatient" by Cay Horstmann, on chapter 5 exercise 8, there is this question:
//Make a class Car with read-only properties for manufacturer, model name,
//and model year, and a read-write property for the license plate. Supply four
// constructors. All require the manufacturer and model name. Optionally,
//model year and license plate can also be specified in the constructor. If not,
//the model year is set to -1 and the license plate to the empty string. Which
//constructor are you choosing as the primary constructor? Why?
So I coded the class:
case class Car(val manufacturer: String, val modelName: String,
val modelYear: Int, var licensePlate : String = "") {
def this(manufacturer: String, modelName: String, licensePlate: String) {
this(manufacturer, modelName, -1, licensePlate)
}
def this(manufacturer: String, modelName: String, modelYear: Int) {
specifically on this part:
this(manufacturer, modelName, modelYear)
}
def this(manufacturer: String, modelName: String) {
this(manufacturer, modelName, -1)
}
}
The compiler complains of the error:
<console>:14: error: called constructor's definition must precede calling constructor's definition
this(manufacturer, modelName, modelYear)
^
Why does it complain when I have provided a default value for the license Plate as an empty String in the primary constructor, and it sure is defined first??
The error goes away if I do this:
this(manufacturer, modelName, modelYear, "")
or if I make the class primary constructor not have a default value for the licensePlate (of course adjusting other auxilliary constructor calls in the process).
Note that the question specifically asked for 4 constructors, so instance creation can be called like:
new Car("Honda", "City", 2010, "ABC-123")
new Car("Honda", "City")
new Car("Honda", "City", "ABC-123")
new Car("Honda", "City", 2010)
Thanks in advance to those who can shed light on this issue.
====
Thanks to answers by Ende Neu and Kigyo, this looks like the perfect solution (remove the recursive constructor):
case class Car(val manufacturer: String, val modelName: String,
val modelYear: Int = -1, var licensePlate : String = "") {
def this(manufacturer: String, modelName: String, licensePlate: String) {
this(manufacturer, modelName, -1, licensePlate)
}
<< removed constructors here >>
}
Console println new Car("Honda", "City", 2010, "ABC-123")
Console println new Car("Honda", "City")
Console println new Car("Honda", "City", "ABC-123")
Console println new Car("Honda", "City", 2010)
I just want to make some things clear.
You can leave out the last parameter in this example. Here we call the primary constructor, that has 3 parameters, with only supplying two. (related to Ende Neu's example)
case class Test(a: String, b: String, c: String = "test") {
def this() = this("", "")
}
So why does it not work in your scenario? Have a close look!
def this(manufacturer: String, modelName: String, modelYear: Int) {
this(manufacturer, modelName, modelYear)
}
Here you also leave out the last parameter, but the new constructor you define takes exactly that amount of parameters and this makes it a recursive call. So you never call the primary constructor and therefore you get the error.
I would also remove the default value in your case. Maybe there is a way around it, but I'm too tired at the moment.
You get this error because the scala compiler is not able to see the default value you provided in your case class and you are declaring a constructor with three parameters instead of four, for example:
case class Test(a: String, b: String, c: String = "test") {
def this(d: String, e: String) = this(c, e)
}
This will throw the same error, what you can do is to specify default values in the constructor as you did with the empty string:
def this(d: String) = this(d, "empty")
def this(d: String, e: String) = this(d, e, "empty") // and this would return a new object
Having a case class with default value simply corresponds to a constructor where you don't have to serve all parameters, so for the exercise you don't need two constructors, if the year and the plate are not specified use some predifined value, else use the default constructor (which takes already 4 parameters):
case class Car(val manufacturer: String, val modelName: String, val modelYear: Int, var licensePlate : String) {
def this(manufacturer: String, modelName: String) =
this(manufacturer, modelName, -1, "")
}
}
And then call it like this:
new Car("Wolksvagen", "Polo")
Car("Ford", "Fiesta", 1984, "plate")
Note that you have to use the new keyword in the first declaration because it's not referring to the apply method in the companion object (which could also be overridden, see this SO question).

Scala case class generated field value

I have an existing Scala application and it uses case classes which are then persisted in MongoDB. I need to introduce a new field to a case class but the value of it is derived from existing field.
For example, there is phone number and I want to add normalised phone number while keeping the original phone number. I'll update the existing records in MongoDB but I would need to add this normalisation feature to existing save and update code.
So, is there any nice shortcut in Scala to add a "hook" to a certain field of a case class? For example, in Java one could modify setter of the phone number.
Edit:
The solution in Christian's answer works fine alone but in my case I have defaults for fields (I think because of Salat...)
case class Person(name: String = "a", phone: Option[String] = None, normalizedPhone: Option[String] = None)
object Person {
def apply(name: String, phone: Option[String]): Person = Person(name, phone, Some("xxx" + phone.getOrElse("")))
}
And if use something like:
Person(phone = Some("s"))
I'll get: Person = Person(a,Some(s),None)
You can define an apply method in the companion object:
case class Person(name: String, phone: String, normalizedPhone: String)
object Person {
def apply(name: String, phone: String): Person = Person(name, phone, "xxx" + phone)
}
Then, in the repl:
scala> Person("name", "phone")
res3: Person = Person(name,phone,xxxphone)
You could add methods to the case class that would contain the transforming logic from existing fields. For example:
case class Person(name: String, phone: String) {
def normalizedPhone = "+40" + phone
}
Then you can use the method just as if it was a field:
val p1 = new Person("Joe", "7234")
println(p1.normalizedPhone) // +407234
I think this comes close to what you need. Since you can't override the generated mutator, prefix the existing field with an underscore, make it private, and then write the accessor and mutator methods for the original field name. After that, you only need an extra line in the constructor to accommodate for constructor-based initialization of the field.
case class Test(private var _phoneNumber: String, var formatted: String = "") {
phoneNumber_=(_phoneNumber)
def phoneNumber = _phoneNumber
def phoneNumber_=(phoneNumber: String) {
_phoneNumber = phoneNumber
formatted = "formatted" + phoneNumber
}
}
object Test {
def main(args: Array[String]) {
var t = Test("09048751234")
println(t.phoneNumber)
println(t.formatted)
t.phoneNumber = "08068745963"
println(t.phoneNumber)
println(t.formatted)
}
}

How to avoid using null?

Suppose, I have my domain object named "Office":
case class Office(
id: Long,
name: String,
phone: String,
address: String
) {
def this(name: String, phone: String, address: String) = this(
null.asInstanceOf[Long], name, phone, address
)
}
When I create new Office:
new Office("officeName","00000000000", "officeAddress")
I don't specify id field becouse I don't know it. When I save office (by Anorm) I now id and do that:
office.id = officeId
So. I know that using null is non-Scala way. How to avoid using null in my case?
UPDATE #1
Using Option.
Suppose, something like this:
case class Office(
id: Option[Long],
name: String,
phone: String,
address: String
) {
def this(name: String, phone: String, address: String) = this(
None, name, phone, address
)
}
And, after saving:
office.id = Option(officeId)
But what if I need to find something by office id?
SomeService.findSomethingByOfficeId(office.id.get)
Does it clear? office.id.get looks not so good)
UPDATE #2
Everyone thanks! I've got new ideas from your answers! Greate thanks!
Why not declare the id field as a Option? You should really avoid using null in Scala. Option is preferable since it is type-safe and plays nice with other constructs in the functional paradigm.
Something like (I haven't tested this code):
case class Office(
id: Option[Long],
name: String,
phone: String,
address: String
) {
def this(name: String, phone: String, address: String) = this(
None, name, phone, address
)
}
Just make the id field an Option[Long]; once you have that, you can use it like this:
office.id.map(SomeService.findSomethingByOfficeId)
This will do what you want and return Option[Something]. If office.id is None, map() won't even invoke the finder method and will immediately return None, which is what you want typically.
And if findSomethingByOfficeId returns Option[Something] (which it should) instead of just Something or null/exception, use:
office.id.flatMap(SomeService.findSomethingByOfficeId)
This way, if office.id is None, it will, again, immediately return None; however, if it's Some(123), it will pass that 123 into findSomethingByOfficeId; now if the finder returns a Some(something) it will return Some(something), if however the finder returns None, it will again return None.
if findSomethingByOfficeId can return null and you can't change its source code, wrap any calls to it with Option(...)—that will convert nulls to None and wrap any other values in Some(...); if it can throw an exception when it can't find the something, wrap calls to it with Try(...).toOption to get the same effect (although this will also convert any unrelated exceptions to None, which is probably undesirable, but which you can fix with recoverWith).
The general guideline is always avoid null and exceptions in Scala code (as you stated); always prefer Option[T] with either map or flatMap chaining, or using the monadic for syntactic sugar hiding the use of map and flatMap.
Runnable example:
object OptionDemo extends App {
case class Something(name: String)
case class Office(id: Option[Long])
def findSomethingByOfficeId(officeId: Long) = {
if (officeId == 123) Some(Something("London")) else None
}
val office1 = Office(id = None)
val office2 = Office(id = Some(456))
val office3 = Office(id = Some(123))
println(office1.id.flatMap(findSomethingByOfficeId))
println(office2.id.flatMap(findSomethingByOfficeId))
println(office3.id.flatMap(findSomethingByOfficeId))
}
Output:
None
None
Some(Something(London))
For a great introduction to Scala's rather useful Option[T] type, see http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html.
When using id: Option[Long] , extract the option value for instance with
if (office.id.isDefined) {
val Some(id) = office.id
SomeService.findSomethingByOfficeId(id)
}
or perhaps for instance
office.id match {
case None => Array()
case Some(id) => SomeService.findSomethingByOfficeId(id)
}
Also you can define case classes and objects as follows,
trait OId
case object NoId extends OId
case class Id(value: Long) extends OId
case class Office (
id: OId = NoId,
name: String,
phone: String,
address: String
)
Note that by defaulting id for example to NoId , there is no need to declare a call to this. Then
val office = Office (Id(123), "name","phone","addr")
val officeNoId = Office (name = "name",phone="phone",address="addr")
If the id member is defined last, then there is no need to name the member names,
val office = Office ("name","phone","addr")
office: Office = Office(name,phone,addr,NoId)
As of invoking (neatly) a method,
office.id match {
case NoId => Array()
case Id(value) => SomeService.findSomethingByOfficeId(value)
}
I prefer more strong restriction for object Id property:
trait Id[+T] {
class ObjectHasNoIdExcepthion extends Throwable
def id : T = throw new ObjectHasNoIdExcepthion
}
case class Office(
name: String,
phone: String,
address: String
) extends Id[Long]
object Office {
def apply(_id : Long, name: String, phone: String, address: String) =
new Office(name, phone, address) {
override def id : Long = _id
}
}
And if I try to get Id for object what is not stored in DB, I get exception and this mean that something wrong in program behavior.
val officeWithoutId =
Office("officeName","00000000000", "officeAddress")
officeWithoutId.id // Throw exception
// for-comprehension and Try monad can be used
// update office:
for {
id <- Try { officeWithoutId.id }
newOffice = officeWithoutId.copy(name = "newOffice")
} yield OfficeDAL.update(id, newOffice)
// find office by id:
for {
id <- Try { officeWithoutId.id }
} yield OfficeDAL.findById(id)
val officeWithId =
Office(1000L, "officeName","00000000000", "officeAddress")
officeWithId.id // Ok
Pros:
1) method apply with id parameter can be incapsulated in DAL logic
private[dal] def apply (_id : Long, name: String, ...
2) copy method always create new object with empty id (safty if you change data)
3) update method is safety (object not be overridden by default, id always need to be specified)
Cons:
1) Special serealization/deserealization logic needed for store id property (json for webservices, etc)
P.S.
this approach is good if you have immutable object (ADT) and store it to DB with id + object version instead object replace.