C# 使いが Kotlin を使ってみて「いいな」と思ったトコ

最近 Kotlin をよく使っているので、 C# とくらべて「お、これはイイな！」と思ったところを挙げてみました、今後足してく予定。

これ↓も似たような話かな。

* [C# + ReactiveProperty vs Kotlin + RxProperty : Command 編 - Qiita](https://qiita.com/amay077/items/37e1032f2a8f30138284)

## データクラス

C#

```csharp
public class AddressCard 
{
  public string Name { get; }
  public string Phone { get; }
  
  public AddressCard(string name, string phone)
  {
    this.Name = name;
    this.Phone = phone;
  }
}
```

Kotlin

```kotlin
data class AddressCard(val name:String, val phone:String)

fun main() {
   val card = AddressCard("name", "phone")
   val copied = card.copy(name = "hoge") // 指定したプロパティだけ値を変えて複製してくれる
}
```

圧倒的短さ！ & ``copy`` メソッドなにこれすごい！
Json のモデルクラスを作る時にはほんと便利。

## 型定義の省略

C#

```csharp
public class AddressCard 
{
  public ObservableField<string> Name { get; } = new ObservableField<string>("");
  public IDictionary<string, string> Map { get; } = new Dictionary<string, string>();
}
```

Kotlin

```kotlin
class AddressCard {
  val name = ObservableField<String>("")
  val map = HashMap<String, String>() // これは悪手。public ならちゃんと map:Map<String, String> と基本抽象型にすべき
}
```

圧倒的短さ！
これが型を後ろに書く言語の強みなのか？？？

## コンストラクタ引数をメンバ変数に入れるやつ

C#

```csharp
public class AddressCard 
{
  public readonly string _name;
  public readonly string _phone;
  
  public AddressCard(string name, string phone)
  {
    _name = name;
    _phone = phone;
  }

  public string ToFullName() = $"{_name}:{_phone}";
}
```

Kotlin

```kotlin
class AddressCard(
  private val name:String, 
  private val phone:String) {
  
  fun toFullName() = "${name}:{phone}"
}
```

代入の必要ナシ！
そもそもプライマリコンストラクタの引数はそのままプロパティになる模様（``val`` を付けない場合はイニシャライザ ``init {}`` の中でのみ参照可能な変数になるとのことです、コメントで教えていただきました）。

## 読み取り専用かどうか

C#

```csharp
public class AddressCard 
{
  public string Name { get; } // 読み取り専用プロパティ
  public string Phone { get; set; } // 書き込み可プロパティ

  private readonly string _fullName; // 読み取り専用フィールド
  
  public AddressCard(string name, string phone)
  {
    this.Name = name;
    this.Phone = phone;
    _fullName = $"{_name}:{_phone}"
  }
}
```

Kotlin

```kotlin
class AddressCard {

  val name:String   // 読み取り専用プロパティ
  var phone:String  // 書き込み可プロパティ

  private val _fullName:String // 非公開読み取り専用プロパティ

  constructor(name:String, phone:String) { // 敢えてのコンストラクタ
    this.name = name
    this.phone = phone
    _fullName = "${name}:{phone}"
  }
}
```

いかなるケースでも ``val`` と ``var`` の使い分けだけで済むのがイイ！

## クラスでも ``null`` を排除できる

C#

```csharp
class HogeClass {  }
struct HogeStruct {  }

void Main()
{
   HogeClass hogeClass = null; // null にできる   
   HogeStruct hogeStruct = null; // null にできない
   HogeStruct? nullableHoge = null; // null にできる
   int? num = null; // null にできる
   
   // null条件/合体演算子
   Console.WriteLine(hogeClass?.ToString() ?? "empty");
   Console.WriteLine(num?.ToString() ?? "empty");
}
```

Kotlin

```kotlin
class HogeClass {  }

fun main()
{
   val hogeClass:HogeClass = null; // null にできない
   val nullableHoge:HogeClass? = null; // null にできる
   val num:Int? = null; // null にできる
   
   // null条件/合体演算子
   System.out.println(nullableHoge?.ToString() ?: "empty");
   System.out.println(num?.ToString() ?: "empty");
}
```

末端関数において、 ``null`` になる可能性を排除して実装できる安心感パない。
(C# でも構造体を多用すればできるけど、目的が違うし実質ムリ)

## "使用しない引数" を明示できる

C#

```csharp
button.Clicked += (_, __) =>  // _ は２度使えない
{
    var hoge1 = _.ToString();  // 変数名が _ なだけ
    var hoge2 = __.ToString(); // 変数名が __ なだけ
};
```

Kotlin

```kotlin
button.setOnHoverListener({ _, _ ->  // _ は何度でも使える！
    val hoge1 = _.toString() // エラー
    val hoge2 = _.toString() // エラー
    true
})
```

主にイベントリスナーで、ラムダ式の「引数を使わない」ことを示すために、 C# では「引数名を ``_`` にする」という文化があります。
が、あくまで文化でしかないので、変数 ``_`` が存在しているだけであり、引数が２個あったら両者に ``_`` は使えないし、関数内で ``_`` は変数として普通に使えてしまいます。

一方で Kotlin の ``_`` は「使用しない変数名」として特別視されており?、複数の引数に割り当てられるし、関数内で ``_`` を使うとエラーにしてくれます。

C# でラムダ式をネストせざるを得ないときに、まあまあな頻度で ``_`` を複数回使いたいなーと感じることがあるので、Kotlin の ``_`` は便利だなー、と思います。


## 逆に Kotlin の「これは個人的には好かん」ところ

### デフォルトで public

API設計は、慎重派なんですよ。
気持ちよさにかまけて非公開とすべきAPIに private を付け忘れそう。

### Smart cast

```kotlin
fun doWork(card:AddressCard?) {
  val name = card.name  // nullableだからエラー
  if (card != null) { // null をチェックすれば…
    val name2 = card.name  // 大丈夫だ、nullの可能性は無い
  }
}
```

まあ便利で使いもするんだけど、 ``card?.let{ }`` で代用できるし(これも Smart Cast だとコメントで教えてもらいました)。

C# でも ``Nullable<T>`` なら 「スコープ内は null でないことを保証できる」 ``Let`` 拡張関数が書けるので、参考までに載せときます。

```csharp
public static R? Let<T, R>(this T? self, Func<T, R?> mapper) where T : struct where R : struct 
    => self.HasValue ? mapper.Invoke(self.Value) : (R?)null;

int? num = 3;
int ret1 = num?.Let((int nonNullNum) => nonNullNum * 2) ?? -1; // -> 6

num = null;
int ret2 = num?.Let((int nonNullNum) => nonNullNum * 2) ?? -1; // -> -1
```

### Non-local return

```kotlin
fun upperJoin(name:String, zip:String) : String {
    val nameUpper = name.let { x->
        if (x == "") {
            return ""      // upperJoin を抜けちゃう！
//          return@let ""  // この let {} スコープを抜けるだけ
        }
        return x.toUpperCase()
    }

    val zipUpper = zip.let { it.toUpperCase() }
    return "$nameUpper:$zipUpper"
}
```

上のコードは ``name`` が空文字の場合、``zip`` を無視して空文字を返してしまいます。
いつかハマりそうで、オドオドしてます。

Smart-cast も Non-local return も、自分が知ってる言語にない機構に拒否反応を示してるだけですね。慣れたらガンガン使いそうです。

C# にしかない機能や、これから新たに追加される機能もあると思いますが、あくまで自分が使用する範囲で感じたこと、ということで。

C# の方ももちろん進化は続いていて、

* [Introducing Nullable Reference Types in C# | .NET Blog](https://blogs.msdn.microsoft.com/dotnet/2017/11/15/nullable-reference-types-in-csharp/)

に代表されるように、モダンと呼ばれる仕様も次々と取り込まれていく雰囲気が好きです。