暗黙的に型付けされる構造体の Javaへの導入

1
Javaのための暗黙的に型定義される
構造体
大久保 貴司 千葉 滋
東京工業大学
数理・計算科学専攻
2
静的型付け言語における構造体の利用
• 構造体(レコード型)
▫ 複数の異なる型のデータを
まとめるために利用
Java
人を表す構造体を
利用したい
• 静的型付け言語における構造体
▫ 定義が別途必要
 クラス等
▫ 構造体は単純なデータ構造
 値の出し入れさえできれば良い
 メソッドや関数は必要ない
class Person{
String name;
int age;
}
Person p = new Person();
p.name = “hoge”;
p.age = 20;
3
構造体の定義は省略したい
• 局所的にしか利用しない場合
• タプルの利用
▫ 新たな定義なしに生成可能
▫ 構造体として扱う上での制限
 任意の数のメンバをもつタプルは簡潔に記述できない
 各メンバへのアクセスは名前でなく index等
 不可変
Scalaのタプル
val p = (“hoge”, 20)
// p : Tuple2[String, Int]
4
動的型付け言語なら可能
• オブジェクトの型を定義する必要がない
▫ オブジェクトのメンバ (プロパティ) は自由に追加可能
• 動的型付け言語だからできる記述法
▫ 静的型付け言語 にこのまま導入することは不可能
Java
JavaScript
class Person{
String name;
int age;
}
Person p =
new Person();
p.name = “hoge”;
p.age = 20;
定義する必要なし
var p = {};
p.name = ”hoge”;
p.age = 20;
5
提案: 暗黙的に型定義される構造体
• 動的型付け言語のような構文で構造体を利用可能
▫ Javaで実現
▫ ストラクトオブジェクトと var 型を導入
 メンバを自由に追加可能
 追加したメンバにはアクセス可能
• フィールド以外で利用可能
本システムを用いた Java
var 型: ストラク
トオブジェクトを
参照する変数
の宣言時の型
var p = new();
p.name = “hoge”;
p.age = 20;
int i = p.age;
ストラクトオブジェ
クト( 構造体を表す
オブジェクト)を生
成
6
暗黙的な型定義
• structural type [Cardelli ‘88]+ 型推論
▫ 型はstructural type を用いて表現
 型は内部のデータ構造によって区別される
 型 = アクセス可能なメンバの集合
▫ 変数の型推論
 構造体のメンバへの代入から適切な型を決定
 変数が定義されているメソッド内をパース
変数 p の型
Struct{
String name;
int age;
}
var p = new();
p.name = “hoge”;
p.age = 10;
20;
int i = p.age;
7
構造体のフィールドの型
• 構造体のフィールドへ異なる型のオブジェクトが代
入されている場合
▫ フィールドの型 = 代入される各オブジェクトの型のアッ
パーバウンドの型
変数 a の型
Struct{
Shape obj;
}
class Shape{…}
class Circle extends Shape{…}
class Square extends Shape{…}
var a = new();
a.obj = new Circle();
a. obj = new Square();
8
Subtyping
• new()によって初期化されていないvar 型の変数へ
既存のストラクトオブジェクトを代入
▫ 必要に応じてスーパータイプを生成
 共通のアクセス可能メンバのみメンバとして持つ
new()で
初期化
var circle = new();
circle.color = “red”;
circle.radius = 3;
new()で
初期化
var square = new();
square.color = “blue”;
square.size = 5;
代入
var shape;
shape = circle;
shape = square;
struct{
String color;
int radius; }
struct {
String color;
int size; }
Struct{
String color;
}
circleの型
squareの型
shapeの型
9
メソッドへの受け渡し(1)
• ストラクトオブジェクトをメソッドに渡すことが可能
▫ メソッドの仮引数の型にvar型を指定
▫ 仮引数の型 = 仮引数がメソッド内で満たすべき条件
を満たす型
▫ 簡単な記述のみ可能 (現在)
仮引数xの型
void f(var x){
String s = x.name;
int age = x.age;
:
}
Struct{
String name;
int age;
}
var p = new();
p.name = “hoge”;
p.age = 20;
f(p);
pがxのサブタイプ
であれば引数としてOK
10
メソッドへの受け渡し(2)
• ストラクトオブジェクトをメソッドの返り値とすることが
可能
▫ メソッドの返り値の型としてvar型を指定
var makePerson(){
var p = new();
p.name = “hoge”;
p.age = 20;
return p;
}
var person = makePerson();
makePerson, person共に
以下の型がつけられる
Struct{
String name;
int age;
}
11
typeof の提供
• 型を取得するための演算子
▫ 本システムでは構造体の型の名前を明示的に指定で
きないため必要
p と同じ型のストラ
クトオブジェクトの
み格納可能
var p ;
Map<String, typeof(p)> map =
new HashMap<String, typeof(p)>();
for(int i = 0; i < 5; i ++){
p = new();
p.name = “hoge” + i;
p.age = 10;
map.put(“p” + i, p);
}
Struct{
String name;
int age;
}
p の型
12
実装
• 標準のバイトコードに変換
▫ var 型 = Object 型
 変数ごとにインタフェースを作成、必要に応じてキャスト
 インタフェースがアクセス可能なフィールドを表す
▫ ストラクトオブジェクト
 上記のインタフェースを実装するクラスのインスタンス
ストラクトオブジェクトを
表すクラス
変数の型
interface StringName{
String getName();
void setName(String name)
}
class Var$$0 implements StringName{
String name;
String getName(){return name;}
void setName(String name){
this.name = name;}
}
13
実験
• 内部クラスによる構造体と本システムを比較
▫ 構造体を生成・操作するメソッドを100個定義し、実行
するプログラム
▫ コンパイル時間と実行時間を計測
内部クラスを用いた構造体
run(){
class Person{…}
Person p = new Person();
p.name = “hoge”;
p.age = 5;
:
}
本システムを用いた構造体
run(){
var p = new();
p.name = “hoge”;
p.age = 5;
:
}
14
実験結果
• コンパイル時間
▫ 型推論や暗黙的に行われるクラス・インタフェースの定義によってオー
バーヘッドがかかっていると考えられる
▫ 既存のプログラムには影響を与えない
• 実行時間
▫ 実行時間には影響なく実現できた
2500
2000
30
本システム
約+40%
本システム
の利用
25
内部クラス
/JastAddJ
20
1500
15
1000
内部クラス/本
システムのコン
パイラ
10
500
5
0
0
コンパイル時間(ミリ秒)
var型/本システ
ムのコンパイラ
実行時間(ミリ秒)
15
関連研究
• Whiteoak [Gil ら ‘08]
▫ Javaにおいて structural typeな型を宣言できる
 インスタンスは生成できない
▫ 型を明示的に定義する必要はある
• Scala他
▫ 型推論を行う言語
 明示的に型を宣言する必要のない静的型付け言語
▫ タプルを用いると、クラス定義せずに構造体を生成で
きるが制限がある
16
まとめと今後の課題
• まとめ
▫ 暗黙的に型が定義・付けられる構造体を実現
 動的型付け言語の記述法を静的型付け言語である
Javaで実現
▫ 暗黙的に付けられた型を取得する typeof を提供
• 今後の課題
▫ var型の仮引数のメソッド内での利用の強化
▫ 形式化