In the Scala documentation at https://docs.scala-lang.org/tour/classes.html, the following example shows a minimal class definition that includes parameters:
class Point(var x: Int, var y: Int) {
...
}
Both of the following code snippets work correctly for me:
Snippet 1: class Train(number: Int)
Snippet 2: class Train(val number: Int)
What would be the benefit of using val in snippet 2? From what I understand, by default val is implicit. Would code readability by being explicit to say that number is a val and not a var be the only benefit? Thank you.
From the documentation you linked:
Primary constructor parameters with val and var are public.
E.g. (as in the example):
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- does not compile (because vals are immutable)
In this definition you can access x and y, as they are public vals
point.x // 1
point.y // 2
The next paragraph explains:
Parameters without val or var are private values, visible only within the class.
E.g. (as in the example):
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- does not compile
In this definition, x and y are private vals
Thus your snippet 1 has a private val called number
And your snippet 2 has a public val called number
(Just to note) A small caveat to this is case classes, where all arguments of the constructor are public, regardless of the val or var keyword. If omitted, the variable/value will be public.
In Snippet 1, number is a construction parameter and is not a member of the class. It can only be used inside the constructor (the body of the class).
In Snippet 2, number is a public read-only member of the class. It can be used by any code that has an instance of the class.
From what I understand, by default val is implicit.
This is not true for class parameters but is true for case class parameters, which can cause confusion when learning Scala.
I found the answer in Lightbend Scala Language - Professional:
I confirmed it from the REPL:
scala> class Hello(message: String)
class Hello
scala> val hello = new Hello("Hello, world!")
val hello: Hello = Hello#2a454afb
scala> hello.message
^
error: value message is not a member of Hello
scala> class Hello(val message: String)
class Hello
scala> val hello = new Hello("Hello, world!")
val hello: Hello = Hello#639e35dc
scala> hello.message
val res7: String = Hello, world!
Related
I have this:
class Max(val value : Int) extends StaticAnnotation{}
class Child() extends Parent {
#Max(5) val myMember= register("myMember")
}
abstract class Parent {
def register(fieldName : String) = {
val cls = getClass
import scala.reflect.runtime.universe._
val mirror = runtimeMirror(cls.getClassLoader)
val clsSymbol = mirror.staticClass(cls.getCanonicalName)
val fieldSymbol = clsSymbol.typeSignature.member(TermName(fieldName))
println(s"${fieldSymbol.fullName} " + fieldSymbol.annotations.size)
}
}
this does not work, somehow, it returns 0 annotations, if instead, I put the annotation on the class, then I can read it fine. Why?
Discovered that the previous line:
clsSymbol.typeSignature.member(TermName(fieldName))
was returning the symbol of the auto generated getter for the "val" (which of course does not have any annotation), instead of the symbol from the val itself. If instead I do:
clsSymbol.toType.decl(TermName(s"${fieldName} "))
that seems to work fine. For any reason that I do not know, if I write a space at the end of the TermName, then it returns the field symbol with the annotations.
Adding a bit of additional information to your answer to demonstrate and ilustrate the problem:
scala> import scala.annotation.StaticAnnotation
import scala.annotation.StaticAnnotation
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> class Max(val value : Int) extends StaticAnnotation
defined class Max
scala> class Child {
| #Max(5) val myMember = 2
| }
defined class Child
scala> val cls = classOf[Child]
cls: Class[Child] = class Child
scala> val mirror = runtimeMirror(cls.getClassLoader)
mirror: reflect.runtime.universe.Mirror = JavaMirror with... (I truncated this part which was super long and not useful)
scala> mirror.classSymbol(cls).selfType.decls
res0: reflect.runtime.universe.MemberScope = SynchronizedOps(constructor Child, value myMember, value myMember)
scala> println(mirror.classSymbol(cls).selfType.decls)
Scope{
def <init>: <?>;
val myMember: <?>;
private[this] val myMember: scala.Int
}
scala> mirror.classSymbol(cls).selfType.decls.map(_.annotations)
res2: Iterable[List[reflect.runtime.universe.Annotation]] = List(List(), List(), List(Max(5)))
scala> mirror.classSymbol(cls).selfType.decls.map(_.isMethod)
res4: Iterable[Boolean] = List(true, true, false)
scala> mirror.classSymbol(cls).selfType.decls.map(_.asTerm.name)
res15: Iterable[reflect.runtime.universe.TermName] = List(<init>, myMember, myMember )
Only one of them include the annotation, and we can see that the last one which is the actual attribute you defined and not the synthetic getter that the compiler defined automatically, has a space at the end of its name ! I really wonder who thought it was a good idea to do such horrible thing, but it seems to be the reality. I am no Scala expert but this whole API seems very complex to me and unpractical to work with. It probably suffers from the complexity of Scala as a language itself, which under appearances of simplicity and "magic" features, actually has some very complex mechanisms.
To me, a better API should propose one method to get def declarations and another one for getting val and var declarations. Also, the names should probably not be dedupes by a completely unexpected space at the end of the name !
PS: Martin Odersky explained this design choice on the following thread: https://contributors.scala-lang.org/t/design-choice-reflection-valdef-and-synthetic-getter/565
Search results so far have led me to believe this is impossible without either a non-primary constructor
class Foo { // NOT OK: 2 extra lines--doesn't leverage Scala's conciseness
private var _x = 0
def this(x: Int) { this(); _x = x }
def x = _x
}
val f = new Foo(x = 123) // OK: named parameter is 'x'
or sacrificing the name of the parameter in the primary constructor (making calls using named parameters ugly)
class Foo(private var _x: Int) { // OK: concise
def x = _x
}
val f = new Foo(_x = 123) // NOT OK: named parameter should be 'x' not '_x'
ideally, one could do something like this:
class Foo(private var x: Int) { // OK: concise
// make just the getter public
public x
}
val f = new Foo(x = 123) // OK: named parameter is 'x'
I know named parameters are a new thing in the Java world, so it's probably not that important to most, but coming from a language where named parameters are more popular (Python), this issue immediately pops up.
So my question is: is this possible? (probably not), and if not, why is such an (in my opinion) important use case left uncovered by the language design? By that, I mean that the code either has to sacrifice clean naming or concise definitions, which is a hallmark of Scala.
P.S. Consider the case where a public field needs suddenly to be made private, while keeping the getter public, in which case the developer has to change 1 line and add 3 lines to achieve the effect while keeping the interface identical:
class Foo(var x: Int) {} // no boilerplate
->
class Foo { // lots of boilerplate
private var _x: Int = 0
def this(x: Int) { this(); _x = x }
def x = _x
}
Whether this is indeed a design flaw is rather debatable. One would consider that complicating the syntax to allow this particular use case is not worthwhile.
Also, Scala is after all a predominantly functional language, so the presence of vars in your program should not be that frequent, again raising the question if this particular use case needs to be handled in a special way.
However, it seems that a simple solution to your problem would be to use an apply method in the companion object:
class Foo private(private var _x: Int) {
def x = _x
}
object Foo {
def apply(x: Int): Foo = new Foo(x)
}
Usage:
val f = Foo(x = 3)
println(f.x)
LATER EDIT:
Here is a solution similar to what you originally requested, but that changes the naming a bit:
class Foo(initialX: Int) {
private var _x = initialX
def x = _x
}
Usage:
val f = new Foo(initialX = 3)
The concept you are trying to express, which is an object whose state is mutable from within the object and yet immutable from the perspective of other objects ... that would probably be expressed as an Akka actor within the context of an actor system. Outside the context of an actor system, it would seem to be a Java conception of what it means to be an object, transplanted to Scala.
import akka.actor.Actor
class Foo(var x: Int) extends Actor {
import Foo._
def receive = {
case WhatIsX => sender ! x
}
}
object Foo {
object WhatIsX
}
Not sure about earlier versions, but In Scala 3 it can easily be implemented like follows:
// class with no argument constructor
class Foo {
// prive field
private var _x: Int = 0
// public getter
def x: Int = _x
// public setter
def x_=(newValue: Int): Unit =
_x = newValue
//auxiliary constructor
def this(value: Int) =
this()
_x = value
}
Note
Any definition within the primary constructor makes the definition public, unless you prepend it with private modifier
Append _= after a method name with Unit return type to make it a setter
Prepending a constructor parameter neither with val nor with var, makes it private
Then it follows:
val noArgFoo = Foo() // no argument case
println(noArgFoo.x) // the public getter prints 0
val withArgFoo = Foo(5) // with argument case
println(withArgFoo.x) // the public getter prints 5
noArgFoo.x = 100 // use the public setter to update x value
println(noArgFoo.x) // the public getter prints 100
withArgFoo.x = 1000 // use the public setter to update x value
println(withArgFoo.x) // the public getter prints 1000
This solution is exactly what you asked; in a principled way and without any ad hoc workaround e.g. using companion objects and the apply method.
What is the difference between defining an object using the new operator vs defining a standalone object by extending the class?
More specifically, given the type class GenericType { ... }, what is the difference between val a = new GenericType and object a extends GenericType?
As a practical matter, object declarations are initialized with the same mechanism as new in the bytecode. However, there are quite a few differences:
object as singletons -- each belongs to a class of which only one instance exists;
object is lazily initialized -- they'll only be created/initialized when first referred to;
an object and a class (or trait) of the same name are companions;
methods defined on object generate static forwarders on the companion class;
members of the object can access private members of the companion class;
when searching for implicits, companion objects of relevant* classes or traits are looked into.
These are just some of the differences that I can think of right of the bat. There are probably others.
* What are the "relevant" classes or traits is a longer story -- look up questions on Stack Overflow that explain it if you are interested. Look at the wiki for the scala tag if you have trouble finding them.
object definition (whether it extends something or not) means singleton object creation.
scala> class GenericType
defined class GenericType
scala> val a = new GenericType
a: GenericType = GenericType#2d581156
scala> val a = new GenericType
a: GenericType = GenericType#71e7c512
scala> object genericObject extends GenericType
defined module genericObject
scala> val a = genericObject
a: genericObject.type = genericObject$#5549fe36
scala> val a = genericObject
a: genericObject.type = genericObject$#5549fe36
While object declarations have a different semantic than a new expression, a local object declaration is for all intents and purpose the same thing as a lazy val of the same name. Consider:
class Foo( name: String ) {
println(name+".new")
def doSomething( arg: Int ) {
println(name+".doSomething("+arg+")")
}
}
def bar( x: => Foo ) {
x.doSomething(1)
x.doSomething(2)
}
def test1() {
lazy val a = new Foo("a")
bar( a )
}
def test2() {
object b extends Foo("b")
bar( b )
}
test1 defines a as a lazy val initialized with a new instance of Foo, while test2 defines b as an object extending Foo.
In essence, both lazily create a new instance of Foo and give it a name (a/b).
You can try it in the REPL and verify that they both behave the same:
scala> test1()
a.new
a.doSomething(1)
a.doSomething(2)
scala> test2()
b.new
b.doSomething(1)
b.doSomething(2)
So despite the semantic differences between object and a lazy val (in particular the special treatment of object's by the language, as outlined by Daniel C. Sobral),
a lazy val can always be substituted with a corresponding object (not that it's a very good practice), and the same goes for a lazy val/object that is a member of a class/trait.
The main practical difference I can think of will be that the object has a more specific static type: b is of type b.type (which extends Foo) while a has exactly the type Foo.
My goal is to enhance inside scala code an existing Java class using a trait mix-in. For example to add a method like java.awt.Rectangle.translate(dx, dy) to java.awt.geom.Ellipse2D class. For this I create the following trait:
trait RectangleLike {
var x: Double // abstract vals to correspond to java class fields
var y: Double // I need these vars to refer to them inside translate method
def translate(dx: Double, dy: Double) {
x = x + dx
y = y + dy
}
// more concrete trait methods here
} // defines without errors in scala REPL
Then use the trait when constructing an Ellipse:
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
However when I execute the above script in scala REPL I get the following output:
<console>:8: error: overriding variable x in trait RectangleLike of type Double;
variable x in class Double of type Double has incompatible type;
other members with override errors are: y
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
I suspect that this error is due to the way Scala implements vars - as a private field and a getter/setter pair of methods. Is what I try to achieve doable? Is there another way to define the java class fields in the trait and then refer to them inside the concrete trait methods?
Thanks in advance
Jack Dimas
Yes, it is doable but instead of trying to access the private fields of the classes you want to mix in with (which is most likely a bad idea anyway), you would want to declare the self-type of RectangleLike to be java.awt.geom.RectangularShape so that you can use your trait with e.g. Ellipse2D.Double just as well as with Rectangle2D.Double.
Here is how it works:
trait RectangleLike {
self: java.awt.geom.RectangularShape =>
def translate(dx: Double, dy: Double) {
setFrame(getX + dx, getY + dy, getX + getWidth, getY + getHeight)
}
}
object Test {
val foo = new java.awt.geom.Ellipse2D.Double with RectangleLike
}
By saying self: java.awt.geom.RectangularShape => you declare the self-type of your trait which enables you to access all corresponding methods like the necessary getters and setters, allows for using your trait with all descendants of RectangularShape, and also "restricts" your trait so that it can only be used as a mixin to classes which themselves are subtypes of RectangularShape.
The alternative to the above scenario is using a so-called view of your RectangularShape which is a common paradigm as well. For this, you would e.g. declare a class
class RichRectangularShape(shape: java.awt.geom.RectangularShape) {
def translate(dx: Double, dy: Double) {
shape.setFrame(shape.getX + dx, shape.getY + dy,
shape.getX + shape.getWidth, shape.getY + shape.getHeight)
}
}
Scala has a way of implicitly viewing an object of one type as an object of another type. If you happen to call a method on a object which is not declared in its corresponding type, the compiler trys to find a type that provides this method and in particular also trys to find an implicit conversion so that your original object can be viewed as an instance of the latter type. For this to work, you would typically declare the companion object of RichRectangularShape as something like this:
object RichRectangularShape {
implicit def mkRRS(shape: java.awt.geom.RectangularShape): RichRectangularShape =
new RichRectangularShape(shape)
}
Then:
scala> import RichRectangularShape._
import RichRectangularShape._
scala> val foo = new java.awt.geom.Ellipse2D.Double
foo: java.awt.geom.Ellipse2D.Double = java.awt.geom.Ellipse2D$Double#0
scala> foo.translate(5,2)
scala> foo.getX
res1: Double = 5.0
scala> foo.getY
res2: Double = 2.0
scala> :t foo
java.awt.geom.Ellipse2D.Double
Indeed impressive explanation and example!
I have one little problem with this approach, the translate method includes the real calculation that I would like to avoid. Yes in this case it is very simple but generally speaking such method may be complicated and lead to the serious development. Therefore I suggest the following approach:
trait RectangleLike extends java.awt.geom.RectangularShape {
def translate(dx: Int, dy: Int): Unit = {
val rect = new java.awt.Rectangle
rect.setRect(getX, getY, getWidth, getHeight)
rect.translate(dx,dy)
setFrame(rect.getX, rect.getY, rect.getWidth, rect.getHeight)
}
}
In this way I am using the original translate calculation.
Consider the file bug.scala:
package sandbox
object Foo {
implicit def stringToInt(s: String) = 5
}
import Foo._
class Boo(val a: Int = "foo" / 3) {
val b: Int = "foo" / 3
def c(d: Int = "foo" / 3) = d
}
It defines an implicit conversion, imports it, and uses it in three slightly different scenarios. Compile it:
E:\prog\scala\test>scalac bug.scala
bug.scala:9: error: value / is not a member of java.lang.String
class Boo(val a: Int = "foo" / 3) {
^
one error found
The implicit conversion seems not to be working when used for a default constructor parameter, but works for the other scenarios.
Now watch this:
package sandbox
object Foo {
implicit def stringToInt(s: String) = 5
}
object dummy
import Foo._
import dummy._
class Boo(val a: Int = "foo" / 3) {
val b: Int = "foo" / 3
def c(d: Int = "foo" / 3) = d
}
We've simply added an empty object and imported it. Now the file compiles without errors!
I see two possibilities here: 1) My head is messing with me. 2) There's a bug in the compiler. Can anyone confirm it's the latter?
(Using Scala 2.8.1.)
Definitely a bug. I've lodged it on your behalf.
https://issues.scala-lang.org/browse/SI-4141