Page 1
型なき言語に付ける型
Type in untyped languages
#virtual_study_groupバーチャル空間勉強会#0
公開日:
by USAMI Kenta@tadsan
にClusterのバーチャル空間で開催された『バーチャル空間勉強会#0』でライトニングトーク(5分)として発表しました。
Type in untyped languages
#virtual_study_groupバーチャル空間勉強会#0
近況
話しました
仕方がないので全然違う話をします
本日のお題
型、ついてますか?
型については結構雑な印象で見解を語るひとが多い
俺も俺も
型があるから変更に強いというひとも居れば、型がないから変更に強いというひとも居る
???
型よくわからん
私もだ
intとboolとかでしょ
読むがよい
‒Benjamin C. Pierce 著/住井英二郎 監訳/遠藤侑介・酒井政裕・今井敬吾・黒木裕介・今井宜洋・才川隆文・今井健男 訳 『型システム入門 プログラミング言語と型の理論』(オーム社、978-4-274-06911-6、2013年)サンプル
‒Benjamin C. Pierce 著/住井英二郎 監訳/遠藤侑介・酒井政裕・今井敬吾・黒木裕介・今井宜洋・才川隆文・今井健男 訳 『型システム入門 プログラミング言語と型の理論』(オーム社、978-4-274-06911-6、2013年)サンプル
(一章はサンプルとしてPDFが無料でダウンロードできます)
正しい、完璧に正しいのだが
最初から用語多すぎ
説明の抽象度が高すぎて現実とのギャップ大きすぎ
この1章の内容を解きほぐして説明するだけで何時間も話せそう
そのほかの型とかプログラミング言語論の本を読むと数式みたいなのが出てきてワケワカラン
型についてちょっと知りたいだけなのに
世の中の人と型
型を使っているが思索の対象として向き合ってないひと
特定の言語の型とだけ向き合ってる人
抽象概念の型と向き合ってるひと
いろんな背景の人が居る
動的言語を使っていると静的型付き言語利用者から冷ややかに見られがち
やーい型なし型なし
型はあるんだ!実行時にあるんだ!
そういうことをまじめに主張すると憐れみを湛えた目で見られはじめる
真の型なし言語も複数あるが今回は割愛しました
型わかりたくないですか
このトークに結論はない
実際の言語の型からいきましょう
C言語
#include <stdio.h>
long add(long a, long b) {return a + b;}
int main(void) {unsigned int x = 1, y = 2;
printf("%d + %d = %d\n", x, y, add(x, y));}
私たちFラン情報科学生は情弱なのでまともな説明もないカビの生えた教科書でC言語を叩き込まれる
私の入門者時代のC言語理解は曖昧なので曖昧なままで次の話に進めます
さておき
// JavaScript
function add(a, b) {return a + b;}
const x = 1, y = 2;
console.log(`${x} + ${y} + ${add(x, y)}`);
# Ruby
def add(a, b)a + b end
x = 1; y = 2
puts "#{x} + #{y} + #{add x, y}"
そういう俺たちが動的言語に触れるとこうなる
型とか要らんやろw
そうだな
# Ruby
# to_sオブジェクトが生えてたら何でもいい
def show(obj)puts obj.to_s end
# Ruby
# 足し算できるものならなんでもいいし
# ジェネリクスとかなくてもいいw
def add(a, b)a + b end
def show(obj)puts obj.to_s end
# Ruby
user = User.findBy(id: params[:user_id])
# Ruby
obj = palpunte(user_id,????,????,????,)
p obj
実装を直接見に行く機会が増える
# Ruby
# 実装を見ないと期待するオプションに何を渡せばいいのか
def palpunte (id, foo, bar, buz)p [id, foo, bar, buz]end# というか見てもよくわからない
# Ruby
# 実際にはキーワード引数だけで表現できる
def palpunte (id: nil, **options)raise TypeError if id.nil?
foo ||= "default foo"bar ||= "default bar"buz ||= "default buz"
p [id, foo, bar, bar]]end
# Ruby
raise TypeError unless foo.instance_of?(String)raise TypeError unless bar.instance_of?(String)raise TypeError unless buz.instance_of?(String)
いわゆる動的言語にも型が付く流れ
Flowtype
TypeScript
PEP484
mypy
Ruby3 rbi
Sorbet
Steep
PHP型宣言
PHPDoc
PhpStorm,Phan
身体は型を求める
型が付いていないということはどういうことか
<?php
/*** @param mixed $a 可能性は無限大
* @param mixed $b* @return mixed*/function add($a, $b){return $a + $b;}
<?php
function add(){$args = func_get_args();
return array_pop($args)+ array_pop($args);}
無限大じゃ困るんだよ
とはいえ+できる値という前提があるので案外困らない
ほんとに?
<?php
error_reporting(0);
var_dump(add(1, 2)); // => int(3) 想定通り
var_dump(add(1.0, 2.0)); // => float(3.0) 許容範囲
var_dump(add('1', '2')); // => int(3) 許容範囲
var_dump(add('', '')); // => int(0) ?????var_dump(add(1, 2, 3)); // => int(3) ?????var_dump(add([], [])); // => [] えっ?????
var_dump(add(PHP_INT_MAX, 1));// => float(9.2233720368548E+18)
実行時に型を調べよう
いわゆる動的言語は実行時に型があるのでそれを検査できる
JavaScriptではtypeof 演算子で型名文字列がとれる
Python type()
Ruby Object#class
PHPではis_int(),is_string()などの関数(gettypeは使いにくい)
<?php
/*** @param mixed $a 可能性は無限大
* @param mixed $b 可能性は無限大
* @return mixed*/function add($a, $b){if (!is_int($a)) {throw new TypeError('Error');}if (!is_int($b)) {throw new TypeError('Error');}
// 実装するときに int 以外の値が渡ってくる可能性を考えなくて良い
return $a + $b;}
実行時に変な値に対して処理が続行する可能性は避けられる
例外で処理が停止するので
PHPとかいう静的型付きプログラミング言語
<?php declare(strict_types=1);
// このメソッドを実装するときに int 以外の値が
// 渡ってくる可能性は考えなくてよい
function add(int $a, int $b): int{return $a + $b;}
静的 =実行しなくても型が決まってる状態
静的型付きStatically typed既に型が決定してる
動的型付けDynamic typing実行時に型を付ける
よくある誤解
静的型=コンパイラ
動的型=インタプリタ
ただしプログラム実行時のデータの表現方法がそういう関係になりがち
C言語は静的型付き
多くの動的言語はC言語で実装
必ずしも排他の関係ではない
お使いの言語ランタイム(ruby,python, phpなど)のC言語実装がどうなっているか、変数がC言語の型でどう表現されてるか読んでみるとおもしろいと思います
PHPは実行時に型をチェックする
ただし関数とプロパティに静的に型を付けられる
ただし静的に型を付けても実行時にクラッシュする可能性があります
型で守られてるとはどういう状態か
‒Akinori Abe 『型安全性入門』(Apr 6, 2017)
‒Akinori Abe 『型安全性入門』(Apr 6, 2017)
関数を呼び出す側が間違って呼び出すことをPHPだけでは防げない
動的言語で完全かつ健全にするのは不可能
偽陽性(動かないのに動きそうなフリをしている)ことを最小にしていくことを目指す
コンパイラの代りに静的型チェッカーを使おうということになる
PHPでも複数の型チェッカーが揃っている
PhpStorm
Phan, Psalm
PHPStan
PHPのソースコードを解析しても判別できない型は注釈(annotate)してあげる必要がある
人間がコメントで型を書く
人間が型を間違ってつけると破綻するので実際簡単ではない
連想配列(Hash, dict)を構造体のつもりで多用されると静的解析を簡単に破滅できる
と思うでしょ?PHPDocでなら型をつけられます
PHPに型を付けたりCIに載せる話はFANBOXに記事やスライドを掲載してます
型について学ぶにはどうすればいい
ハードルが高い(そもそも値段が…)
一章のPDFは無料なので読んでほしいが難しいので理解できなくてもいい
型のみならずプログラミング言語についてのさまざまな概念を学べる
まとめ
仕事で使ってる言語を好きになるために目を逸らさず向き合っていこう
