JSX / Haxe / TypeScript

Post on 28-May-2015

13.594 views 2 download

description

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

Transcript of JSX / Haxe / TypeScript

JSXの紹介

bleis-tift

November 3 2012

/////JSX型の紹介

bleis-tift

November 3 2012

自己紹介

id:bleis-tift / @bleis

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

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

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

注意!

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

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

今日話すこと

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

型の便利さ

型の楽しさ

型の奥深さ

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

出てくる言語

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

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

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

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

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

注意そのに!

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

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

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

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

質問!

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

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

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

型がある言語ない言語

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

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

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

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

ざっくり説明:

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

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

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

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

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

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

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

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

型推論

よくある比較の例

.

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

.

.

.

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

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

.

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

.

.

.

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

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

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

型推論!

簡単な型推論

.

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

.

.

.

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

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

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

.

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

.

.

.

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

var s = "hoge";

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

var d = new Date();

ん?

同じや!

.

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

.

.

.

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

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

.

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

.

.

.

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

var s = "hoge";

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

var d = new Date();

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

.

.

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は型推論自体が後付けなので残念。ちなみに・・・

関数式 (ラムダ式)

.

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が一番短く書けました

オーバーロード

JavaScriptで

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

それ indexOfで

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

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

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

.

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

.

.

.

function idxOf(str, target) {

switch (target.constructor.name) {

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

}

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

実は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

JSX / Haxe / TypeScriptの場合

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

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

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

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

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

.

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

.

.

.

function f(i: Int) { return 0 }

function f(s: String) { return 1 }

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

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

名前を付けない型

ダックタイピング

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

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

それはアヒルだ!

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でどうやるのかを見ていきます。

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;

}

}

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

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;

}

}

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) { }

}

短い!

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

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

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

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

これらの状況に対し、

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

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

それにしても、だ

JSXマジ頑張れ・・・

直和型

トランプのカード

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

1~10までの数字

Jack / Queen / King

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

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; }

}

長い!

Haxeの場合:enum

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

.

トランプのカードの表現

.

.

.

enum Card {

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

}

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

enumに対する操作

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

.

カードを数値化する

.

.

.

function toInt(c)

return switch (c) {

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

case queen: 12;

case king: 13;

}

パターンマッチ!

ここで仕様変更!

Jokerも扱いたくなった

.

Cardに Jokerを追加

.

.

.

enum Card {

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

}

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

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

.

カードの数値化 (再掲)

.

.

.

function toInt(c)

return switch (c) {

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

case queen: 12;

case king: 13;

}

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

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

でも、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;

}

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

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が正規表現の場合の実装

}

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に数値などを渡すとコンパイルエラーになってくれる!

TypeScriptの場合:enum?

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

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

まとめ

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

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

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

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

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

注意そのに!(再掲)

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

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

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

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

おしまい