Issues Overloading CTOR's in Scala - scala

Im having an issue over loading the constructors in Scala. Each time I try to pass a value for the over loaded CTOR I get the error
Example:
var client : Client = Client(*variable type List[String]()*);
Unspecified value parameter clientList.
My goal is to have an object created using 2 different data types. One a NodeSeq and the Other a List. Never Both. Am I over loading the CTOR correctly or is there a more efficient way to achieve my goal?
package api
import xml._
case class Client(clientNode: NodeSeq, clientList: List[String]) {
def this(clientNode: NodeSeq) = this(clientNode, null)
def this(clientList: List[String]) = this(null, clientList)
var firstName: String
var lastName: String
var phone: String
var street: String
var city: String
var state: String
var zip: String
var products = List[String]()
var serviceOrders = List[String]()
if (clientList == null) {
firstName = (clientNode \\ "firstname").text
lastName = (clientNode \\ "lastname").text
phone = (clientNode \\ "phone").text
street = (clientNode \\ "street").text
city = (clientNode \\ "city").text
state = (clientNode \\ "state").text
zip = (clientNode \\ "zip").text
(clientNode \\ "products").foreach(i => products = i.text :: products)
(clientNode \\ "serviceOrders").foreach(i => serviceOrders = i.text :: serviceOrders)
} else {
firstName = clientList(0)
lastName = clientList(1)
phone = clientList(2)
street = clientList(3)
city = clientList(4)
state = clientList(5)
zip = clientList(6)
}
override def toString(): String = {
return "Name : " + firstName + " " + lastName +
"\nAddress : " +
"\n\t" + street +
"\n\t" + city + ", " + state + " " + zip
}
}

You didn't post working code; you can't have undefined vars.
Anyway, the problem is that even though you have overridden the constructors, you have not overridden the builders in the companion object. Add this and it will work the way you want:
object Client {
def apply(clientNode: NodeSeq) = new Client(clientNode)
def apply(clientList: List[String]) = new Client(clientList)
}
(if you're using the REPL, be sure to use :paste to enter this along with the case class so you add to the default companion object instead of replacing it).
But a deeper problem is that this is not the way you should be solving the problem. You should define a trait that contains the data you want:
trait ClientData {
def firstName: String
def lastName: String
/* ... */
}
and inherit from it twice, once for each way to parse it:
class ClientFromList(cl: List[String]) extends ClientData {
val firstName = cl.head
. . .
}
or you could turn the NodeSeq into a list and parse it there, or various other things. This way you avoid exposing a bunch of vars which are probably not meant to be changed later.

Auxiliary constructors are for simple one-liners and aren't suitable in this case. More idiomatic way would be to define factory methods in a companion object:
case class Client(firstName: String,
lastName: String,
products: List[String] = Nil)
object Client {
import scala.xml.NodeSeq
def fromList(list: List[String]): Option[Client] =
list match {
case List(firstName, lastName) =>
Some(Client(firstName, lastName))
case _ => None
}
def fromXml(nodeSeq: NodeSeq): Option[Client] = {
def option(label: String) =
(nodeSeq \\ label).headOption.map(_.text)
def listOption(label: String) =
(nodeSeq \\ label).headOption.map {
_.map(_.text).toList
}
for {
firstName <- option("firstname")
lastName <- option("lastname")
products <- listOption("products")
} yield Client(firstName, lastName, products)
}
}
I also took the liberty of improving your code by eliminating mutability and making it generally more runtime safe.

Related

DSL in scala using case classes

My use case has case classes something like
case class Address(name:String,pincode:String){
override def toString =name +"=" +pincode
}
case class Department(name:String){
override def toString =name
}
case class emp(address:Address,department:Department)
I want to create a DSL like below.Can anyone share the links about how to create a DSL and any suggestions to achieve the below.
emp.withAddress("abc","12222").withDepartment("HR")
Update:
Actual use case class may have more fields close to 20. I want to avoid redudancy of code
I created a DSL using reflection so that we don't need to add every field to it.
Disclamer: This DSL is extremely weakly typed and I did it just for fun. I don't really think this is a good approach in Scala.
scala> create an Employee where "homeAddress" is Address("a", "b") and "department" is Department("c") and that_s it
res0: Employee = Employee(a=b,null,c)
scala> create an Employee where "workAddress" is Address("w", "x") and "homeAddress" is Address("y", "z") and that_s it
res1: Employee = Employee(y=z,w=x,null)
scala> create a Customer where "address" is Address("a", "b") and "age" is 900 and that_s it
res0: Customer = Customer(a=b,900)
The last example is the equivalent of writing:
create.a(Customer).where("address").is(Address("a", "b")).and("age").is(900).and(that_s).it
A way of writing DSLs in Scala and avoid parentheses and the dot is by following this pattern:
object.method(parameter).method(parameter)...
Here is the source:
// DSL
object create {
def an(t: Employee.type) = new ModelDSL(Employee(null, null, null))
def a(t: Customer.type) = new ModelDSL(Customer(null, 0))
}
object that_s
class ModelDSL[T](model: T) {
def where(field: String): ValueDSL[ModelDSL2[T], Any] = new ValueDSL(value => {
val f = model.getClass.getDeclaredField(field)
f.setAccessible(true)
f.set(model, value)
new ModelDSL2[T](model)
})
def and(t: that_s.type) = new { def it = model }
}
class ModelDSL2[T](model: T) {
def and(field: String) = new ModelDSL(model).where(field)
def and(t: that_s.type) = new { def it = model }
}
class ValueDSL[T, V](callback: V => T) {
def is(value: V): T = callback(value)
}
// Models
case class Employee(homeAddress: Address, workAddress: Address, department: Department)
case class Customer(address: Address, age: Int)
case class Address(name: String, pincode: String) {
override def toString = name + "=" + pincode
}
case class Department(name: String) {
override def toString = name
}
I really don't think you need the builder pattern in Scala. Just give your case class reasonable defaults and use the copy method.
i.e.:
employee.copy(address = Address("abc","12222"),
department = Department("HR"))
You could also use an immutable builder:
case class EmployeeBuilder(address:Address = Address("", ""),department:Department = Department("")) {
def build = emp(address, department)
def withAddress(address: Address) = copy(address = address)
def withDepartment(department: Department) = copy(department = department)
}
object EmployeeBuilder {
def withAddress(address: Address) = EmployeeBuilder().copy(address = address)
def withDepartment(department: Department) = EmployeeBuilder().copy(department = department)
}
You could do
object emp {
def builder = new Builder(None, None)
case class Builder(address: Option[Address], department: Option[Department]) {
def withDepartment(name:String) = {
val dept = Department(name)
this.copy(department = Some(dept))
}
def withAddress(name:String, pincode:String) = {
val addr = Address(name, pincode)
this.copy(address = Some(addr))
}
def build = (address, department) match {
case (Some(a), Some(d)) => new emp(a, d)
case (None, _) => throw new IllegalStateException("Address not provided")
case _ => throw new IllegalStateException("Department not provided")
}
}
}
and use it as emp.builder.withAddress("abc","12222").withDepartment("HR").build().
You don't need optional fields, copy, or the builder pattern (exactly), if you are willing to have the build always take the arguments in a particular order:
case class emp(address:Address,department:Department, id: Long)
object emp {
def withAddress(name: String, pincode: String): WithDepartment =
new WithDepartment(Address(name, pincode))
final class WithDepartment(private val address: Address)
extends AnyVal {
def withDepartment(name: String): WithId =
new WithId(address, Department(name))
}
final class WithId(address: Address, department: Department) {
def withId(id: Long): emp = emp(address, department, id)
}
}
emp.withAddress("abc","12222").withDepartment("HR").withId(1)
The idea here is that each emp parameter gets its own class which provides a method to get you to the next class, until the final one gives you an emp object. It's like currying but at the type level. As you can see I've added an extra parameter just as an example of how to extend the pattern past the first two parameters.
The nice thing about this approach is that, even if you're part-way through the build, the type you have so far will guide you to the next step. So if you have a WithDepartment so far, you know that the next argument you need to supply is a department name.
If you want to avoid modifying the origin classes you can use implicit class, e.g.
implicit class EmpExtensions(emp: emp) {
def withAddress(name: String, pincode: String) {
//code omitted
}
// code omitted
}
then import EmpExtensions wherever you need these methods

Companion objects in scala

can any one explain the following output. I have a simple Scala code like this..
object compOrNotTest {
def main(args: Array[String]) {
var emp = new Employee("tom", 20)
println(emp)
println(Employee.adult(emp))
Employee.printName("Roland", 38)
var emp2 = new Employee("Harry", 37)
Employee.printName(emp2)
}
}
class Employee(name: String, age: Int) {
val ageOfEmplyedd: Int = age
val nameEmp: String = name
override def toString() = this.name + " age : " + this.age
def printName() {
println("name is in Class " + nameEmp)
}
}
object Employee {
def adult(emp: Employee) = {
if (emp.ageOfEmplyedd > 18)
true
else
false
}
def printName(name: String, age: Int) = {
val emp1 = new Employee(name, age)
println("Name is : " + emp1.printName())
}
def printName(emp1: Employee) = {
//val emp1 = new Employee(name, age)
println("Name is : "+ emp1.printName())
}
}
And the output I am getting is
tom age : 20
true
name is in Class Roland
Name is : ()
name is in Class Harry
Name is : ()
My question is that why , when I am calling from Companion object I am getting only Name is : (). I am expecting something like Name is : name is in Class Roland. Please help me out to understand the how scala works in this case. Thanks a lot
The return type of Employee.printName (in class Employee) is Unit. This is because this function was declared using procedure syntax (a function declaration with no = sign in it, which has been deprecated and which will no longer be supported in a future version of Scala) that has an associated return type of Unit. The Unit value that is returned is represented in Scala as ().
The following function declarations are equivalent:
// Using (soon-to-be-deprecated) procedure syntax.
def printName() {
println("name is in Class " + nameEmp)
}
// Using an explicit return type.
def printName(): Unit = {
println("name is in Class " + nameExp)
}
// Using an inferred return type (note "=" in declaration). The last statement is the call
// to println, which returns Unit, so a return type of Unit is inferred.
def printName() = {
println("name is in Class " + nameExp)
}
If you wanted to return the string that was printed, you would need something like this:
def printName() = {
val s = "name is in Class " + nameEmp
println(s)
s
}
Or, using an explicit return type, instead of inferring it from the last statement:
def printName(): String = {
val s = "name is in Class " + nameEmp
println(s)
s
}

Neo4j OGM example with Scala

I tried the example mentioned in Luanne's article The essence of Spring Data Neo4j 4 in Scala. The code can be found in the neo4j-ogm-scala repository.
package neo4j.ogm.scala.domain
import org.neo4j.ogm.annotation.GraphId;
import scala.beans.BeanProperty
import org.neo4j.ogm.annotation.NodeEntity
import org.neo4j.ogm.annotation.Relationship
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
abstract class Entity {
#GraphId
#BeanProperty
var id: Long = _
override def equals(o: Any): Boolean = o match {
case other: Entity => other.id.equals(this.id)
case _ => false
}
override def hashCode: Int = id.hashCode()
}
#NodeEntity
class Category extends Entity {
var name: String = _
def this(name: String) {
this()
this.name = name
}
}
#NodeEntity
class Ingredient extends Entity {
var name: String = _
#Relationship(`type` = "HAS_CATEGORY", direction = "OUTGOING")
var category: Category = _
#Relationship(`type` = "PAIRS_WITH", direction = "UNDIRECTED")
var pairings: Set[Pairing] = Set()
def addPairing(pairing: Pairing): Unit = {
pairing.first.pairings +(pairing)
pairing.second.pairings +(pairing)
}
def this(name: String, category: Category) {
this()
this.name = name
this.category = category
}
}
#RelationshipEntity(`type` = "PAIRS_WITH")
class Pairing extends Entity {
#StartNode
var first: Ingredient = _
#EndNode
var second: Ingredient = _
def this(first: Ingredient, second: Ingredient) {
this()
this.first = first
this.second = second
}
}
object Neo4jSessionFactory {
val sessionFactory = new SessionFactory("neo4j.ogm.scala.domain")
def getNeo4jSession(): Session = {
System.setProperty("username", "neo4j")
System.setProperty("password", "neo4j")
sessionFactory.openSession("http://localhost:7474")
}
}
object Main extends App {
val spices = new Category("Spices")
val turmeric = new Ingredient("Turmeric", spices)
val cumin = new Ingredient("Cumin", spices)
val pairing = new Pairing(turmeric, cumin)
cumin.addPairing(pairing)
val session = Neo4jSessionFactory.getNeo4jSession()
val tx: Transaction = session.beginTransaction()
try {
session.save(spices)
session.save(turmeric)
session.save(cumin)
session.save(pairing)
tx.commit()
} catch {
case e: Exception => // tx.rollback()
} finally {
// tx.commit()
}
}
The problem is that nothing gets saved to Neo4j. Can you please point out the problem in my code?
Thanks,
Manoj.
Scala’s Long is an instance of a Value class. Value classes were explicitly introduced to avoid allocating runtime objects. At the JVM level therefore Scala's Long is equivalent to Java’s primitive long which is why it has the primitive type signature J. It cannot be therefore be null, and should not be used as a graphId. Although Scala mostly will do auto-boxing between its own Long and Java’s Long class, this doesn’t apply to declarations, only to operations on those objects.
The #GraphId isn't being picked up on your entities. I have zero knowledge of Scala but it looks like the scala long isn't liked much by the OGM; var id: java.lang.Long = _ works fine.

what's the right method to accomplish this in scala

So, I have to parallel class structures, Books and Makers. A Maker creates a book based on some file or something. We can simplify the definition of the basic Maker down to:
class Maker {
type PF = (String, Book) => Book
def apply(in: Source): Book = {
mkMap(in, parseTop)
}
def mkMap(in: Source, top: PF) {
var res = new Book
in.getLines.foreach { ln => res = top(ln, res)
}
def parseTop(line: String, book: Book): Book = {
// really makes a new Book object with changes based on the content of `line` and returns it
book
}
}
and Book looks something like this (not a case class because we want to be able to inherit it)
class Book(val title: String = "Untitled", val author: String = "No Author", val language: String = "English")
def copy(title: String = this.title, author: String = this.author, language: String = this.language) = new Book(title, author, language)
Now, I'd like to extend this to make a SpecialMaker that makes SpecialBooks. A Special Book can be defined like this:
class SpecialBook(title: String = "Untitled", author: String = "No Author", language: String = "English", val specialness: Int = 9000) extends Book(title, author, language)
def copy(title: String = this.title, author: String = this.author, language: String = this.language, specialness: Int = this.specialness) = new SpecialBook(title, author, language, specialness)
The only thing that changes in making a SpecialBook from a Book is that the parseTop function does some additional calculation to make the specialness factor, let's say like this:
class SpecialMaker {
override def parseTop(line: String, book: SpecialBook): SpecialBook = {
book.copy(specialness = book.specialness + 9000)
}
}
Obviously, that code doesn't work because that parseTop would end up assigning a SpecialBook to a Book, among other problems. What's the best way to deal with the issue in Scala? Implicit conversions? (Could something to do with type parameters work?)
If there is a design pattern that deals with this, please let me know what it's called.
My approach, so you define the return type of parseTop by parameterizing the type of Maker:
trait Maker[B <: Book] {
def parseTop(line: String, book: B): B
}
trait Book {
val title: String
val author: String
val language: String
}
case class NonSpecialBook(title: String = "Untitled", author: String = "No Author", language: String = "English") extends Book
case class SpecialBook(title: String = "Untitled", author: String = "No Author", language: String = "English", val specialness: Int = 9000) extends Book
class NonSpecialMaker extends Maker[NonSpecialBook] {
def parseTop(line: String, book: NonSpecialBook): NonSpecialBook = {
book
}
}
class SpecialMaker extends Maker[SpecialBook] {
def parseTop(line: String, book: SpecialBook): SpecialBook = {
book.copy(specialness = book.specialness + 9000)
}
}
Do you need the parseTop method in SpecialMaker to hanle SpecialBooks´s or is it supposed to make books special? Is it possible to have a trait for books and all book types inherit from that trait?
Tell me, what´s missing to fit your needs.
EDIT: (due to comment)
You can supply an implicit BookBuilder :
trait Maker[B <: Book] {
type PF = (String, B) => B
def parseTop(line: String, book: B): B
def mkMap(in: Source, top: PF)(implicit bookBuilder: {def apply(): B} ) {
var res = bookBuilder()
// ...
}
}
But that implicit BookBuilder must be implicitly in scope (or conveyed manually) everytime you use mkMap.
I don´t know when you use mkMap.

How to store child objects on GAE using JDO from Scala

I'm have a parent-child relation between 2 classes, but the child objects are never stored. I do get an warning:
"org.datanucleus.store.appengine.MetaDataValidator checkForIllegalChildField: Unable to validate relation net.vermaas.kivanotify.model.UserCriteria.internalCriteria"
but it is unclear to me why this occurs. Already tried several alternatives without luck.
The parent class is "UserCriteria" which has a List of "Criteria" as children.
The classes are defined as follows (Scala):
class UserCriteria(tu: String, crit: Map[String, String]) extends LogHelper {
#PrimaryKey
#Persistent{val valueStrategy = IdGeneratorStrategy.IDENTITY}
var id = KeyFactory.createKey("UserCriteria", System.nanoTime)
#Persistent
var twitterUser = tu
#Persistent
var internalCriteria: java.util.List[Criteria] = flatten(crit)
def flatten(crits: Map[String, String]) : java.util.List[Criteria] = {
val list = new java.util.ArrayList[Criteria]
for (key <- crits.keySet) {
list.add(new Criteria(this, key, crits(key)))
}
list
}
def criteria: Map[String, String] = {
val crits = mutable.Map.empty[String, String]
for (i <- 0 to internalCriteria.size-1) {
crits(internalCriteria.get(i).name) = internalCriteria.get(i).value
}
Map.empty ++ crits
}
// Stripped the equals, canEquals, hashCode, toString code to keep the code snippet short...
}
#PersistenceCapable
#EmbeddedOnly
class Criteria(uc: UserCriteria, nm: String, vl: String) {
#Persistent
var userCriteria = uc
#Persistent
var name = nm
#Persistent
var value = vl
override def toString = {
"Criteria name: " + name + " value: " + value
}
}
Any ideas why the childs are not stored? Or why I get the error message?
Thanks,
Gero
It looks to me like you are trying to implement an owned one-to-many relationship. Also you seem to have forgotten the #Embedded annotation for the UserCriteria's internalCriteria field, though I think, that it might still not work since the field contains a list and not the embedded class itself.