0

If I can do this:

var num: Int = 1
num += 1
print(num)

Why can’t I do this? What would be the correct way? Fails on line 4

var num: Int = 1
def someFunction(num:Int){
    num += 1
}
someFunction(num)
print(num)

Thanks for any insight. I've done some searching but nothing too helpful. I am mostly looking for the theory behind why this fails. I have accomplished what I need to with for statements but I am still wondering why this fails. Thanks!

Andrew Cassidy
  • 2,940
  • 1
  • 22
  • 46
riorben
  • 95
  • 6

3 Answers3

2

Because the JVM uses call-by-value semantics, and because Int is a primitive type (not an object reference).

What this means is that num inside the method is not the same as num on the outside, the only thing passed to the method is 1

It's a good thing too... It's bad enough when you have a mutable object and some innocent-looking method goes and changes things around behind your back. I don't wish to imagine the new category of bugs that would emerge if the same risk also existed for simple numbers!

Kevin Wright
  • 49,540
  • 9
  • 105
  • 155
2

It's a similar behavior to what you would see in Java. In Java and Scala you pass by value. A reference to your object/argument is copied and passed into the function. Thus, even if you would be able to change the value of that reference (num:Int) you would be working with a copy of that value - essentially a reassignment. Reassignment to arguments is allowed in Java by default but not in Scala. In other words there is nothing like C/C++ has where you can reference external variable and modify its value. That being said you can still achieve similar effect if the value you are trying to modify is an object field:

// I'm changing it directly but you could have a setter instead:
scala> class A(var m: Int)
defined class A

scala> val a = new A(0)
a: A = A@469c3554

scala> a.m
res0: Int = 0

scala> def someFunction(a: A, newVal: Int): Unit = { a.m = newVal }
someFunction: (a: A, newVal: Int)Unit

scala> someFunction(a, 3)

scala> a.m
res2: Int = 3

Using mutable state like this is NOT recommended. This example is just for illustration purposes. In this case you pass a copy of object reference a from which you can access the field directly and modify it.

If you want to understand this better read up on passing by value and passing by reference. Contrast C/C++ pointer and by reference args with Java and Scala. One difference between Scala and Java here is that in Java everything is a var by default, so if you write your arg as final num in Java it will also fail compilation and will work similarly to Scala in this case.

yǝsʞǝla
  • 16,272
  • 2
  • 44
  • 65
  • 1
    Thank you! This helps a lot coming from PHP – riorben Feb 03 '14 at 18:21
  • @AlekseyIzmailov isn't another difference that in Java there is no such thing as a reference to a primitive, but in scala primitives (Int, Double, etc) are fully fledged objects with references? – Andrew Cassidy Feb 03 '14 at 19:04
  • You can, however, access a `var` in a containing scope if you *don't* pass it in as a parameter (which would also work in PHP). See the "even worse" part of my answer. – Ian McLaird Feb 03 '14 at 19:05
  • @IanMcLaird aren't you just rewriting the += function using lexical scope if you do that? You could just do num += 1.. There is no need to write another increment function – Andrew Cassidy Feb 03 '14 at 19:08
  • Well, sure, but that's exactly what the example in question is asking to do. You could, conceivably, do anything you wanted with that variable, since you have access to it. – Ian McLaird Feb 03 '14 at 19:09
  • Though I'll agree that writing it in a function is rather pointless at that stage, which I suppose is your point. – Ian McLaird Feb 03 '14 at 19:10
0

@flavian's link answers the "why not" part, but here's how you do what you're trying to do. Make someFunction a function instead of a procedure.

var num = 1
def someFunction(num: Int) = num + 1
num = someFunction(num)

Note though that this isn't idiomatic scala. Avoid using vars whenever you can for best style.

Or alternatively for even worse style (seriously, this works, but don't ever do it):

var num = 1
def someFunction() = num += 1
someFunction()
print(num)
Ian McLaird
  • 5,507
  • 2
  • 22
  • 31