Kotlin の後置・前置インクリメントと演算子オーバーロード (C, Java, C++ との比較)

## 概要

- a++ のような後置インクリメント演算子: 値が関数に渡された後にインクリメントされる
- ++b のような前置インクリメント演算子: 値が関数に渡される前にインクリメントされる

[インクリメント \- Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88)

> C言語、C++、Java、JavaScriptなどでは、インクリメント演算子(増量子)「++」が用意されている。前置インクリメントと後置インクリメントの2種類がある。字句は同じ「++」だが前置演算子として使うか（例: ++x）後置演算子として使うか（例: x++）で意味が違う。オペランドの値が整数の場合は1、ポインタの場合は指し示す対象1個ぶん変わるのはどちらも同じだが、式としての値が、前置の場合はインクリメントした後の値になる（この意味は += 1 と同じ）、後置の場合はインクリメントする前の値になる。

## 環境

- kotlinc-jvm 1.3.10 (JRE 11.0.1+13-LTS)

## Kotlin で後置・前置インクリメント

Kotlin のソースコード。

```kotlin
var a = 1
var b = 1
println(a++)
println(++b)
```

実行結果。
a++ の場合、値が +1 される前に関数に渡されるため 1 が出力される。
++b の場合、値が +1 された後に関数に渡されるため 2 が出力される。

```
$ kotlinc -script hello.kts
1
2
```

Kotlin のインクリメント演算子は C や Java と同様の挙動をしている。

C のソースコード。

```c
#include <stdio.h>

int main(int argc, char *args[]) {
  int a = 1;
  int b = 1;
  printf("%d\n", a++);
  printf("%d\n", ++b);
  return 0;
}
```

実行結果。

```
$ gcc hello.c -o hello

$ ./hello 
1
2
```

Java のソースコード。

```java
public class Hello {
  public static void main(String[] args) {
    int a = 1;
    int b = 1;
    System.out.println(a++);
    System.out.println(++b);
  }
}
```

実行結果。

```
$ javac Hello.java 

$ java Hello
1
2
```

## Kotlin で演算子オーバーロードしてインクリメント

Kotlin のインクリメント演算子オーバーロードは手軽に書ける。
operator fun inc でインクリメント演算子をオーバーロードできる。

```kotlin
data class Counter(val num: Int) {
  operator fun inc(): Counter {
    return Counter(num + 1)
  }
}

var a = Counter(1) 
var b = Counter(1)
println(a++)
println(++b)
```

実行結果。
a++ の場合、num の値が +1 される前に関数に渡されるため、num=1 の状態が出力される。
++b の場合、num の値が +1 された後に関数に渡されるため、num=2 の状態が出力される。

```
$ kotlinc -script counter.kts
Counter(num=1)
Counter(num=2)
```

同じようなインクリメント演算子の挙動を C++ で書いてみる。
C++ では後置と前置で別の関数を書く必要がある。

```c++
#include <iostream>

class Counter {

private:
  int num;

public:
  Counter(int num) : num(num) {}

  // Prefix increment operator
  Counter& operator ++() {
    this->num++;
    return *this;
  }

  // Postfix increment operator
  Counter operator ++(int) {
    Counter c = *this;
    this->num++;
    return c;
  }

  friend std::ostream& operator<<(std::ostream& os, const Counter& c) {
    os << c.num;
    return os;
  }
};

int main(int argc, char *argv[]) {
  Counter a(1);
  Counter b(1);
  std::cout << a++ << std::endl;
  std::cout << ++b << std::endl;
  return 0;
}
```

実行結果。

```
$ g++ hello.cpp -o hellocpp
$ ./hellocpp 
1
2
```

## 参考資料

- [Operator overloading \- Kotlin Programming Language](https://kotlinlang.org/docs/reference/operator-overloading.html)
- [後置インクリメント演算子と後置デクリメント演算子: \+\+ および \-\- \| Microsoft Docs](https://docs.microsoft.com/ja-jp/cpp/cpp/postfix-increment-and-decrement-operators-increment-and-decrement?view=vs-2019)
- [Prefix Increment and Decrement Operators: \+\+ and \-\- \| Microsoft Docs](https://docs.microsoft.com/en-us/cpp/cpp/prefix-increment-and-decrement-operators-increment-and-decrement?view=vs-2019)
- [前置インクリメント演算子と前置デクリメント演算子: \+\+ および \-\- \| Microsoft Docs](https://docs.microsoft.com/ja-jp/cpp/cpp/prefix-increment-and-decrement-operators-increment-and-decrement?view=vs-2019)
- [Increment and Decrement Operator Overloading \(C\+\+\) \| Microsoft Docs](https://docs.microsoft.com/id-id/cpp/cpp/increment-and-decrement-operator-overloading-cpp?view=vs-2017)
- [インクリメント演算子とデクリメント演算子のオーバーロード \(C\+\+\) \| Microsoft Docs](https://docs.microsoft.com/ja-jp/cpp/cpp/increment-and-decrement-operator-overloading-cpp?view=vs-2019)