JSX / Haxe / TypeScript

46
JSX の紹介 bleis-tift November 3 2012

description

大なごやJS vol. 4での発表資料です

Transcript of JSX / Haxe / TypeScript

Page 1: JSX / Haxe / TypeScript

JSXの紹介

bleis-tift

November 3 2012

Page 2: JSX / Haxe / TypeScript

/////JSX型の紹介

bleis-tift

November 3 2012

Page 3: JSX / Haxe / TypeScript

自己紹介

id:bleis-tift / @bleis

好きなプログラミング言語は JavaScript /Scala / F#など

てるるーさんがHaxeの話をするっぽいので、当初は JSXの話を考えてました

無理っぽいので型と絡めた話をします

Page 4: JSX / Haxe / TypeScript

注意!

ガチな話はしない (できない)ので気軽に聞いてください

ガチな話が聞きたい人は、@keita44 f4 とか、@t6sとかにどうぞ。

Page 5: JSX / Haxe / TypeScript

今日話すこと

JSを吐き出す言語と型の話

型の便利さ

型の楽しさ

型の奥深さ

このあたりをちょっとでも伝えられたらな、と。

Page 6: JSX / Haxe / TypeScript

出てくる言語

JSX・・・DeNA社製。生の JSよりも遅くならないらしい (要出典1)。JSの皮をかぶった Java

Haxe・・・この中では最古参。JSだけでなく、PHPやFlash、JavaにC#など、様々な言語に変換可能。手続型言語の皮をかぶった関数型言語

TypeScript・・・この中では最後発。C#作った人が設計。JSとの親和性を重視している、JSの皮をかぶったC#

静的型付けの言語オンリー

1ベンチマークが少ないので評価保留中

Page 7: JSX / Haxe / TypeScript

注意そのに!

これら 3つの言語は設計思想が全く異なるJSXは最適化に重点を置いて、ばしばしインライン化を行う。ベストプラクティスという名のバッドノウハウを気にせずにコードが書けるTypeScriptは JSとの親和性を重視し、素直な JSを出力するHaxeは柔軟性があり、どちらにも倒せる

今回は「型」という観点からこれらの言語を見てみる

これら 3つの言語の優劣を決めようとかって話ではない

目的や状況に合わせて言語を選択しましょう

Page 8: JSX / Haxe / TypeScript

質問!

Q. みなさん型についてどういうイメージをお持ちですか?

マイナスイメージ書くのが面倒・・・冗長で邪魔!考えたくない><

プラスイメージ安心!分かりやすいウヒョヒョ、脳汁出るウヒョー

Page 9: JSX / Haxe / TypeScript

型がある言語ない言語

型を持っている言語C / Java / JSX / TypeScript / HaxePHP / Perl / Ruby / JavaScript / CoffeeScript

型を持っていない言語機械語Grass / LazyK / ラムダ計算

静的型付け言語だろうが、動的型付け言語だろうが、型はある

Page 10: JSX / Haxe / TypeScript

動的型付けと静的型付けの違い

ざっくり説明:

動的型付け・・・値にしか型が付かない

静的型付け・・・変数に型が付く

型を書く必要がある/ないという違いではない点に注意!

Page 11: JSX / Haxe / TypeScript

静的型付けの何がうれしいの?

型に関するエラーが実行時に発生しないこれはテストでは得られない保証キャスト?しらんがなー

型がドキュメントになる型があればある程度何をするか分かるとはいっても、何でもかんでも文字列で表すとかは論外なので死ねばいい

最適化の余地が多い最適化をどこまでやるかはトレードオフ

開発支援ツールが充実する可能性入力補完とか、リファクタリングツールとか可能性はあるが用意されてるかどうかは別

Page 12: JSX / Haxe / TypeScript

型推論

Page 13: JSX / Haxe / TypeScript

よくある比較の例

.

架空の静的型付け言語の変数宣言

.

.

.

// 文字列型の変数 sを"hoge"で初期化String s = "hoge";

// 日付型の変数 dを現在日時で初期化Date d = new Date();

.

架空の動的型付け言語の変数宣言

.

.

.

// 変数 sを"hoge"で初期化var s = "hoge";

// 変数 dを現在日時で初期化var d = new Date();

これで「静的型付け言語は冗長だ!」となるのは悲しい

型推論!

Page 14: JSX / Haxe / TypeScript

簡単な型推論

.

架空の静的型付け言語の変数宣言

.

.

.

// 文字列型の変数 sを"hoge"で初期化String s = "hoge";

// 日付型の変数 dを現在日時で初期化Date d = new Date();

=の右側が分かれば、左側の型って自明じゃね?→静的型付け言語なら右側の型は分かる→じゃぁ書かなくていいじゃん!

.

架空の簡単な型推論付静的型付け言語の変数宣言

.

.

.

// 変数 sを"hoge"で初期化 (変数の型は文字列)

var s = "hoge";

// 変数 dを現在日時で初期化 (変数の型は日付)

var d = new Date();

Page 15: JSX / Haxe / TypeScript

ん?

Page 16: JSX / Haxe / TypeScript

同じや!

.

架空の動的型付け言語の変数宣言

.

.

.

// 変数 sを"hoge"で初期化var s = "hoge";

// 変数 dを現在日時で初期化var d = new Date();

.

架空の簡単な型推論付静的型付け言語の変数宣言

.

.

.

// 変数 sを"hoge"で初期化 (変数の型は文字列)

var s = "hoge";

// 変数 dを現在日時で初期化 (変数の型は日付)

var d = new Date();

Page 17: JSX / Haxe / TypeScript

どんなものが来ても推論できるの?

.

.

var i = 42; // iは数値型

.

.

var xs = [1, 2, 3]; // xsは数値の配列型

.

.

// f: Regex[]を返すなら、xは Regex型var x = f("hoge")[2];

// gは文字列を受け取って Regexの配列を返す関数var g = f;

.

.

var h = function(a) { return a + 1; };

// JSX : コンパイルエラー// TypeScript : anyを受け取り anyを返す関数// Haxe : Intを受け取り Intを返す関数

Haxe素敵。TypeScriptは anyに落ちる。JSXは型推論自体が後付けなので残念。ちなみに・・・

Page 18: JSX / Haxe / TypeScript

関数式 (ラムダ式)

.

JS

.

.

.

var f = function(i) { return i + 1 }

これをHaxe / JSX / TypeScriptで書くと・・・

.

Haxe

.

.

.

var f = function(i) return i + 1;

.

JSX

.

.

.

var f = (i: int): int -> i + 1;

.

TypeScript

.

.

.

var f = (i: number) => i + 1

TypeScriptが一番短く書けました

Page 19: JSX / Haxe / TypeScript

オーバーロード

Page 20: JSX / Haxe / TypeScript

JavaScriptで

文字列を検索して、ヒットした indexが欲しい!

それ indexOfで

文字列だけじゃなくて、正規表現でも指定したい!

とかそんな場合にどうするか。

Page 21: JSX / Haxe / TypeScript

そこでオーバーロードですよ!

.

JSでオーバーロードもどき

.

.

.

function idxOf(str, target) {

switch (target.constructor.name) {

case ’String’: // targetが文字列の場合の実装case ’RegExp’: // targetが正規表現の場合の実装}

}

他にも、コンストラクタはオーバーロード欲しいことが多いかも。

Page 22: JSX / Haxe / TypeScript

実はJSにも一部オーバーロードがある

.

演算子はオーバーロードされてる

.

.

.

1 + 2 // number + number = number

’3’ + 4 // string + number = string

// Object + number = number

{

valueOf: function() { return 10 }

} + 20

// Object + number = string

{

toString: function() { return ’x’ }

} + 20

Page 23: JSX / Haxe / TypeScript

JSX / Haxe / TypeScriptの場合

JSX・・・オーバーロード対応

TS・・・オーバーロード対応 (メソッドはできないっぽ)

Haxe・・・オーバーロード非対応

オーバーロードは一見便利だが・・・

Page 24: JSX / Haxe / TypeScript

オーバーロードが型推論を邪魔する

.

オーバーロードがあると・・・

.

.

.

function f(i: Int) { return 0 }

function f(s: String) { return 1 }

// xの型は・・・?function g(x) { return f(x) }

オーバーロードを導入すると、強力な型推論はあきらめたほうがよい。それに加え、後で出てくる variantがあれば型が違うだけのオーバーロードはパターンマッチで代用できるし、数が異なるものはリストで代用できる。

Page 25: JSX / Haxe / TypeScript

名前を付けない型

Page 26: JSX / Haxe / TypeScript

ダックタイピング

アヒル (duck)のように歩き、

アヒルのように鳴くらば、

それはアヒルだ!

Page 27: JSX / Haxe / TypeScript

JSでのダックタイピング

.

xと yさえあればいい

.

.

.

function f(point) {

var x = point.x;

var y = point.y;

// なにか素敵な処理}

var p1 = { x: 10, y: 20 };

var p2 = new (function() {

this.x = 1;

this.y = 2;

})();

JSX / Haxe / TypeScriptでどうやるのかを見ていきます。

Page 28: JSX / Haxe / TypeScript

JSXの場合:templateJSXは templateを使います。

.

template

.

.

.

function f.<T>(point: T): 戻り値の型 {

var x = point.x;

var y = point.y;

// なにか素敵な処理}

var p = { x: 10, y: 20 }; // うっ・・・class Point {

var x: number;

var y: number;

function constructor(x: number, y: number) {

this.x = x; this.y = y;

}

}

が、現行バージョンではユーザは関数テンプレートが使えません・・・駄目じゃん

Page 29: JSX / Haxe / TypeScript

Haxeの場合:構造的部分型

Haxeでは、構造的部分型を使います。

.

構造的部分型 (Haxe)

.

.

.

function f(point: { x: Int, y: Int }) {

var x = point.x;

var y = point.y;

// なにか素敵な処理}

var p = { x: 10, y: 20 };

class Point {

public var x: Int;

public var y: Int;

public function new(x, y) {

this.x = x; this.y = y;

}

}

Page 30: JSX / Haxe / TypeScript

TSの場合:構造的部分型

TypeScriptでも、構造的部分型を使います。

.

構造的部分型 (TypeScript)

.

.

.

function f(point: { x: number; y: number; }) {

var x = point.x;

var y = point.y;

// なにか素敵な処理}

var p = { x: 10, y: 20 };

class Point {

constructor(public x: number, public y: number) { }

}

短い!

Page 31: JSX / Haxe / TypeScript

ダックタイピングと構造的部分型の比較

両者、同じようなことが実現できました。しかし、プログラムの変更に対して、両者はまったく異なる特徴を持ちます。

内側の変更・・・関数 fの中で、他のメンバにアクセスしたくなった

外側の変更・・・渡していたオブジェクトのメンバ名を、リファクタリングで変更した

これらの状況に対し、

ダックタイピングは前者は容易だが後者は困難

構造的部分型は前者は困難だが後者は容易

Page 32: JSX / Haxe / TypeScript

それにしても、だ

JSXマジ頑張れ・・・

Page 33: JSX / Haxe / TypeScript

直和型

Page 34: JSX / Haxe / TypeScript

トランプのカード

簡単のために、絵柄を無視するとして・・・

1~10までの数字

Jack / Queen / King

これを、どう表現するか?

Page 35: JSX / Haxe / TypeScript

JSXの場合:クラス階層

.

.

abstract class Card {

abstract function toNum(): number;

}

class Num extends Card {

var num: number;

function constructor(n: number) {

this.num = n;

}

override function toNum(): number { return this.num; }

}

class Jack extends Card {

static var _instance = new Jack();

static function getInstance(): Jack { return Jack._instance; }

override function toNum(): number { return 11; }

}

class Queen extends Card {

static var _instance = new Queen();

static function getInstance(): Queen { return Queen._instance; }

override function toNum(): number { return 12; }

}

class King extends Card {

static var _instance = new King();

static function getInstance(): King { return King._instance; }

override function toNum(): number { return 13; }

}

長い!

Page 36: JSX / Haxe / TypeScript

Haxeの場合:enum

enumといっても、Cや Javaの enumとは違います。

.

トランプのカードの表現

.

.

.

enum Card {

num(n: Int); jack; queen; king;

}

numに注目!何と他の列挙子と違い、値を持ってます。

Page 37: JSX / Haxe / TypeScript

enumに対する操作

enumに対する操作は、switchを使って行います。

.

カードを数値化する

.

.

.

function toInt(c)

return switch (c) {

case num(n): n; // !case jack: 11;

case queen: 12;

case king: 13;

}

パターンマッチ!

Page 38: JSX / Haxe / TypeScript

ここで仕様変更!

Jokerも扱いたくなった

.

Cardに Jokerを追加

.

.

.

enum Card {

num(n: Int); jack; queen; king; joker;

}

これでよい・・・?今まで書いてきたCardを使う処理、どうしましょう。

Page 39: JSX / Haxe / TypeScript

例えばさっき書いたこの処理

.

カードの数値化 (再掲)

.

.

.

function toInt(c)

return switch (c) {

case num(n): n; // !case jack: 11;

case queen: 12;

case king: 13;

}

jokerの場合の処理が書かれてないです。こんな感じの関数がすでにいたるところで書かれている・・・

Page 40: JSX / Haxe / TypeScript

パターンの網羅性チェック

でも、Haxeの enumならパターンの網羅性チェックがあるので、全ての場所でコンパイルエラーとなります。

.

パターンが網羅性がチェックされる

.

.

.

function toInt(c)

// Some constructors are not matched: joker

return switch (c) {

case num(n): n;

case jack: 11;

case queen: 12;

case king: 13;

}

あとはコンパイルエラーをつぶしていくだけ!安心!

Page 41: JSX / Haxe / TypeScript

enumによるオーバーロードの代用

例えばこんな enumを用意します。

.

.

enum StrOrEReg { str(s: String); regex(r: EReg); }

そしてパターンマッチ!

.

.

function idxOf(s, target)

return switch(target) {

case str(x): // targetが文字列の場合の実装case regex(x): // targetが正規表現の場合の実装

}

Page 42: JSX / Haxe / TypeScript

JSとの比較

.

JavaScript

.

.

.

function idxOf(str, target) {

switch (target.constructor.name) {

case ’String’: // targetが文字列の場合の実装case ’RegExp’: // targetが正規表現の場合の実装}

}

.

Haxe

.

.

.

function idxOf(s, target)

return switch(target) {

case str(x): // targetが文字列の場合の実装case regex(x): // targetが正規表現の場合の実装

}

Haxe版は、targetに数値などを渡すとコンパイルエラーになってくれる!

Page 43: JSX / Haxe / TypeScript

TypeScriptの場合:enum?

We expect the final language tosupport enum types, but not in the formthey are currently implemented.

「最終的な言語には enumのせたいけど、今はまだないよ」とのことなので、Haxeの enumっぽいものがのることをみんなで祈りましょう。

Page 44: JSX / Haxe / TypeScript

まとめ

静的型付け言語といっても、型をいっぱい書く必要はない (型推論)

オーバーロードは便利だが、いいことばかりではない

構造によって型を指定できる (構造的部分型)

Haxeの enumは他の言語の enumとは違う (直和型)

今回は「型」という観点で各言語を見たもう一度「注意そのに!」のスライドをよく読むこと

Page 45: JSX / Haxe / TypeScript

注意そのに!(再掲)

これら 3つの言語は設計思想が全く異なるJSXは最適化に重点を置いて、ばしばしインライン化を行う。ベストプラクティスという名のバッドノウハウを気にせずにコードが書けるTypeScriptは JSとの親和性を重視し、素直な JSを出力するHaxeは柔軟性があり、どちらにも倒せる

今回は「型」という観点からこれらの言語を見てみる

これら 3つの言語の優劣を決めようとかって話ではない

目的や状況に合わせて言語を選択しましょう

Page 46: JSX / Haxe / TypeScript

おしまい