2024-10 の TC39 meeting
まとめ
決まったこと
Web compatibility issues / Needs Consensus PRs
るまさんが Array#toSorted が安定ソートを要請していないことを見つけて報告していたやつ。承認された。
ECMAを…変えるきっかけに…!
Intl.RelativeTimeFormat と Intl.DateTimeFormat で "numberingSystem" オプションを無視していた仕様バグの修正。承認された。
code: js
new Intl.RelativeTimeFormat("en", {
numberingSystem: "hanidec",
}).format(2, "days");
// current: "in 2 days"
// this PR: "in 二 days"
各言語の複数形について扱う Intl.PluralRules のカテゴリ順を明示的に定義する修正。
例えば英語は単数("one")と複数("other")のカテゴリがあり、フランス語ではそれに加えて大きい数("many")を扱う。これらカテゴリ全部で "zero", "one", "two", "few", "many" そして "other" の6つある。
カテゴリの順番を明示することで、言語にあるカテゴリ一覧を配列で返す API の結果が一意に定まる。承認された。
Intl.NumberFormat で通貨を扱うときに "notation" オプションが適用されてしまう。例えば notation: "scientific" とすると科学の有効数字を考慮した文字列の出力になる。
この対応はナンセンスなので辞めて "currency" オプションは notation: "standard" でないと通貨としての文字列を出力しないようにする修正。承認された。
code: js
new Intl.NumberFormat("en", {
style: "currency",
currency: "JPY",
notation: "scientific",
}).format(12345678);
// current: "¥1E7"
// this PR: "1E7" (currency オプションは無視される)
CurrencyDigits(通貨の小数点以下をどこまで表示するか)のデータは ISO 4217 を使うことと定められているが、他に CLDR 30 にも定義が存在する。V8 は CLDR 30 を使っており、SpiderMonkey は ISO 4217 を使っている。
その定義には差異があり、ISO 4217 はより法律的な定義を目指し、CLDR 30 は言語学的に関連性のあるものを目指しているのか、それともいずれかのデータが古いのか。定かではないがとりあえず非 ISO 4217 を使うことを仕様で許容したい話。
承認されたが、どっちがいいか今後調査が必要。
ArrayBuffer のコンストラクタのステップが SpiderMonkey 以外で仕様に合っていない。
仕様はそのままでひとまず test262 でカバーするとのこと。
TypedArray が大きさ 0 の ArrayBuffer を持つとき Object.preventExtensions を実行することで拡張不可能なオブジェクトに出来るが、その後 ArrayBuffer を resize したときに新たに数値プロパティを拡張できてしまう。
code: js
const buffer = new ArrayBuffer(0, { maxByteLength: 10 });
const uint8 = new Uint8Array(buffer);
Object.preventExtensions(uint8);
Object.isExtensible(uint8);
// false
Object.getOwnPropertyDescriptor(uint8, "0");
// undefined
buffer.resize(10);
console.log(Object.isExtensible(uint8));
// false
console.log(Object.getOwnPropertyDescriptor(uint8, "0"));
// { value: 0, writable: true, enumerable: true, configurable: true }
これを解決するために TypedArray に [[PreventExtensions]] 内部メソッドを追加したい話。多分次回に持ち越し。
Stage 4 (ES2025)
Stage 4 になった 🎉
Stage 4 になった 🎉
現状追加したいモディファイアと取り除きたいモディファイアを指定するのに - で区切るようになっている。
その左右両方とも空の時に Early Error を投げるようになっているが、右が空の時も - を書く必要がないため Early Error を投げていいのではないかという議論があった。これはリジェクトされた。
Stage 4 になった 🎉
Stage 4 になった 🎉
Stage 3
ソースが見つからなかったときに ReferenceError となっていたところを SyntaxError にする Normative Change。
ES2020 で Early Error はすべて SyntaxError になったのもありそれに寄せる。承認された。
"digital" スタイルが有効なときに "numeric" スタイルと "2-digit" スタイルを個々の単位に使用する場合に "useGrouping" を false にする Normative Change。
https://gyazo.com/709005c499d58298e4fb5bf5b040f1a7
承認された。
承認されていた Temporal.TimeZone と Temporal.Calendar クラス削除の Normative Change が落ち着いて、実装が進んでいる。
https://gyazo.com/448e82d12ef9fe993c152face8376998
仕様がほぼほぼフリーズされたので、あとは実装を待つのみ。
V8 が 74% だが、Deno で古い API を新しい API にマイグレートするパッチを当てた所感から、ほぼ内部実装は完了している印象がある。あとは表面的なところのみかな。
JavaScriptCore はこれから頑張って欲しい。Normative Change が多すぎたことから途中で実装を中断していた経緯があるので、特に怠慢とかではない。Stage 2.7 ができた理由の一つでもあるだろうし……。
Stage 3 になった。
Stage 2.7
メソッド名を変えるラストチャンスだったが、特に候補が上がらなかったのでそのまま。
遅延モジュールの実行トリガーについて議論された。ネームスペースオブジェクトの [[Get]] を定義し、string でアクセスされたときに実行される。ここでエクスポート名に存在しないプロパティはそもそもモジュールにエクスポートが無い場合や、エクスポート名のリストが取得できないプラットフォームのために許容される。
https://gyazo.com/a0e879cfda2b2b46345e5a413e840e69
さて他のメタオブジェクトプロパティについては中で [[Get]] を呼ぶかどうかでトリガーになるかどうかが決まるが、 [[GetOwnProperty]] ではエクスポート名のリストが既知でない場合に強制的に undefined を返すようになっている。これを解決するにはエクスポート名のリストを事前に取得しておく必要がある。
https://gyazo.com/366ee73757140d6bbbfd1b8a2e5b3404
また import.defer を使ったときに thenable の問題がある。ネームスペースオブジェクトの then プロパティにアクセスしたときに [[Get]] が実行されてしまう。
https://gyazo.com/9dfba08bad811aa49c68d653f10ed4a2
この問題については色々な案があった。例えば "then" を特別扱いするとか。
https://gyazo.com/79073cee1c31864a6bdc917fe3e5fa10
結果的に Dynamic Imports の import.defer は消されることになった。
Stage 2.7 になった。
非 Iterable を渡したときにどうするか議論された。
https://gyazo.com/826c4e566469d4b3c6216865e08e2bac
結果的に非 Iterable が渡されたときに即座に例外を投げることになった。Stage 2.7 になった。
Stage 2
Web 統合を進めている。
champion が引き継がれた。
Map#getOrInsert{, Computed} に API が変更されたようだ。
AbstructModuleSource に hasImportMeta と hasTopLevelAwait ゲッタープロパティが追加されている。
HTML 仕様における Transferable をどうするか明確になっておらず Stage 2 にとどまっている状態。
関連する議論として Worker における Import Maps の対応や、ずっと放置されている Loader Standard について話されている。
前回に引き続き void を使うか _ を使うかの議論。void を使いたいという話になっている。
Iterator#{chunks, window} の提案。
Stage 2 になった。
Struct は Struct を継承可能。作られるインスタンスとプロトタイプは封印され、インスタンスは [[StructBrands]] 内部スロットを持つことで異なる Struct のメソッドを実行できないようにレシーバー(this)がチェックされる。
code: js
struct Point2D {
x; y;
constructor(x, y) {
this.x = x;
this.y = y;
}
distance2D() { /* */ }
}
struct Point3D extends Point2D {
z;
constructor(x, y, z) {
// プロパティはすでに undefined で初期化されている
assert(Object.hasOwn(this, p));
}
// super の前にプロパティに代入しても問題ない
this.z = z;
super(x, y);
}
}
Shared Struct と Shared Fixed-length Array は null プロトタイプとなり、メソッドを持てない(メソッドがないと意味がないためプライベートプロパティも持てない)。
code: js
shared struct SharePoint {
x; y;
constructor(x, y) {
this.x = x;
this.y = y;
}
}
Atomics メソッドを使うことで SEQ-CST に実行することが出来る。アトミックに読み書きしない場合は例外を投げ、それを回避したい場合は明示的に unsafe ブロックで囲む必要がある。
code: js
function increment(ctr) {
ctr.value++;
}
unsafe {
increment(ctr);
}
また、扱いやすくするために mutex が導入される。
code: ts
shared struct Atomics.Mutex {
constructor();
static lock(
mutex: Mutex,
unlockToken: UnlockToken | undefined = undefined,
): UnlockedToken;
static lockIfAvailable(
mutex: Mutex,
timeout: Number,
unlockToken: UnlockToken | undefined = undefined,
): UnlockToken|null;
}
class Atomics.Mutex.UnlockToken {
constructor();
get locked(): bool;
unlock(): bool;
}
Stage 2 になった。今後 Realm の問題、複雑性や unsafe ブロックがその名前に反して使い所が少ない問題、Mutax.lockIfAvailable の返り値問題、そしてクラスと違ってコンストラクタで super の前に this が触れるがそれでいいのかを話していく。
仕様の文法中に [no |LineTerminator| here] が入り、改行を許容しないことで ASI (Automatic Semicolon Insertion) の問題が解決された。
Stage 2 になった。
Stage 1
たびたびセキュリティバグを引き起こすことから Symbol.species をやめたい話。
Firefox が調査したところ残念ながら Array, RegExp そして Promise で広く使われることがわかった。
https://gyazo.com/e67d20adf8a5e8911d7b2ef543e0014f
この結果を受けて、この提案はやめるか ArrayBuffer のような互換性を壊さないクラスにのみ Symbol.species を廃止するかが議論された。
TypedArray や ArrayBuffer, SharedArrayBuffer では消していく方向で、RegExp は調査することとなった。
ユースケースがないため Stage 1 のまま。
議論されていた trailing zero のサポートについてが別の提案にスプリットされた。
Array.zip for stage 1, or 2, or 2.7 | Jordan Harband Iterator.zip{, Keyed} の提案の Array バージョン。
Stage 1 になった。
Intl.NumberFormat に単位変換を入れる提案。サポート範囲が改められたらしい。
https://gyazo.com/fd781222e018e774a599281d206f979d
Smart Units の提案から触発されて単位の変換を扱うクラスを追加したい話。
code: js
let m = new Measure(1.8, "meter");
m.convert('foot', 2);
// { value: 5.91, unit: "foot" }
m.localeConvert("en-CA", "personHeight")
// {value: 5, minorValue: 11}
Smart Units とは異なり、サブセットとして CLDR から最低限必要なものだけを入れたいということらしい。
Stage 1 になった。
TC53 (Moddable XS) からの提案。ArrayBuffer#transferToImmutable メソッドと immutable プロパティを追加する。
Stage 1 になった。
Stage 0
N/A
Withdrown
N/A
その他
Exploring an Idea of a Proposal Management and Technical Arbitration Tool (slides) | Mikhail Barash 提案の管理などのツールを用意する話。
かつて optimize-js というライブラリが誕生し、函数を括弧でくくることで初回パース時にパフォーマンス改善するという触れ込みで流行ったことがあった。これは結果的に V8 や SpiderMonkey の実装でヒューリスティックに最適化されたことで使われなくなった。 この最適化をヒューリスティックにやるのではなく、開発者がファイル先頭にマジックコメント //# eagerCompilation=all をつけることで制御できるようにしたい話。特に言語仕様に入る訳では無いが、とりあえず頭出し。
Porffor JS engine - Compiling JS ahead-of-time | Oliver Medhurst
元 Mozilla の方が AoT JS エンジンを作っている話。
JSSugar/JS0 (slides) | Shu-yu Guo エンジンが実装している JavaScript を JS0 とし、それにトランスパイルするツールを JSSuger として議論していきたい話。JS0 を ABI として扱うイメージ。
気持ちはわからないでもない。マクロとかを言語仕様に入れられないし……。
ところで自分は使ったことないが昔 JSSuger って AltJS を作るためのパッケージがあったはずなので、そこから名前をとってるのかな?
TG4: Source Map Specification, 2024 edition approval (slides) Source Map 2024 の最終仕様が出来ている。
Google / Mozilla にあったライセンスを ECMA に移す作業がなされ、ECMA GA 行きとなった。
JSON みたいに ECMA ⚪︎⚪︎ みたいな数値が割り当てられるのだろうか?
TG5 Report
研究文脈で色々まとめている。
東大でワークショップをする(した)とのこと。
総括
今回は様々な提案が Stage 4 になった。特に Iterator Helpers と Import Attributes が入ったのが嬉しい。
また Source Map が今まで Google Document に仕様が記述されており Google/Mozilla 管理だったのがちゃんと ECMA に移管されるようになるのもよい。
個人的には JSSuger の話題が気になっている。特にマクロ周りの機能は JavaScript に入りようがないのでそちらが進むと嬉しい……ただその反面それは JavaScript なのだろうかと思わなくもない。JS0 を ABI として扱うのではなくて Binary AST がその役割を担うほうがいいのではとも思う。