In scala I'm not allowed to perform the following:
case class Terminal(value: Double, name: String = value.toString)
Moreover I also cannot do this:
case class Terminal(value: Double)(name: String = value.toString)
I understand the multiple parameter list approach is not supported for constructors.
Is is there a way to define in the apply method in order to make this possible?
Expected behavior:
Terminal(1.0) // => Terminal (1.0, "1.0")
You can't do this in the case class itself, and it won't make a constructor, but it is possible through the apply method on the companion.
case class Terminal(value: Double, name: String)
object Terminal {
def apply(value: Double): Terminal = Terminal(value, value.toString)
}
Note that:
def apply(value: Double, name: String = value.toString) = new Terminal(value, name)
is an error because it conflicts with the autogenerated apply.
Maybe you just want this?
case class Terminal(value: Double) {
val name = a.toString
}
Related
i have following class hierarchy.
trait Item {val id: String}
case class MItem(override val id: String, val name: String) extends Item
class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name)
val d = new DItem("1", "one", "another one")
println(d)
Expected Output
DItem(1, one, another one)
Actual Output
Mitem(1,one)
Why is this happening. What is recommended so that i get the real type of my object and the not type of super class.
This is not a type erasure. You are getting this result because DItem gets toString() implementation inherited from Mitem. You have to override it to get what you want
class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
override def toString = s"DItem($id, $name, $name2)"
}
So here is a result:
scala> val d = new DItem("1", "one", "another one")
d: DItem = DItem(1, one, another one)
scala> println(d)
DItem(1, one, another one)
It is almost always a bad idea to inherit from case classes because besides toString successor class will also inherit equals and hashCode.
Another drawback is limited pattern-matching for such successor classes i.e it is impossible to use such classes in case branches and may lead to confusing errors.
Example
case class A(id: String)
class B(id: String, name: String) extends A(id)
new B("foo", "bar") match {
case A(id) => println(id)
case other => println(other)
}
You may expect that there is no error in this code, but you'll get
<console>:17: error: constructor cannot be instantiated to expected type;
found : A
required: B
case A(id) => println(id)
^
However if you'll infer a type for B instance explicitly it will work
scala> new B("foo", "bar").asInstanceOf[A] match {
| case A(id) => println(id)
| case other => println(other)
| }
foo
So... Inheriting from case classes is very error-prone and confusing and should be avoided unless you know what are you doing.
Inheriting from case classes is deprecated as far as I know. So case classes can (should) only inherit from regular classes.
doing println usually invoke toString on the object pass on it.
so what happen on your code is, it will invoke the toString implementation of the object, it happens to be MItem that has this implementation.
so you need to override the toString on DItem like this:
class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
override def toString = s"DItem($id, $name, $name2)"
}
if you want to just get the type of the object you can use getClass.
println(d.getClass)
Say I have a case class:
case class Name(first: String, last: String)
val n1 = Name("John", "Doe")
val n2 = Name("Mary", "Doe")
and I have a java script object:
#js.native
trait MyJSObject extends js.Object {
def add(name: js.Object): Unit = js.native
}
such that name should be of the format
{"first":"John","last":"Doe"}
What is the best way to convert my case object to a js.Object?
I know this can be achieved doing a upickle.write() to convert it to a json String so I guess my question is is this the best way?
If you control the case class, you can just add the #JSExportAll annotation to it:
#JSExportAll
case class Name(first: String, last: String)
This will create properties named first and last. Note that this is not the same as a simple object. However, depending on what the add method does, it is sufficient (and much more lightweight than converting to JSON and parsing again).
In case you need to cross compile the case class, you can include the scalajs-stubs library in your JVM project. It will provide dummy annotations (that are not written to .class files).
If you need a js.Object, you can use the export typechecker:
val x = Name("foo", "bar")
js.use(x).as[js.Object]
This will even work with a trait that defines the fields you need:
#js.native
trait Options extends js.Object {
def first: String = js.native
def last: String = js.native
}
val x = Name("foo", "bar")
js.use(x).as[Options]
The js.use(x).as call will fail, if there is a mismatch between the types (i.e. if Options defines a field that Name doesn't define).
With uPickle:
val jsValue: Js.Value = upickle.Types.writeJs[Name](n1)
val jsObject: js.Any = upickle.json.writeJs(jsValue).asInstanceOf[js.Any]
I had a case class with a option parameter, let's say:
case class Student(id: Option[Int], name: String)
To get a Student instance, not only I could use Student(Some(1), "anderson"), I also want this form to be a valid way Student(2,"Sarah")
I guess I have to create a Int => Option[Int] and put it somewhere. So what's the best way to do so?
Update
As mentioned in the comment, override apply method will block calling it by Student.apply _
It might be easier to just make an apply method in a companion object.
case class Student(id: Option[Int], name: String)
object Student {
def apply(id: Int, name: String): Student = {
Student(Some(id), name)
}
}
An alternative solution using implicit conversions:
implicit def intToOption(x: Int) = Some(x)
case class Student(id: Option[Int], name: String)
scala> Student(1,"Nu")
res1: Student = Student(Some(1),Nu)
Using Scala, I want to achieve the following:
// SETUP:
implicit class ExampleOps(s: String) {
def name: String = ???
}
case class Example(prop1: String, prop2: String)
val e = Example("a", "b")
// BEHAVIOR I WANT:
e.prop1.name // should return "prop1"
In this case def name somehow knows what it's being called on. How is this accomplished?
As I explained in the comment, macros could be used to a certain extent. However, they can not magically restore some information that is lost. For example if you store the property value in an arbitrary variable, there is no way to figure out from which property it was read:
val x: String = e.prop1
x.name // no way to know if came from calling e.prop1
So I think the only solution is to use a custom type. You could allow them to be unrolled as strings implicitly:
object Property {
implicit def value[A](prop: Property[A]): A = prop.value
}
case class Property[+A](name: String, value: A)
case class Example(value1: String, value2: String) {
def prop1 = Property("prop1", value1)
def prop2 = Property("prop2", value2)
}
val e = Example("a", "b")
e.prop1.toUpperCase
e.prop1.name
{
class MyClass(name: String) {}
val x = new MyClass("x")
println(x.name) // Error name is not a member of MyClass
}
but
{
abstract class Base
case class MyClass(name: String) extends Base {}
var x = new MyClass("x")
println(x.name) // name is a member of MyClass
}
So, what's the deal with case classes? Why are all of the constructor parameters turned into variables.
name is member in both examples, but private in your first example while public in your second. Case classes make their constructor parameters public val by default.
Pattern matching is the most important but not the only application for case classes. Another important point is that they implement the equals and hashCode methods in terms of the constructor arguments (aka product elements). Therefore, case classes are very useful for defining data structures that serve as elements in sets or keys in maps. That in turn only makes sense if these elements are visible.
Compare:
class Foo(val i: Int)
val set1 = Set(new Foo(33))
set1.contains(new Foo(33)) // false!!
And:
case class Bar(val i: Int)
val set2 = Set(Bar(33)
set2.contains(Bar(33)) // true!
Two case class instances with equal parameters are equal themselves. You can imagine them representing some "constants". This implies that you should not have mutable state in them.
You can, however, use a second parameter list to exclude arguments from the equality:
case class Baz(i: Int)(val n: Long)
Baz(33)(5L) == Baz(33)(6L) // true!
Another useful feature which implies that the constructor arguments become values, is making copies. This is the way immutable data is changes—you create a new instance with a particular value changed, leaving the original value in place.
case class Person(name: String, age: Int)
val p1 = Person("Fuzzi", 33)
val p2 = p1.copy(age = 34)
The copy method uses default values for all unspecified argument, taking those values from the constructor args.
Just to be clear, the constructor arguments aren't used to create variables, they're used to create values.
If you specify val in your first example, the non-case class:
class MyClass(val name: String) {}
then you also get the argument translated into a public value, the same as is done for the case class.
In the example on the Scala-Lang site it says:
It makes only sense to define case classes if pattern matching is used
to decompose data structures. The following object defines a pretty
printer function for our lambda calculus representation:
followed by the example code:
object TermTest extends Application { def printTerm(term: Term) {
term match {
case Var(n) =>
print(n)
case Fun(x, b) =>
print("^" + x + ".")
printTerm(b)
case App(f, v) =>
Console.print("(")
printTerm(f)
print(" ")
printTerm(v)
print(")")
} } def isIdentityFun(term: Term): Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false } val id = Fun("x", Var("x")) val t = Fun("x", Fun("y", App(Var("x"), Var("y")))) printTerm(t) println println(isIdentityFun(id)) println(isIdentityFun(t)) }
To add something to my comment due to lack of available space: consider the following example case class:
case class My(x: Int)
If you save it to file and pass it to scalac -print, you get following expanded code (I removed unimportant stuff):
case class My extends Object with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val x: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def x(): Int = My.this.x;
Notice <caseaccessor>s here.
And then companion object:
<synthetic> object My extends runtime.AbstractFunction1 with Serializable {
case <synthetic> def apply(x: Int): My = new My(x);
case <synthetic> def unapply(x$0: My): Option = if (x$0.==(null))
scala.this.None
else
new Some(scala.Int.box(x$0.x()));
case <synthetic> <bridge> def apply(v1: Object): Object = My.this.apply(scala.Int.unbox(v1));
//...
Notice apply and unapply here. If you look at complete output yourself, you'll learn more about how scala generates your code.