Increment (++) operator in Scala
Asked Answered
P

9

68

Is there any reason for Scala not support the ++ operator to increment primitive types by default? For example, you can not write:

var i=0
i++

Thanks

Pressor answered 21/10, 2010 at 22:9 Comment(3)
just curious, can you issue i += 1 in Scala?Dilisio
Yeah, you can, but only if it's a var and not a val. When the Scala compiler finds a method ending in = invoked on a var and the class doesn't have that method (variable method= arg), it expands it to variable = variable.method(arg).Nonsuch
Here is the original text from <Programming in scala 3rd> 2016 : Note that Java's ++i and i++ don't work in Scala. To increment in Scala, you need to say either i = i + 1 or i += 1Badminton
T
42

My guess is this was omitted because it would only work for mutable variables, and it would not make sense for immutable values. Perhaps it was decided that the ++ operator doesn't scream assignment, so including it may lead to mistakes with regard to whether or not you are mutating the variable.

I feel that something like this is safe to do (on one line):

i++

but this would be a bad practice (in any language):

var x = i++

You don't want to mix assignment statements and side effects/mutation.

Tedmund answered 21/10, 2010 at 22:17 Comment(4)
I guess you're not a big fan of C/C++, then. All sorts of *(a++) = ++*(b++) stuff there....Grith
@Rex Kerr : now I feel good that my first programming language was Java :)Dilisio
I'm a C++ lead developer: There be none of that nonsense in my codebase if I can help it.Gallium
"You don't want to mix assignment statements and side effects/mutation." yes I do, lol I hate this languageBootless
Y
34

I like Craig's answer, but I think the point has to be more strongly made.

  1. There are no "primitives" -- if Int can do it, then so can a user-made Complex (for example).

  2. Basic usage of ++ would be like this:

    var x = 1 // or Complex(1, 0)

    x++

  3. How do you implement ++ in class Complex? Assuming that, like Int, the object is immutable, then the ++ method needs to return a new object, but that new object has to be assigned.

It would require a new language feature. For instance, let's say we create an assign keyword. The type signature would need to be changed as well, to indicate that ++ is not returning a Complex, but assigning it to whatever field is holding the present object. In Scala spirit of not intruding in the programmers namespace, let's say we do that by prefixing the type with @.

Then it could be like this:

case class Complex(real: Double = 0, imaginary: Double = 0) {
  def ++: @Complex = {
    assign copy(real = real + 1)
    // instead of return copy(real = real + 1)
}

The next problem is that postfix operators suck with Scala rules. For instance:

def inc(x: Int) = {
  x++
  x
}

Because of Scala rules, that is the same thing as:

def inc(x: Int) = { x ++ x }

Which wasn't the intent. Now, Scala privileges a flowing style: obj method param method param method param .... That mixes well C++/Java traditional syntax of object method parameter with functional programming concept of pipelining an input through multiple functions to get the end result. This style has been recently called "fluent interfaces" as well.

The problem is that, by privileging that style, it cripples postfix operators (and prefix ones, but Scala barely has them anyway). So, in the end, Scala would have to make big changes, and it would be able to measure up to the elegance of C/Java's increment and decrement operators anyway -- unless it really departed from the kind of thing it does support.

Yarmouth answered 22/10, 2010 at 12:28 Comment(0)
D
21

In Scala, ++ is a valid method, and no method implies assignment. Only = can do that.

A longer answer is that languages like C++ and Java treat ++ specially, and Scala treats = specially, and in an inconsistent way.

In Scala when you write i += 1 the compiler first looks for a method called += on the Int. It's not there so next it does it's magic on = and tries to compile the line as if it read i = i + 1. If you write i++ then Scala will call the method ++ on i and assign the result to... nothing. Because only = means assignment. You could write i ++= 1 but that kind of defeats the purpose.

The fact that Scala supports method names like += is already controversial and some people think it's operator overloading. They could have added special behavior for ++ but then it would no longer be a valid method name (like =) and it would be one more thing to remember.

Dave answered 22/10, 2010 at 3:17 Comment(0)
G
13

I think the reasoning in part is that +=1 is only one more character, and ++ is used pretty heavily in the collections code for concatenation. So it keeps the code cleaner.

Also, Scala encourages immutable variables, and ++ is intrinsically a mutating operation. If you require +=, at least you can force all your mutations to go through a common assignment procedure (e.g. def a_=).

Grith answered 21/10, 2010 at 22:20 Comment(1)
I agree - you don't need to use ++. I just discovered after 1.5 years of experience that this operator isn't available and it was only because I was trying to obfuscate something to annoy my peer.Cordon
F
2

The primary reason is that there is not the need in Scala, as in C. In C you are constantly:

for(i = 0, i < 10; i++)
{
  //Do stuff
}

C++ has added higher level methods for avoiding for explicit loops, but Scala has much gone further providing foreach, map, flatMap foldLeft etc. Even if you actually want to operate on a sequence of Integers rather than just cycling though a collection of non integer objects, you can use Scala range.

(1 to 5) map (_ * 3) //Vector(3, 6, 9, 12, 15)
(1 to 10 by 3) map (_ + 5)//Vector(6, 9, 12, 15)

Because the ++ operator is used by the collection library, I feel its better to avoid its use in non collection classes. I used to use ++ as a value returning method in my Util package package object as so:

implicit class RichInt2(n: Int)
{      
  def isOdd: Boolean = if (n % 2 == 1) true else false
  def isEven: Boolean = if (n % 2 == 0) true else false
  def ++ : Int = n + 1
  def -- : Int = n - 1     
}

But I removed it. Most of the times when I have used ++ or + 1 on an integer, I have later found a better way, which doesn't require it.

Frontward answered 30/10, 2012 at 20:18 Comment(0)
S
2

It is possible if you define you own class which can simulate the desired output however it may be a pain if you want to use normal "Int" methods as well since you would have to always use *()

import scala.language.postfixOps //otherwise it will throw warning when trying to do num++

/*
 * my custom int class which can do ++ and --
 */
class int(value: Int) {

  var mValue = value

  //Post-increment
  def ++(): int = {

    val toReturn = new int(mValue)
    mValue += 1
    return toReturn 
  }

  //Post-decrement
  def --(): int = {

    val toReturn = new int(mValue)
    mValue -= 1
    return toReturn 
  }

  //a readable toString
  override def toString(): String = {
      return mValue.toString
  }
}

//Pre-increment
def ++(n: int): int = {
  n.mValue += 1
  return n;
}

//Pre-decrement
def --(n: int): int = {
  n.mValue -= 1
  return n;
}

//Something to get normal Int
def *(n: int): Int = {
  return n.mValue
}

Some possible test cases

scala>var num = new int(4)
num: int = 4

scala>num++
res0: int = 4

scala>num
res1: int = 5 // it works although scala always makes new resources

scala>++(num) //parentheses are required
res2: int = 6

scala>num
res3: int = 6

scala>++(num)++ //complex function
res4: int = 7

scala>num
res5: int = 8

scala>*(num) + *(num) //testing operator_*
res6: Int = 16
Synchronize answered 17/11, 2016 at 2:12 Comment(0)
R
1

Of course you can have that in Scala, if you really want:

import scalaz._
import Scalaz._

case class IncLens[S,N](lens: Lens[S,N], num : Numeric[N]) { 
  def ++ = lens.mods(num.plus(_, num.one))
}

implicit def incLens[S,N:Numeric](lens: Lens[S,N]) =
  IncLens[S,N](lens, implicitly[Numeric[N]])

val i = Lens[Int,Int](identity, (x, y) => y)

val imperativeProgram = for {
  _ <- i := 0;
  _ <- i++;
  _ <- i++;
  x <- i++
} yield x

def runProgram = imperativeProgram ! 0

And here you go:

scala> runProgram
runProgram: Int = 3
Reader answered 23/12, 2010 at 17:30 Comment(1)
Beware: if you want to impress C or Java programmer, you need to try harder. In this sequence x value should be 2, not 3, as postfix ++ is postincrement. The challenge to impress this crowd is: can you implement both prefix and postfix forms to behave as expected on mutable Numerics? ;)Mosier
M
0

It isn't included because Scala developers thought it make the specification more complex while achieving only negligible benefits and because Scala doesn't have operators at all.

You could write your own one like this:

class PlusPlusInt(i: Int){
  def ++ = i+1
  }

implicit def int2PlusPlusInt(i: Int) = new PlusPlusInt(i)

val a = 5++
// a is 6

But I'm sure you will get into some trouble with precedence not working as you expect. Additionally if i++ would be added, people would ask for ++i too, which doesn't really fit into Scala's syntax.

Meggs answered 21/10, 2010 at 22:23 Comment(5)
I suppose you could add a ++: method to support prefix operators, like val a = ++:5. But I suppose that looks a little wierd.Nonsuch
Bad idea. This doesn't work the canonical way that i++ is supposed to work--i++ is supposed to be equivalent to { val temp = i; i += 1; temp }.Grith
I'm not saying it was a good idea either! In my humble opinion the language design of Scala is pretty perfect (****-ups like automatically converting integral numbers to floating point numbers excluded) and in practice using += is much more readable.Meggs
@Rex Kerr: But that’s only a minor problem. The main thing is you cannot do var a = 5; a++; assert(a == 6) because a itself does not actually change.Chicky
@Chicky - I thought my answer covered that. I guess it was too opaque because there was more than one thing wrong.Grith
T
0

Lets define a var:

var i = 0

++i is already short enough:

{i+=1;i}

Now i++ can look like this:

i(i+=1)

To use above syntax, define somewhere inside a package object, and then import:

class IntPostOp(val i: Int) { def apply(op: Unit) = { op; i } } 
implicit def int2IntPostOp(i: Int): IntPostOp = new IntPostOp(i)

Operators chaining is also possible:

i(i+=1)(i%=array.size)(i&=3)

The above example is similar to this Java (C++?) code:

i=(i=i++ %array.length)&3;

The style could depend, of course.

Tenderize answered 30/9, 2012 at 17:37 Comment(2)
This doesn't answer the question, nor does it offer a good style to use Scala. Please mention this in your answer.Bleak
Operator chaining seems a beautiful application of a Scala way, I think. If you'll be more accurate in specifying a possible pitfall, I will gladly update my answer.Tenderize

© 2022 - 2024 — McMap. All rights reserved.