• 67
    Like
  • 1
    Comment
More than 1 year has passed since last update.

JavaScript, TypeScript界隈におけるDecoratorsについて取り上げます。

JavaScriptとDecorators

JavaScriptでは馴染みのなかったDecoratorsが目に触れるようになったのはAtScript発表の際だったと記憶しています。

AtScript

AtScriptとは、2014年10月23日、ng-europeにて発表されたTypeScriptを包含する「新構文」です。

このときの例文を引用します。

@Directive({
  selector: ['[blink]']
})
class Blink {
  constructor(element:Element,
              options:Options,
              timeout:Timeout) {
    var selectors:Array<CssSelectors> =
        someThirdPartyAPI();
    element.query(selectors.join(','))
           .forEach(e => options.apply(e));
   }
}

@Directive()という箇所が彼らのいう(当初いっていた)AtScriptに該当する構文であり、本稿の題材でもあるDecoratorsです。

筆者の確認できた限りでは、この構文を用いられたJavaScriptソースが公になったのは2014年9月26日のangular/angularにおけるコミットが初で、この時点ではまだ関連ソースも揃ってなく動作しないソースでした。Angular 2関連で範囲を広げると、さらに前の2014年9月3日にはAngular 2にDecoratorsを採り入れる案があったようです。

ng-europeでの発表に向けて、既にこの時期には動き出していたことが推察できます。

TypeScript

2015年3月5日ng-confにて、MicrosoftのJonathan Turner氏によってTypeScript 1.5にAnnotationsが加わると発表されました。

翌3月6日にも同氏によってTypeScriptとAngular 2に関する講演が行われており、公式Twitterでも以下のような発言が掲載されています。

事実上AtScriptはTypeScript言語仕様として落ち着いたという瞬間です。(追記、稿末に詳細あり)落ち着こうとしています。

その後、2015年3月27日にMicrosoftよりTypeScript 1.5 Alphaの公式発表がなされ、予告されていたDecoratorsも併せてこの場で発表となりました。なお1.0以降、アルファ段階のTypeScriptが公式発表として取り上げられたのはこれが初です。

Decoratorsの文化的背景

筆者には馴染みのない構文だったため、そもそもこういった@で書き始める構文はどの言語から影響を受けたのか、という疑問がありました。元となった言語の使用者ではないため表面的な事実の羅列となりますが、確認した限りを並べてみます。

C#

C#には、@の構文ではありませんがMetadata構文というものがあります。登場時期はC# 1.0と同じく2001年2月。深くは言及しませんが、メタデータを読み取るためのReflectionという概念がAngular 2の実装内にも確認できたため触れておきます。

Java

どうやら@で書き始めるこの構文の根元はJavaにあるようです。2004年9月30日に発表されたJ2SE 5.0に採用されたMetadata構文(アノテーション構文とも)が最初で、この機能も、Java最初期(1996年1月23日)から存在していたJavadocの@が由来で採用された経緯があるようです。

J2SE 5.0(別名はTigerで、現在は2番目のベータ・リリースです)が入手できるようになるまでは、コアとしてのJava言語でメタデータ機能に最も近いものはJavadocによる手法でした。
http://www.ibm.com/developerworks/jp/java/library/j-annotate1/

@構文はJava由来なようですが、概念自体は前述のC#が先行しており、影響を与え合っていたと見る向きもあります。

Python

Pythonは2004年11月30日の2.4から@で記述するDecorators構文を備えました。これはPEP (Python Enhancement Proposals)で提言されたPEP 318 - Decorators for Functions and Methodsが源流のようです。資料にはJavaの影響を受けた旨が明記されています。

Why @?
There is some history in Java using @ initially as a marker in Javadoc comments and later in Java 1.5 for annotations, which are similar to Python decorators.
https://www.python.org/dev/peps/pep-0318/#why

Decoratorsは、やはりGoFのDecoratorパターンが由来で、JavaのMetadata構文を用途までそっくり取り込んだわけではないようです。

Some symbol options:
@
+ Java-like, so not completely unknown.
+ Not confusable with any current Python symbol
+ Makes syntax highlighting easy

@採用の経緯にJava風で既知の表記法だ、という旨が盛り込まれていました。PEP 318がまとまっていった様子の議事録はとても興味深いものです。PythonDecoratorLibraryというコンテンツは、JavaScriptにおいてDecoratorsを用いる際の着想として参考になるかもしれません。

Dart

Dart(2011年10月登場、2014年6月にECMA-408として規格化)にもMetadata構文と呼ばれる構文が存在しており、これはJava, Pythonのように@で始まっています。登場時期からみても、Dartはこれら先行言語からの影響を受けている可能性が高いです。

JavaScriptにDecoratorsが持ち込まれた経緯

これまで存在しなかったDecorators構文がなぜここへ来てJavaScriptに採り入れられるのか、客観的事実を元にした推察です。

2013年10月 AngularDartの存在

AngularDartの初期リリースはタグ基準で2013年10月17日のv0.0.2です。AngularDartではDartの言語仕様をそのまま活用して@で始まるAnnotationsを採用しています

AngularJS 1.xをDartで再実装するとして動いていたようですが、Angular 2がAngularJS 2, AngularDart 2という名前ではなく"Angular 2 for JavaScript|Dart"となったことから一本化されたものと理解しています。事実、Angular 2には.es6.dartという二つの拡張子のソースがまとめて格納されており、一つのプロジェクトで2言語に対応しようと試みられています。

GoogleのMiško Hevery氏がAngularDartの立ち上げ人で最多コード記述者である点、Angular 2草案リポジトリの中心人物である点、ng-europeでのAtScriptの発表者が同氏である点から総合的に判断して、Angular 2 for JavaScriptにDecoratorsが持ち込まれた経緯がAngularDart由来である、そして主要人物がMiško Hevery氏であることが分かります。

2014年4月 TC39での議題に上る

TC39というECMAのミーティングがあるのですが、TC39自体については日本国内でもウォッチしている方がおられるので、そちらに任せます。(参考

2014年4月のTC39で、"ECMA-262 7th Edition"、俗にいうES7の議論の際にYehuda Katz (wycats)氏によって案が提出されていたようです。

時系列としてはこの位置ですが、wycats氏がAngular事情と絡んでいたかは定かでなく、活動内容を見る限りその可能性は無さそうに見えます。TC39にて草案が提出されたことをAngular開発陣が観察していた可能性は有り得ます。

2014年10月 AtScriptの発表

前述のとおり、ng-europeにてAtScriptの発表が行われました。まだこの時はGoogle側の独自的な構文の範疇でしたが、ここから約半年で大きく動くことになります。

2015年3月 TypeScript 1.5への採用

さすがにGoogleとMicrosoft間のやりとりは窺い知れませんが、AtScript絡みで情報交換はしていたのだろうと想像しています。MSDN Blogsでは大歓迎の模様です。

この発表を行ったMicrosoftのJonathan Turner氏は2015年3月29日にDecoratorsに関するTC39 Proposalを立ち上げている件が非常に興味深く、ここに参加しているRon Buckton氏はTypeScript開発者の一人です。

DecoratorsのECMA-262 7th Editionでの規格化

語弊を含んで噛み砕いて言うと『JavaScript ES7でのDecoratorsの仕様策定』です。前述のとおりTC39ミーティングで進んでいるようです。

2015年3月のTC39ではwycats氏のプロポーザルで議論が進んだようですが、Microsoft側もプロポーザルを準備しており、今後どのように絡んでくるのか非常に注目しています。

TypeScript側のプロポーザル

Babel

ES6, ES7 Proposalの構文をES5に変換することでおなじみのBabelにはDecoratorsがすでに実装されています

このBabelの実装根拠がwycats氏のプロポーザルに限っているため、Angular 2がBabelで動かないという問題が起こりました。Angular, Microsoft側からも動きが出ると予想しており、動きにあわせてIssueも立つことでしょうから、この問題は時間が解決すると期待しています。

現時点での実装と挙動

挙動に関して本稿で触れると冗長になるため今回は割愛します。この件についてはQiitaやその周辺にて以下の記事を確認しています。(敬称略)

2015年4月13日現在、BabelとTypeScriptで挙動に差がでているという目撃情報があるので、これも時期尚早という印象がありました。
(追記)執筆中に直っていたことに気付いていませんでした。Babel開発者のsebmck氏が日本(上記記事絡みの方々)での挙動指摘のツイートを検索・翻訳し、直してしまったようです。恐るべき情報収集力と速さに感服しました。

AtScriptはTypeScriptを包含しているという誤解

(追記)本稿掲載後、さらに延長線上を調査していたところ、AtScript構文とTypeScriptに完全な互換性が無いことが明らかになりました。TypeScript 1.5 Alphaのtscでどうやっても通らないこの構文が許容されている根拠は何かと調べていたところ、次の二つのIssues/PRsを発見しました。

これらが意味するところを突き止めるためコミットの前後を追っていたところ、この構文は/tools/transpilerのツールのみが処理できるようで、ここを深追いはしていませんがtraceurのランタイムを拡張して実現させているようでした。

つまり変換できないBabel、TypeScript 1.5 Alpha側に問題があるのではなく、Angular 2の独自実装構文が生き残っていたということになります。ng-confではまことしやかに「AtScriptはTypeScriptだ」と囁かれ筆者も当然そうなのだろうと信じていたのですが、Angular 2側は2015年4月現在、TypeScriptにまだ移行できておらず、TypeScript言語仕様に加えてもらうのか、この構文をAngular側が諦めるのか、traceur依存を続けるのか、まったく目が離せない状況です。ng-europeからng-confまでの約半年に前述したinvalid構文についても仕様策定しておけば…と些か片手落ち感があります。

まとめ

  • @をデコレーション、アノテーションの構文として使う言語はJava, Python, Dartなど複数
  • AngularDartではDart言語にある@を使用している
  • Angular 2でJavaScript版とDart版を同時開発する上でJavaScriptにDecoratorsを持ち込んだ(発表当初のAtScript)
    • 2015年3月5日、TypeScript 1.5にDecoratorsを採用すると告知
    • 2015年3月27日、TypeScript 1.5 AlphaにてDecoratorsが正式に発表
  • TC39にてES7規格化の動き
    • プロポーザル提出はwycats氏のみだがTypeScript側にも準備がある

主要人物

敬称略

関連記事

謝辞

本稿の作成中、多くの方々を巻き込んでしまい、多大なる学びが得られました。ありがとうございました。お騒がせいたしました。

感想

まだ早い。