Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you return an assignable lvalue in Scala?

Tags:

scala

(note, lvalue is actually a term from the C grammar, I don't know what it's called in Scala!)

Trying to learn Scala... this evening I'm working on an internal DSL for a dynamically scoped language that might resemble PHP syntax.

My REPL is: Welcome to Scala version 2.7.6.final (Java HotSpot(TM) Client VM, Java 1.6.0).

I have some made-up example code:


class $(any: Any) {
    def update(sym: Symbol, any: Any) { println("line 2 executed");}
    def ->(sym: Symbol) : $ = { println("line 1 executed"); return this  }
    def update(any: Any) { println("line 3 executed");}
}

The following works as expected:

scala> var a = new $(0)
a: $ = $@19238ad

scala> a('x) = "blah"
line 2 executed

On the other hand, why does the following not invoke the 1-parameter update method?

scala> a = 1
:6: error: type mismatch;
 found   : Int(1)
 required: $
       a = 1
           ^

While doing some trial and error, I found this syntactical curiousity:

scala> class A { def this_= { print("hello") } }
defined class A

scala> var a = new A
a: A = A@9aca82

scala> a = 2
:6: error: type mismatch;
 found   : Int(2)
 required: A
       a = 2
           ^

scala> a.this_
:7: error: value this_ is not a member of A
       a.this_
         ^

What is the meaning over overriding "this_" above? Where does it go?

Ultimately, I would like this to work:

a->'x = "blah"

Thanks

like image 297
Alex R Avatar asked Apr 15 '10 00:04

Alex R


2 Answers

def this_= { print("hello") }

You seem to think this is the method this_ that is equal to { print("hello") }. Instead, this is the method this_=, which uses the procedure style declaration (ie, no equal sign).

It is most often used like this:

scala> class A {
     |   private var _x = ""
     |   def x = _x
     |   def x_=(s: String) = _x = s.toUpperCase
     | }
defined class A

scala> new A
res0: A = A@1169fb2

scala> res0.x
res1: java.lang.String =

scala> res0.x = "abc"

scala> res0.x
res2: java.lang.String = ABC

However, while you coincidentally used a syntax (id_=) which has special meaning, it is just an identifier. Any identifier many mix alphanumeric characters and other symbols, separarted by the underscore character.

Finally, no, there's no assignable lvalue in Scala. You can have things like this:

id(key) = value // with update
id.key = value  // with key_=, as long as key also exists and is public
id += value     // or any other method containing "=" as part of its name

For instance, you could do this:

scala> class A {
     |   private var _x = ""
     |   def :=(s: String) = _x = s.toUpperCase
     |   override def toString = "A("+_x+")"
     | }
defined class A

scala> val x = new A
x: A = A()

scala> x := "abc"

scala> x
res4: A = A(ABC)

But =, by itself, is reserved. And, by the way, there's no pass by reference in Scala -- you'll never be able to change the value of a variable passed as a parameter.

like image 153
Daniel C. Sobral Avatar answered Nov 18 '22 08:11

Daniel C. Sobral


I think what you need is implicit conversion.

scala> case class Test (val x: Int)  
defined class Test

scala> implicit def testFromInt (x: Int) = new Test (x)
testFromInt: (Int)Test

scala> var a = new Test (3)
a: Test = Test(3)

scala> a = 10
a: Test = Test(10)

BTW, I believe you should not use $ as identifier, its usually used in compiler generated class/function.

like image 33
Brian Hsu Avatar answered Nov 18 '22 08:11

Brian Hsu