I want to define one (or two, depends on how you look at it) operators in scala.
Something like this : _ ==> _ | _ where the underscore stands for the arguments.
The tricky part is, that the operator should be used in an constructor to set the fields of the object.
I wrote a small example, using implicits and a wrapper object. But that approach clearly does not work.
I don't know, how i can set the fields of the current object.
In this example, every create object from type B should have set its fields to "B", 44 and "foo". The result of "B" ==> 44 | "foo" should be the same as this.a = "B"; this.b = 44; this.c = foo.
Is there a way to achieve that?
Thanks!
abstract class Top {
var a = "a"
var b = 3
var c = "c"
implicit def js2WJ(js: String) : Wrapper = {
new Wrapper(js)
}
}
case class B() extends Top
{
"B" ==> 44 | "foo"
}
class Wrapper(js: String)
{
var ju : Option[Int] = None
var cs : Option[String] = None
def ==>(j: Int): Wrapper = {
ju = Some(j)
this
}
def | (cs: String) =
{
this.cs = Some(cs)
}
}
Is this what you needed?
abstract class Top {
var a = "a"
var b = 3
var c = "c"
implicit def js2WJ(js: String): TopBuilder = TopBuilder(js, b, c, this)
}
case class TopBuilder(a: String, b: Int, c: String, top: Top) {
def ==> (j: Int) = copy(b = j)
def | (s: String) = copy(c = s) toTop
def toTop {
top.a = a
top.b = b
top.c = c
}
}
object B extends Top {
"B" ==> 44 | "foo"
}
Related
I know that one can define an operator in Scala like this :
class value(var valu:Int) {
def +(i:Int) = { this.valu + i }
def ==>(i:Int ) = { this.valu = i }
}
But I cannot seem to overload the = operator like this :
class value(var valu:Int) {
def =(i:Int) = { this.valu = i }
}
Do you know if there is any way to do this?
The syntax for making mutable objects isn't obvious and isn't encountered often because mutability is generally undesirable.
class Value(private var valu:Int) {
def update(i:Int) :Unit = valu = i
}
val v = new Value(19)
v() = 52
= is a reserved word like yield, so to use it as an identifier, you put it in backticks, though I suspect no one does that:
scala> class C(var i: Int) { def `=`(n: Int) = i = n }
defined class C
scala> val c = new C(42)
c: C = C#9efcd90
scala> c.`=`(27)
scala> c.i
res1: Int = 27
scala> c `=` 5
scala> c.i
res3: Int = 5
Compare:
scala> val yield = 2
^
error: illegal start of simple pattern
scala> val `yield` = 2
yield: Int = 2
This is what I want to do -
class A(some args) {
var v: SomeType = null
def method1(args) = {
v = something1
...
method3
}
def method2(args) = {
v = something2
...
method3
}
def method3 = {
// uses v
}
}
In this specific case method1 and 2 are mutually exclusive and either one of them is called exactly once in the lifetime of an instance of A. Also, v is assigned once. I would prefer making it a val. But since I need method2 or method3's context to initialize v, I can't do that in the constructor.
How can achieve this "val" behavior? I can think of modifying method1 and method2 to apply methods, but I don't like the idea. Moreover, method1 and 2 have the same argument signature (hence apply would need some more info to distinguish the 2 types of calls).
An important question is: what exactly do you call "val behavior"? To me "val behavior" is that is assigned once immediately when it is declared, which can be enforced statically. You seem to want to enforce that v is not assigned twice. You possibly also want to enforce it is never read before it is assigned. You could create a very small helper box for that:
final class OnceBox[A] {
private[this] var value: Option[A] = None
def update(v: A): Unit = {
if (value.isDefined)
throw new IllegalStateException("Value assigned twice")
value = Some(v)
}
def apply(): A = {
value.getOrElse {
throw new IllegalStateException("Value not yet assigned")
}
}
}
and now your snippet:
class A(some args) {
val v = new OnceBox[SomeType]
def method1(args) = {
v() = something1
...
method3
}
def method2(args) = {
v() = something2
...
method3
}
def method3 = {
// uses v
v()
}
}
Oh and, just kidding, but Ozma has single-assignment vals built-in :-p
Similar idea to the other answer, but instead of subtypes, a field.
scala> :pa
// Entering paste mode (ctrl-D to finish)
class A {
private[this] var context: Int = _
lazy val v: String =
context match {
case 1 => "one"
case 2 => "two"
case _ => ???
}
def m1() = { context = 1 ; v }
def m2() = { context = 2 ; v }
}
// Exiting paste mode, now interpreting.
defined class A
scala> val a = new A
a: A = A#62ce72ff
scala> a.m2
res0: String = two
scala> a.m1
res1: String = two
Something like this maybe:
class A private (mtdType: Int, ...) {
val v = mdtType match {
case 1 => method1(...)
case 2 => method2(...)
}
}
object A {
def withMethod1(...) = new A(1, ...)
def withMethod2(...) = new A(2, ...)
}
Or, another possibilty:
sealed trait A {
val v
def method3 = println(v)
}
class Method1(...) extends A {
val v = method1(...)
}
class Method2(...) extends A {
val v = method2(...)
}
I would ensure that a method should only accept instances of A or B or C. And I don't want to modify the code of A, B and C.
case class A
case class B
case class C
def method(aOrbOrc: Any) = ???
// method("toto") should not compile
You can use Type Class.
case class A(s: String)
case class B(i: Int)
case class C(i1: Int, i2: Int)
// Type Class
trait ABC[T] {
def bar(t: T): String
}
// Instances
implicit object ABC_A extends ABC[A] {
override def bar(t: A): String = "A : s = " + t.s
}
implicit object ABC_B extends ABC[B] {
override def bar(t: B): String = "B : i = " + t.i
}
implicit object ABC_C extends ABC[C] {
override def bar(t: C): String = "C : i1 = " + t.i1 + ", i2 = " + t.i2
}
def method[T](abc: T)(implicit instance: ABC[T]) = println(instance.bar(abc))
method(A("AAAAA")) // => A : s = AAAAA
method(B(123)) // => B : i = 123
method(C(9, 5)) // => C : i1 = 9, i2 = 5
method(1) // compilation error
You could use Miles Sabin's idea for implementing union types (code below is taken from Rex Kerr's variant):
trait Contra[-A] {}
type Union[A,B,C] = {
type Check[Z] = Contra[Contra[Z]] <:< Contra[Contra[A] with Contra[B] with Contra[C]]
}
then do:
def method[T: Union[A,B,C]#Check](t: T) = ???
for example:
def method[T: Union[Int,String,Boolean]#Check](t:T) = ???
method(1) // OK
method("foo") // OK
method(true) // OK
method(1.5) // does not compile
Read more about it here. And here is a link to Miles' post.
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)