型はデータに意味を与える
型はバグ防止機構という以上にデータに意味付けを与えるものとしての役割が重要です。
その一つの例としてカーディナリティがあります。今回はこれを紹介していこうと思います。
普段から型を使っている人はおそらく暗黙裡にこのカーディナリティに注意しながら型付けを行っているんじゃないかと思います。
型によるカーディナリティの分類
筆者の趣味で Scala で表現していますが、好きな言語で読み替えてください。
型 | カーディナリティ | 補足 |
---|---|---|
A | 1 |
A は Int とか String を始めとする任意の型 |
Option[A] | 0..1 | 言語によっては A? , Nullable<A> , A | null に相当するもの1
|
List[A] | 0..n | 言語によっては A[] , Array<A> に相当するもの |
NonEmptyList[A] | 1..n | 大抵の言語には存在しませんがこういうのもあります |
よくあるミスと改善策
表に登場する型たちはデータのカーディナリティを表すので、それらをユニオン型で組み合わせた型は普通作りません。例えば以下のようなものです2。
A | Option[A]
A | List[A]
List[A] | Option[A]
クラスのフィールドの型が A | List[A]
になっているものをたまに見かけることがあります。もともと A
という型だったけど List[A]
の場合も扱いたくなって追加されたという具合のものだと思います。こういうケースでは次のことを考えて設計を見直してみるとよいでしょう。
- もともと
List[A]
とするべきだったのではないか -
A
の場合とList[A]
の場合では別々のフィールドに分けたほうがいいのではないか
型を単なるバグ防止機構と考えるとこのように型をいじってなんとかしようとしてしまうかもしれません。ですが型をデータに意味付けを与えるものだと意識すれば、こういった場合に設計を改善するヒントを得ることができるのです。
(そもそもむやみにユニオン型を使うべきではないというのがあると思います。)
まとめ
データのカーディナリティを表現する型を紹介しました。カーディナリティを意識することでよりよいコードを書いていきましょう。