from 「名前的型システムと構造的型システムの違い」加筆案 「名前的型システムと構造的型システムの違い」加筆案メモ

Dart: Currently, typedefs are restricted to function types. We expect this to change.

コーディングを支える技術で型の勉強をしてます」とTypeScriptの勉強会で言われて、確認してみたけどやっぱりstructualとnominalの違いの解説はなかった。加筆したい。

ブレスト 動的型付け言語に対する型ヒントの流れ 2014年の言語ランキングを後で調査

TypeScriptは2012年リリース 2019年

辞書によって事前にどういう属性があるか明確化しなくて良くなった ハッカーと画家

  • デッサンのための鉛筆 しかしundefinedの罠
  • "" + 1
    • 静的型付け言語「エラー」
    • Python 実行時エラー TypeError: cannot concatenate ‘str’ and ‘int’ objects
    • JavaScript “1”
  • {}["x"]
    • Python: KeyError
    • JavaScript: undefined
    • これは静的型付けとの差ではない、動的型付け(動的検査)の言語の中でJavaScriptが特にひどいってだけ 問題の箇所から発覚箇所が離れてしまう 社会からのニーズによって急激に拡大したjsでの実装 実行がクライアントサイドで起きる 事前に問題に気づくことにたいする強いニーズ
  • 2つのアプローチ

Python Type hints

リスコフの置換原則

  • 「サブタイプはスーパータイプの代わりに使って良い」

  • サブタイピングはサブクラス化ではない、の論文

    • Cook, W.R.; Hill, W.L.; Canning, P.S. (January 1990). “Inheritance is not subtyping”. Proceedings of the Seventeenth Annual ACM Symposium on Principles of Programming Languages. San Francisco, California: 125–135.
  • Javaは1995年リリースなので、この論文は出ていた

  • 型システム入門では「19.3 名前的型システムと構造的型システム」

    • 型の研究としてはStructualの方が主流だった、システムがシンプル
    • nominalは型が必ず名前を伴う
    • class Cat extends Animal { … }
      • Catという「名前のついた型」を作っている
      • Subtypeであるかどうかの検証が容易
    • 多分JavaなどでNominalが採用されたのは性能上の問題
      • 「Scalaは遅い」という風評
      • 後の研究でStructualでも高速に識別できる方法が生まれた
        • 型のハッシュを作る
      • この辺りのことが直接寄与したかどうか?
      • Scalaが生まれた2004年から15年立つのでマシンの性能も上がっただろう
        • (CPU性能よりもSSD化の方が大きいだろうか??)
        • コンパイル時間の改善がStructual Typingの言語の普及に寄与した?
  • Goのインターフェイスの話、書く場所がなかった

  • https://stackshare.io/stackups/dart-vs-typescript

    • TypeScriptが人気に見える
    • TIOBEではDart 0.5%, TypeScript 0.2%だったけどな
    • どちらも数が少なすぎてちょっとした状況で大小が逆転するって状況かなぁ
  • the more important idea is the separation of concept: data and behavior are two distinct concepts in Go, not conflated into a single notion of “class”.

  • https://en.wikipedia.org/wiki/Structural_type_systemに

  • C++ template functions exhibit structural typing on type arguments.

  • と書いてあるのだが、これって具体的にはどういう挙動のことだろう?

    • (moriyoshit)型パラメータに与えられた型のメンバに対する操作は、その型が何であれ構造が一致していればコンパイルが通るので、その旨かと

    • こういうこと? cpp
struct A{
  int i;
  int j;
};
 
struct B{
  int i;
  int k;
};
 
template<class T>
int get_i(T& x){
  return x.i;
};
 
int main(){
  A a;
  B b;
  get_i<A>(a);
  get_i<B>(b);
}
    - これStructural Typingなのか??与えられた型パラメータで特殊化したget_iの実装が2つ作られていて、それぞれが普通にコンパイルされているだけでは。
        - 普通のコンパイルにおいて"x.i"というコードはxがAでもBでも成功するけど、それをStructuralだ、と呼ぶのはどうなのか?
    - `get_i<T>`の部分だけに注目する。Tに入ることができる型かどうかは「メンバーiを持っている型」という「名前ではなく構造によって決まる」

cpp

struct A{
  int i;
  int j;
};
 
struct B{
  int i;
  int k;
};
 
struct C{
  int j;
  int k;
};
 
template<class T>
int get_i(){
  T x;
  return x.i;
};
 
int main(){
  get_i<A>();
  get_i<B>();
  //get_i<C>();  // error: no member named 'i' in 'C'
}
  • ジェネリクス(総称型)はJavaだと5.0で導入された。2004年のことである。

    • 名前的な言語には、このような「総称的」機能…の拡張を持つものがある。しかしそういう拡張を施したものは、もはや純粋な名前的型システムではなく、二つのアプローチの少々複雑なハイブリッドである。発展的な型機能を備える言語の設計者は、構造的なアプローチを選ぶ傾向がある。

    • C++にテンプレートが導入されたのはいつ?
    • その辺りでNominalな仕組みに徐々にStracturalな仕組みが混ざり込み初めて、もはや純粋なNominalではない、ということかと
  • Constraints and concepts (since C++20) - cppreference.com

  • (Javaは2004年にジェネリクス(総称型)の機能を採用した。これは名前的型だったJavaが構造的型とのハイブリッドに進む方向なのだが、それをページを割いて説明するかどうかは要検討)

    • 要するにJavaにおいて「名前が違う」「継承関係にない」ならそれは全然別の型だったわけだが、特にコンテナなどには「そのコンテナに入れて良い」の条件を異なる型T1とT2で共有してたわけだ。
      • 特定の特徴を持っているものならばコンテナに入れてよかった
      • この辺のことがわかってきた段階で、純粋なNominalでは色々問題があるなぁって気づいたと言うことだな
  • STLが1993年

  • function templates, class templates and, since C++14, variable templates. Since C++11