コンストラクター引数を元にオブジェクトの分解(deconstruction)

Proposal: Positional deconstruction based on existing constructors and properties #8415

パターン マッチングで、現在提案されている範囲では、is 演算子みたいな特殊なメソッドを1個追加してやらないと、o is Person("Alan", var last) みたいな感じのマッチングができません。

これだと、今後追加する型(特にレコード型)に対してなら使えるけども、既存の型には全く使えなくて困る。一方で、現状でも、以下のコードみたいに、コンストラクター引数とプロパティに1対1の関係があるようなクラスを書く人は多いわけで、この規約ベースでオブジェクトの分解をできないかという提案。

public class Person
{
  public Person(string firstName, string lastName) 
  { 
    FirstName = firstName; 
    LastName = lastName; 
  }
  public string FirstName { get; }
  public string LastName { get; }
}

確か自分もこのパターンでクラスを書いていることが多いんで、にこの機能が入れば、それらを1個1個レコード型に置き換えたりしなくてもパターン マッチングが使えて大変便利。

でも、引数のfirstNameとプロパティのFirstNameの対応関係を規約ベースでやるのは、C#の文化(規約を嫌う、識別子は大文字小文字を区別する)的には合わないんで悩ましい感じ。ついてるコメントも賛否両論です。

Swift 2.0

Swift 2.0でdeferとguardが入ったわけですが、先月、それはC#には適するかどうか、議論用のissueページが立ちました。

ついてるコメントからすると、賛否は半々くらいか、ちょっと否定が多いくらいかなぁ。個人的な予想では、採用されない気がする。

defer

try { 処理 } finally { 後始末 } の代わりに defer { 後始末 } 処理 と書くような構文。

    {
        SomeType thing = Whatever...;
        defer {
            thing.Free();
        }
        // some code code using thing
    }

メリットは以下のような感じ。

  • using 相当の機能を、IDisposable 実装していなくてもできる
  • try-finally と比べて、「処理」の部分がネスト深くならない
  • try句内と、finally句内の両方で使いたい変数をわざわざその外側で宣言する必要がない

ただ、以下のような問題も。

  • defer が複数並んでるとき、その実行順はどうすべき?
  • try-finally でできることに対してわざわざ新構文増やすの?
  • 1回り外側のブロックに対して影響を与えるような構文ってなかなか理解されにくい

guard

if (絶対満たすべき条件) ; else throw 例外; みたいなよくあるパターンに対して使う構文。絶対満たすべき条件だし、満たしてなかったら必ず例外を投げる(そこから先を絶対に実行しない)ことを保証するために、if じゃなくて guard を使おうというもの。

まあ、そういうものがほしいこともあるというのはわかるものの、コントラクトと被ってるし、そもそもguardの必要性を減らせそう(コンパイル時にチェック可能で、実行時に例外投げる必要がない)な構文もこれから増えるだろうし。