はじめに
オブジェクト指向言語を対象に、型に関する情報をまとめてみました。
誤り、改善箇所がありましたらコメントいただけますと幸いです。
公開当時(2020/12)の情報を基に書いています。
比較表
言語名 | 登場年 | ①検査タイミング | ②指定方法 | ③互換性の確認方法 |
---|---|---|---|---|
Smalltalk | 1980 | 動的 | 暗黙的 | ダックタイプ的 |
Ada | 1983 | 静的 | 明示的 | 名前的 |
C++ | 1983 | 静的 ときどき動的 |
明示的 ときどき暗黙的 |
名前的 ときどき構造的 |
Objective-C | 1984 | 静的 ときどき動的 |
明示的 ときどき暗黙的 |
名前的 ときどきダックタイプ的 |
Eiffel | 1985 | 静的 | 明示的 | 名前的 |
Object Pascal | 1986 | 静的 | 明示的 | 名前的 |
Perl | 1987 | 動的 | 暗黙的 | ダックタイプ的 |
Python | 1990 | 動的 | 暗黙的 ときどき明示的 |
ダックタイプ的 ときどき名前的 |
Lua | 1993 | 動的 | 暗黙的 | ダックタイプ的 |
Java | 1995 | 静的 | 明示的 ときどき暗黙的 |
名前的 |
PHP | 1995 | 動的 | 暗黙的 ときどき明示的 |
ダックタイプ的 ときどき名前的 |
JavaScript | 1995 | 動的 | 暗黙的 | ダックタイプ的 |
Ruby | 1995 | 動的 | 暗黙的 | ダックタイプ的 |
C# | 2000 | 静的 ときどき動的 |
明示的 ときどき暗黙的 |
名前的 ときどきダックタイプ的 |
Visual Basic .NET | 2001 | 静的 ときどき動的 |
明示的 ときどき暗黙的 |
名前的 ときどきダックタイプ的 |
Scala | 2003 | 静的 | 明示的 ときどき暗黙的 |
名前的 ときどき構造的 |
D | 2007 | 静的 ときどき動的 |
明示的 ときどき暗黙的 |
名前的 ときどき構造的 |
Go | 2009 | 静的 | 明示的 ときどき暗黙的 |
構造的 ときどき名前的 ときどきダックタイプ的 |
Rust | 2010 | 静的 | 明示的 ときどき暗黙的 |
名前的 |
Kotlin | 2011 | 静的 | 明示的 ときどき暗黙的 |
名前的 |
Dart | 2011 | 静的 ときどき動的 |
明示的 ときどき暗黙的 |
名前的 |
TypeScript | 2012 | 静的 ときどき動的 |
明示的 ときどき暗黙的 |
構造的 |
Swift | 2014 | 静的 | 明示的 ときどき暗黙的 |
名前的 ときどき構造的 |
①検査タイミング
📝 分類
ⅰ. 静的な検査 static checking
実行前に検査する方式。
ⅱ. 動的な検査 dynamic checking
実行時に検査する方式。
🔦 特徴的なケース
ケース1. オブジェクトだけ実行時に検査する
該当:Objective-C
Objective-Cはコンパイル型言語なのですが、オブジェクトの型だけは実行時に決定します。
ケース2. コンパイル時に決まらない分は実行時に検査する
該当:Dart, TypeScript
静的な検査で型が決まらなくてもエラーにせず、実行時の検査で問題があればそのタイミングでエラーとしています。
②指定方法
📝 分類
ⅰ. 明示的な指定 explicit specification
プログラムの要素に対して特定の型を指定する様に記述する方式。
// int型を明示している
int number = 123;
ⅱ. 暗黙的な指定 implicit specification
明示的な指定の反対。特定の型を指定しない方式。
# 型を明示しない
number = 123
🔦 特徴的なケース
大まかには下記の傾向があります。
- 検査が静的なら明示的な指定をする
- 検査が動的なら暗黙的な指定をする
が、そう単純でないケースも有ったので紹介します。
ケース1. 検査は静的だが型推論で一部の指定を省略できる
該当する言語:C++, Java, C#, Scala, D, Go, Rust, Kotlin, Dart, TypeScript, Swift
// 型の指定は無いが、123を代入してるのでintと決定する
val x = 123
ケース2. 通常時の検査は静的だが、専用の構文で指定を省略すると検査が動的になる
該当する言語:C++, C#
// 型の指定は無いが、実行時に動的に決定する
dynamic number = someNumber;
ケース3. 検査は動的だが明示的な指定ができる
該当する言語:Python, PHP
// 型の指定に基づき、代入可能か実行時に検査する
public int $number = 123;
ケース4. 明示的な指定を強制するか選べる
該当する言語:Visual Basic .NET
Option Strict On ' 明示的な指定を強制する設定
' 中略
Dim number As Integer = 123
③互換性の確認方法
📝 分類
ⅰ. 名前的な互換性 nominal compatibility
名前によって決める方式。
// User型が期待されている。右辺も同じくUser型だから代入可能
User user = new User();
ⅱ. 構造的な互換性 structural compatibility
静的な検査時の構造によって決める方式。
interface User { name(): string; }
// Userと同じ構造が期待されている。右辺が `name(): string` をもつから代入可能
const user: User = { name: () => "山田太郎"; }
ⅲ. ダックタイプ的な互換性 duck type compatibility
動的な検査時1の構造によって決める方式。
🔦 特徴的なケース
ケース1. 通常は「名前的」だが、テンプレートを使うと「構造的」になる
該当:C++, D
通常時は「名前的」ですが
次の様にテンプレートを使うと「構造的」になります。
// 引数には`std::string name()`の構造が期待されている
template<class T> std::string user_name(T user) {
return user.name();
}
ケース2. 通常は「構造的」だが、比較対象同士の型が名前をもつなら「名前的」にもなる
該当:Go
// `Name() string`の構造が期待されている
var user interface { Name() string }
// Userと同じ構造が期待されている
// ただし、同じ構造でもUser以外の名前の型なら代入できない(匿名なら代入可)
var user User
ケース3. 対象の型に応じて異なる方式を使い分ける
該当:Swift
Swiftでは
- 関数とタプルだけ「構造的」
- 他は「名前的」
このように方式を使い分けています。
参考文献
Pierce, B. C., & C., B. (2002). Types and programming languages. MIT Press.
バートランド・メイヤー. (2008). オブジェクト指向入門: 方法論・実践.
増井敏克. (2017). プログラミング言語図鑑: プログラミング言語の現在・過去・未来...知ればもっと楽しめる!
Comparison of programming languages by type system. (2016, May 22). - Wikipedia. Retrieved December 24, 2020, from https://en.m.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system
Type system. (2003, March 22). - Wikipedia. Retrieved December 24, 2020, from https://en.m.wikipedia.org/wiki/Type_system
なぜGoはDuck typingを採用していると言えるのか、データ構造から詳しく解説してみた. (2020, January 26). Qiita. Retrieved December 24, 2020, from https://qiita.com/ttiger55/items/ecf6765847faacf9a60b
-
ダックタイプ(ダックタイピング)という語は、「動的な検査時」に限定しない意味で使うことも有る様です。が、曖昧さの無い他の言葉が見つからなかったので、採用しました。 ↩