今回はKotlinやJava、そしてPythonの変数宣言を使って、静的型付け言語と動的型付け言語の違いや、Kotlinの便利な機能である「型推論」についてお話していこうと思います。
動的型付け言語と静的型付け言語の違い
PythonやJavaScriptは動的型付け言語、JavaやKotlinは静的型付け言語に分類されますが、これらは果たして何が違うのでしょうか?
動的型付け言語
はじめに動的型付けの特徴を見てみましょう。
こちらはPython。動的型付け言語では、下のようなコードが普通に許されます。
# 変数に整数を代入
x = 10
print(x)
# 同じ変数に文字列を代入し直す
x = "Minecraft"
print(x)
# 10
# Minecraft
xという変数に数値の10を入れた後、”Minecraft”という文字列を入れ直しています。変数の型が自動的に変化する動的型付け言語ではいたって当然の処理ですが、では静的型付け言語ではどうでしょう?
静的型付け言語
JavaやKotlinで上と同じことをしようとすると、
fun main() {
var num = 10
num = "Minecraft"
}
//エラー: Type mismatch: inferred type is String but Int was expected
結果はエラーです。
一度Int型として宣言された変数はその後、(基本的には)Int型の値しか受け付けられず、全く違う種類の型であるString型の値を代入しようとするとエラーが起こります。
これはJavaもまったく同じ。変数の型が自動的に変化しないのが静的型付け言語です。
型推論とは何か?
古いJavaとKotlinの違い
では同じ静的型付け言語である、JavaとKotlinの違いは何でしょうか? まずは10以前の、古いJavaのコードから。
public class Main {
public static void main(String[] args) {
int num = 10;
final String game = "Minecraft";
System.out.println(game + "は" + num + "周年");
}
}
//Minecraftは10周年
続いてKotlin。
fun main() {
var num = 10
val game = "Minecraft"
println("${game}は${num}周年")
}
//Minecraftは10周年
上記のように以前のJavaでは変数宣言する場合、まず変数の型を決めてから値を代入しています(これを「明示的な型指定」と呼びます)が、Kotlinのコードではそれが見当たりません。
明示的な型指定が不必要な理由
静的型付け言語のはずのKotlinで、なぜ型指定しなくてもコードが成立するのか。それはKotlinが「型推論」の機能を持った言語だからです。
上の例で変数numに代入される値10は、どう見ても整数です。この場合、例え値がByte型やShort型で表せる数値であっても、Kotlinは自動的に、より一般的なInt型と判断して変数の型を決定します。
Kotlin >「10って普通の整数だよね。じゃとりあえず変数numの型はIntでいいんじゃない?」
コンパイラは代入される値から、「とりあえず一般的に見てこれだろう」と推論して、自動的に変数の型を決定します。この働きが型推論です。
型推論はあくまで推論
ただKotlinによる型推論は絶対的なものではなく、開発者側の都合で変更することが可能になっています。
例えば「この変数はそこまで大きな数値が入っては困る」という場合、型を明示的に指定しましょう。
「Short」とその下の「String」では色が変わっているのが分かると思います。
変数gameがString型であるのは当然であり、当たり前です。そのためIntelliJには「冗長である (ムダに長い)」と判断され、色がグレーになっています。
一方で上のShortは黄色。通常の整数をInt型ではなくShort型として宣言したい場合、明示的に指定するのが妥当だからです。
補足: 現在のJavaでは型推論が使える
この型推論、Javaでも10以降では型推論が導入されているので、現在は普通に使うことができます。
var num = 10;
final var game = "Minecraft";
動的型付け言語は型推論している?
ここでありがちなのが「動的型付け言語は、型推論をしているから型指定が不要」という考えですが、これは全くの誤解です。
JavaScript、Pythonなどの動的型付け言語は型推論しているわけではなく、そもそも型のチェックなどしていません。
動的型付け言語は基本的に「来るもの拒まず」で、何の型であってもとりあえず変数に代入できてしまうというだけです。
なのでもし、おかしな型が入っていれば「実行時」にエラーが出ます。
静的型付け言語の場合、この実行時エラーを極力減らすために、コードを書く時点で型のチェックを行うため、型のエラーはコンパイル時エラーとして補足されます。
実行時エラーを起こさないということは、大規模なプロジェクトになればなるほど大事になってきます。逆に小規模な開発の場合、いちいち型指定するのはそれこそ冗長である場合も多いでしょう。
大規模開発に向いた言語に静的型付けが多く、小規模開発に向いたスクリプト言語に動的型付けが多いというのも、納得出来るのではないでしょうか。
まとめ
最後に今回のお話のポイントをまとめておきます。
- 静的型付け言語は型を強く意識する言語
- 静的型付け言語の変数の型は、一度決まれば自動的に変化しない
- KotlinはJavaと同じ静的型付け言語である
- Kotlinは型推論を持ち、推論できる型であれば明示的な型指定が不要
- 動的型付け言語は型推論をしているわけではない