This works:
class ButtonCountObserver {
private var cnt = 0 // private field
def count = cnt // reader method
def count_=(newCount: Int) = cnt = newCount // writer method
// ...
}
val b = new ButtonCountObserver
b.count = 0
But this doesn't
class ButtonCountObserver {
private var cnt = 0 // private field
def count_=(newCount: Int) = cnt = newCount // writer method
// ...
}
val b = new ButtonCountObserver
b.count = 0
I get: error: value count is not a member of ButtonCountObserver
Is it possible to create a setter (with the syntactic sugar) without a getter?
The spec requires that both a setter and getter are defined to be able to use the syntactic sugar for calling the setter:
The interpretation of an assignment to
a simple variable x = e depends on the
definition of x. If x denotes a
mutable variable, then the assignment
changes the current value of x to be
the result of evaluating the
expression e. The type of e is
expected to conform to the type of x.
If x is a parameterless function
defined in some template, and the same
template contains a setter function
x_= as member, then the assignment x =
e is interpreted as the invocation
x_=(e ) of that setter function.
Analogously, an assignment f .x = e to
a parameterless function x is
interpreted as the invocation f .x_=(e
). An assignment f (args) = e with a
function application to the left of
the ‘=’ operator is interpreted as f
.update(args, e ), i.e. the invocation
of an update function defined by f .
Furthermore, the getter must be visible in order to use the setter. I'm not sure if this is specified
Getter not visible #1
// error: method x cannot be accessed in x.Test
object x {
class Test {
private[this] var x0: Int = 0
private[Test] def x = x0
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
Getter not visible #2
//<console>:11: error: type mismatch; found : x.Test required: ?{val x: ?}
object x {
class Test {
private[this] var x0: Int = 0
private[this] def x = x0
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
Getter visible
object x {
class Test {
private[this] var x0: Int = 0
private[x] def x = x0
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
As retronym pointed out, there must be a getter present. As a workaround however (if you don't want to provide a getter), you can make the getter return Unit
object x {
class Test {
private[this] var x0: Int = 0
def x: Unit = ()
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
Don't think that that is considered good style (!), but it works.
Related
The scope of a name introduced by a declaration or definition is the
whole statement sequence containing the binding. However, there is a
restriction on forward references in blocks: In a statement sequence
s[1]...s[n] making up a block, if a simple name in s[i] refers to
an entity defined by s[j] where j >= i, then for all s[k]
between and including s[i] and s[j],
s[k] cannot be a variable definition.
If s[k] is a value definition, it must be lazy.
Edit: I am not sure Mikaël Mayer's answer actually explained everything. Consider:
object Test {
def main(args: Array[String]) {
println(x)
lazy val x: Int = 6
}
}
Here, the lazy value x definitely has to be read/evaluated before it is actually defined in the code! Which would contradict Mikaël's claim that lazy evaluation does away with the need to evaluate things before they are defined.
Normally you cannot have this:
val e: Int = 2
val a: Int = b+c
val b: Int = c
val c: Int = 1
val d: Int = 0
because value c is not yet defined at the time of the definition of a. Because a references c, all values between a and c should be lazy so that the dependency is avoided
val e: Int = 2
lazy val a: Int = b+c
lazy val b: Int = c
lazy val c: Int = 1
val d: Int = 0
This in fact translates a, b and c as objects whose value is initialized when it is read, which would be after the declaration, i.e. this would be equivalent to:
val e: Int = 2
var a: LazyEval[Int] = null
var b: LazyEval[Int] = null
var c: LazyEval[Int] = null
a = new LazyEval[Int] {
def evalInternal() = b.eval() + c.eval()
}
b = new LazyEval[Int] {
def evalInternal() = c.eval()
}
c = new LazyEval[Int] {
def evalInternal() = 1
}
val d = 0
where LazyEval would be something like the following (implemented by the compiler itself)
class LazyEval[T] {
var value: T = _
var computed: Boolean = false
def evalInternal(): T // Abstract method to be overriden
def eval(): T = {
if(computed) value else {
value = evalInternal()
computed = true
value
}
}
}
Edit
vals don't really exist in java. They are local variables or do not exist in computation. Therefore, the declaration of lazy val exists before anything is done. And remember that closures are implemented in Scala.
Your block would be rewritten as it:
object Test {
def main(args: Array[String]) {
// Declare all variables, val, vars.
var x: Lazy[Int] = null
// No more variables to declare. Lazy/or not variable definitions
x = new LazyEval[Int] {
def evalInternal() = 6
}
// Now the code starts
println(x)
}
}
You're trying to avoid references to entities which are provably uninitialized (or which are maybe uninitialized).
In a block, assignments occur in source order, but in a class template, members can be overridden and initialized early.
For instance,
{ val a = b ; val b = 1 } // if allowed, value of a is undefined
but in a template
class X { val a = b ; val b = 1 } // warning only
val x = new { override val b = 2 } with X
x.a // this is 2
class Y(override val b: Int) extends X // similarly
You also want to avoid this:
locally {
def a = c
val b = 2 // everything in-between must be lazy, too
def c = b + 1
}
Local objects are explicitly the same as lazy vals:
{ object p { val x = o.y } ; object o { val y = 1 } }
Other kinds of forward reference:
{ val x: X = 3 ; type X = Int }
The spec talks about forward references to "entities" -- a "name refers to an entity" -- which elsewhere means both terms and types, but obviously it really means only terms here.
It will let you harm yourself:
{ def a: Int = b ; def b: Int = a; a }
Maybe your mode of self-destruction must be well-defined. Then it's OK.
Can I use multiple parameters in setters?
For example:
private var _a = 0
def a = _a
def a_= (b: Int, c: Int) = _a = b + c
If yes, how can I call the setter method?
What about a tuple?
class A {
private var _a = 0
def a = _a
def a_= (t: (Int, Int)) {
_a = t._1 + t._2
}
}
If you don't like awkward tuple access syntax:
class A {
private var _a = 0
def a = _a
def a_= (t: (Int, Int)) {
t match {
case(b, c) => _a = b + c
}
}
}
Usage:
val x = new A()
x.a = (3, 7)
x.a //10
If you need to set single value from two other values it is probably not a 'setter'. Consider giving this operation a meaningful name or moving it out of this class.
private var _s: Whatever = // init
def s_=(newValue: Whatever): Unit = _setter = newValue
...
implicit def t2whatever(t: (SomeTypeA, SomeTypeB)): Whatever = // some logic here
now we cal call our setter
obj.setter = sta -> stb
// or
obj.setter = (sta, stb)
Which is more or less the same as with plain tuples however, setter semantic isn't mangled.
In case its internal operations in may look like:
class Z {
private var _s = // init
def s = _s
def s_=(newValue: S) = _s = newValue
}
object Z {
def toS(a: S, b: S): S = ChineseZodiac.choose(0.14 * a, math.PI + b)
}
and then
obj.s = Z.toS(1, 2)
This works:
class ButtonCountObserver {
private var cnt = 0 // private field
def count = cnt // reader method
def count_=(newCount: Int) = cnt = newCount // writer method
// ...
}
val b = new ButtonCountObserver
b.count = 0
But this doesn't
class ButtonCountObserver {
private var cnt = 0 // private field
def count_=(newCount: Int) = cnt = newCount // writer method
// ...
}
val b = new ButtonCountObserver
b.count = 0
I get: error: value count is not a member of ButtonCountObserver
Is it possible to create a setter (with the syntactic sugar) without a getter?
The spec requires that both a setter and getter are defined to be able to use the syntactic sugar for calling the setter:
The interpretation of an assignment to
a simple variable x = e depends on the
definition of x. If x denotes a
mutable variable, then the assignment
changes the current value of x to be
the result of evaluating the
expression e. The type of e is
expected to conform to the type of x.
If x is a parameterless function
defined in some template, and the same
template contains a setter function
x_= as member, then the assignment x =
e is interpreted as the invocation
x_=(e ) of that setter function.
Analogously, an assignment f .x = e to
a parameterless function x is
interpreted as the invocation f .x_=(e
). An assignment f (args) = e with a
function application to the left of
the ‘=’ operator is interpreted as f
.update(args, e ), i.e. the invocation
of an update function defined by f .
Furthermore, the getter must be visible in order to use the setter. I'm not sure if this is specified
Getter not visible #1
// error: method x cannot be accessed in x.Test
object x {
class Test {
private[this] var x0: Int = 0
private[Test] def x = x0
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
Getter not visible #2
//<console>:11: error: type mismatch; found : x.Test required: ?{val x: ?}
object x {
class Test {
private[this] var x0: Int = 0
private[this] def x = x0
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
Getter visible
object x {
class Test {
private[this] var x0: Int = 0
private[x] def x = x0
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
As retronym pointed out, there must be a getter present. As a workaround however (if you don't want to provide a getter), you can make the getter return Unit
object x {
class Test {
private[this] var x0: Int = 0
def x: Unit = ()
def x_=(a: Int) = x0 = a
}
val t = new Test
t.x = 1
}
Don't think that that is considered good style (!), but it works.
I want to do this:
var (a, b) = (0, 0)
a = (b = 100)
but Scala is complaining that
error: type mismatch;
found : Unit
required: Int
What I want is to assign a and b to the same value.
Why Scala make it Unit where it should be Int?
Your statement is an assignment, which returns Unit.
See this related question for reasons why. You can do this, if you want:
scala> var (a,b) = (0,0)
a: Int = 0
b: Int = 0
scala> a = {b = 100; b}
a: Int = 100
scala> var a,b,c,d,e,f,g = 0
a: Int = 0
b: Int = 0
c: Int = 0
d: Int = 0
e: Int = 0
f: Int = 0
g: Int = 0
scala> var f,i,j,k,m,n,o = new Object{}
f: java.lang.Object = $anon$1#11ce012
i: java.lang.Object = $anon$2#baf4ae
j: java.lang.Object = $anon$3#15e68d
k: java.lang.Object = $anon$4#1d3633c
m: java.lang.Object = $anon$5#118317f
n: java.lang.Object = $anon$6#15998cb
o: java.lang.Object = $anon$7#13e6f83
scala>
Why ask why? Assignment expressions have type Unit and that's how it is. No chained assignments. Period.
You can define a special assignment operator (it must end with a colon as it must be right associative) for your own types, or write a generic wrapper (including implit conversions) for general types. I wouldn't recommend to actually use this, but here it goes:
case class M[T](var t:T) {
def =: (m: M[T]):M[T] = {m.t = t ; this}
}
implicit def anyToM[T](v:T) = M(v)
implicit def mToAny[T](m:M[T]) = m.t
def main(args: Array[String]) {
var a = M(0)
var b = M(0)
var c = M(0)
a =: b =: c =: 100
println(a + b + c) //--> 300
}
I think it is always a bad idea to summon heavy magick in order to save a few keystrokes. In Germany we would call this "to shoot sparrows with a cannon"...
case class assign[T](v: T) {
def to(vals: (T => Unit)*) { vals.foreach{ vv => vv(v) } }
}
var (a,b) = (0,0)
assign(39) to (a = _, b = _)
assert(a == 39)
assert(b == 39)
Or you can rename it to emulate a rather simple version of a with statement.
with(20) do (a = _, b = _, print)
When this code is executed:
var a = 24
var b = Array (1, 2, 3)
a = 42
b = Array (3, 4, 5)
b (1) = 42
I see three (five?) assignments here. What is the name of the method call that is called in such circumstances?
Is it operator overloading?
Update:
Can I create a class and overload assignment? ( x = y not x(1) = y )
Having this file:
//assignmethod.scala
object Main {
def main(args: Array[String]) {
var a = 24
var b = Array (1, 2, 3)
a = 42
b = Array (3, 4, 5)
b (1) = 42
}
}
running scalac -print assignmethod.scala gives us:
[[syntax trees at end of cleanup]]// Scala source: assignmethod.scala
package <empty> {
final class Main extends java.lang.Object with ScalaObject {
def main(args: Array[java.lang.String]): Unit = {
var a: Int = 24;
var b: Array[Int] = scala.Array.apply(1, scala.this.Predef.wrapIntArray(Array[Int]{2, 3}));
a = 42;
b = scala.Array.apply(3, scala.this.Predef.wrapIntArray(Array[Int]{4, 5}));
b.update(1, 42)
};
def this(): object Main = {
Main.super.this();
()
}
}
}
As you can see the compiler just changes the last one (b (1) = 42) to the method call:
b.update(1, 42)
Complementing Michael's answer, assignment can't be overridden in Scala, though you can create an assignment-like operator, like :=, for example.
The "assignments" that can be overridden are:
// method update
a(x) = y
// method x_=, assuming method x exists and is also visible
a.x = y
// method +=, though it will be converted to x = x + y if method += doesn't exist
a += y