「名前的型システムと構造的型システムの違い」加筆案メモ
「名前的型システムと構造的型システムの違い」加筆案メモ
Dart: Currently, typedefs are restricted to function types. We expect this to change.
「コーディングを支える技術で型の勉強をしてます」とTypeScriptの勉強会で言われて、確認してみたけどやっぱりstructualとnominalの違いの解説はなかった。加筆したい。 ブレスト
動的型付け言語に対する型ヒントの流れ
2014年の言語ランキングを後で調査
Java 14% C++ 5% C# 4%
Python 3% JavaScript 2% Ruby 1%
Scala 0.4% Haskell 0.3%
scalaの話
scala twitter
2019
Java 15% C++ 9% C# 4%
Python 8% JavaScript 3% Ruby 1%
Scala 0.4% TypeScript 0.2% Haskell 0.2%
TypeScriptは2012年リリース
2019年
辞書によって事前にどういう属性があるか明確化しなくて良くなった
ハッカーと画家
デッサンのための鉛筆
しかしundefinedの罠
"" + 1
静的型付け言語「エラー」
Python 実行時エラー TypeError: cannot concatenate 'str' and 'int' objects
JavaScript "1"
{}["x"]
Python: KeyError
JavaScript: undefined
これは静的型付けとの差ではない、動的型付け(動的検査)の言語の中でJavaScriptが特にひどいってだけ
問題の箇所から発覚箇所が離れてしまう
社会からのニーズによって急激に拡大したjsでの実装
実行がクライアントサイドで起きる
事前に問題に気づくことにたいする強いニーズ
2つのアプローチ
Closure Compiler
JavaScriptの文法に従ったまま静的チェック
JavaDoc形式で型アノテーションを付与する
事例
2012
サイボウズkintoneは2012年時点でJavaScriptのコードが10万行あった
2015
サイボウズkintoneは2015年時点でJavaScriptのコードが30万行あった
AltJS
別の言語で開発し、JavaScriptに変換
たくさんの言語が誕生した
TypeScriptもこの一つ
2015年の段階ではすでにTypeScript一強
https://gyazo.com/d057a2390e793eefeb1211c3196e8bf8
2015年の2月ごろに逆転してる
ちなみに日本人が作ったJSXというものもあるが、2019年現在ではJavaScript XMLの略としてのJSXに覆い隠されて検索困難になってしまっている プロジェクトページの著作権表示が2013年で止まっている
Copyright © 2012, 2013 DeNA Co., Ltd. et al.
Python Type hints
Version3.5でライブラリとして提供された
2015年リリース
リスコフの置換原則
「サブタイプはスーパータイプの代わりに使って良い」
サブタイピングはサブクラス化ではない、の論文
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年リリースなので、この論文は出ていた
型の研究としてはStructualの方が主流だった、システムがシンプル
nominalは型が必ず名前を伴う
class Cat extends Animal { ... }
Catという「名前のついた型」を作っている
Subtypeであるかどうかの検証が容易
多分JavaなどでNominalが採用されたのは性能上の問題
「Scalaは遅い」という風評
後の研究でStructualでも高速に識別できる方法が生まれた
型のハッシュを作る
この辺りのことが直接寄与したかどうか?
Scalaが生まれた2004年から15年立つのでマシンの性能も上がっただろう
(CPU性能よりもSSD化の方が大きいだろうか??)
コンパイル時間の改善がStructual Typingの言語の普及に寄与した?
Goのインターフェイスの話、書く場所がなかった
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”.
Goの作者
C++ template functions exhibit structural typing on type arguments.
と書いてあるのだが、これって具体的にはどういう挙動のことだろう?
(moriyoshit)型パラメータに与えられた型のメンバに対する操作は、その型が何であれ構造が一致していればコンパイルが通るので、その旨かと こういうこと?
code: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を持っている型」という「名前ではなく構造によって決まる」
code: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
型に対してpredicateを定義でき、それがコンパイルタイムに検査される
(Javaは2004年にジェネリクス(総称型)の機能を採用した。これは名前的型だったJavaが構造的型とのハイブリッドに進む方向なのだが、それをページを割いて説明するかどうかは要検討)
要するにJavaにおいて「名前が違う」「継承関係にない」ならそれは全然別の型だったわけだが、特にコンテナなどには「そのコンテナに入れて良い」の条件を異なる型T1とT2で共有してたわけだ。
特定の特徴を持っているものならばコンテナに入れてよかった
この辺のことがわかってきた段階で、純粋なNominalでは色々問題があるなぁって気づいたと言うことだな
STLが1993年
function templates, class templates and, since C++14, variable templates. Since C++11
あれ?と言うことは初期のSTLはテンプレートを使わずに実現されてたのか?
1996年のSTL解説でもテンプレートが普通に使われているなぁ
つまり、仕様に入ったのが遅いだけで、個々のコンパイラは実装していたと言うことか?
1990
1990: The Annotated C++ Reference Manual
This book described the language as designed, including some features that were not yet implemented. It served as the de-facto standard until the ISO.
New features: namespaces, exception handling, nested classes, templates
というわけで1990にはデファクトになってた、と。
C++11で入ったのは可変長のテンプレートであって、固定長のものは前からあったのだ