Temporalの能力についていくつか例を挙げます。cookbookを見てみてください。 これらの例の多くは legacy Date クラスには困難なものが多いです。特に timezone の取り扱いに関しては Date では難しいものが多いです。 (ただし、このポストでは例を上げてますが、コードに関しては変更される可能性が大いにあります。)
カジュアルに試すのであれば、インタラクティブなpromptを使えば簡単です!ブラウザを開いて、 API ドキュメントページに行ってください。APIドキュメントもしくは cookbook のページのどこでも、ブラウザコンソールから Temporal をロードされた状態で試すことが可能です。 Example のコードを実際に実行して試すことが可能です。もしくは RunKit上でも試すことが可能です。
これだけで、日付からの差分が出せるところは嬉しい。あとは細かく、 Calendar形式で1日追加するとかの細かい操作や timezone の変更などの操作が直感的にできる。 <input type=date>な field にも直接入れることができたりと細かいニーズに対応できている。さすが次世代 Date といったところか。
ちなみに、これまでの Date だと invalid Dateという number で言う NaNのような扱いになっており、例外は throw されなかった。
newDate("2012-12-11T12:20") // 2012-12-11T03:20:00.000ZnewDate("2012-12-11a12:20") // Invalid Date
どっちが良いかは諸説あると思うが、いままで手軽に扱っていた Date のマインドセットのままでは使えない。ちなみに momentとかも同様にパースできなくても例外を投げたりしない、 NaN 扱いになる。パースできない時に NaN 扱いだった Date ときちんと例外を処理しないといけない Temporal のどちらが良いかは筆者には判断付かないが、 JavaScriptはこれまでの歴史上、例外の取り扱いが難しいので、この辺の議論は是非参加してみたい。
ES2015 以前の Node.js は Web Standard な APIの中で足りないものを自分で補う形で進化を続けてきた。 Callback や Event 主体での非同期処理や Common JS な形でロードできる独自のモジュールの仕組みがその筆頭だと思う。ただ逆に Web Standard な APIが流行ると今度はそれに追従していかないといけなくなってきた。 ES2015 以後に流行ったものといえば、 Promise 主体での非同期処理であり、 async-await での処理だと思う。また、 ES Modules の台頭もあり、今日では Node.js でも普通に呼び出すことが可能になった。
今ではどちらも Node.js で普通に使える。エコシステムを壊さないようにした結果、 Node.js の ES Modules が普通に使えるようになるには時間がかかったが、いずれにせよ今は使えている。
TC39 だけが Web Standard なグループではない。 WHATWGや WICG 、 W3Cなどのグループもそれぞれ存在し、それぞれが Web Standard な APIを作っている。これらを後追いで Node.js は使えるようにしてきた。 Event Target API, Text Encode / Decode, WHATWG URL, Web Stream, Web Crypto, AbortController などなど、足りないパーツを補う形で作られている。
deno は最初から Web Standard な APIをベースに設計されており、割と Node.js よりも既存ブラウザに存在する機能を積極的に持ってきている方だと言える。後発なだけあって、エコシステムに配慮する必要がない分迅速に対応ができている。
Node.js / deno が Web Standard APIに追従する状況は現在でも続いている。ただし、最近は若干やりすぎなのではないかというか、本当に必要なのか?と思うようなものまで入っているし、検討されている気がする。
自分の立場を明確にしておくと、「新しい Web APIに追従することは良いことだと思うが、不要な APIにまで追従する必要はないし、無理矢理ブラウザと同じ APIにする必要もない」という立場だ。
新しい Web APIが必要か不要かにはいくつかの観点があると思う。筆者は以下のように観点を感じている。
ブラウザ間のコンセンサスが取れてない状況で実装したとしても変わる可能性は大いに有り得るし、最終的に実装されなかった場合には誰も得しない APIになってしまう。
まだマージするフェーズにどちらも入っていないものの、Web Standard APIを採用するとしても、ブラウザのコンセンサスはさすがに取られたものにしてほしい。プラットフォーム側がいち早く Web APIを実装しなくとも、コミュニティ側が「使いたい」という意見が出てから実装したとしても遅くないように思う。
これまでは同じ APIが増えることが Web というエコシステムを後押しするように思えていた。一方で、なんでもやりすぎるのはどうなのかと一旦立ち止まって考えるようになってしまった。特に atob/btoa を実装した辺りが個人的に立ち止まって考える切っ掛けになった部分だ。 Web Platform Test のカバレッジが増えることが良いことのようにされ、 mdn 上にある星取表が Yes になることが良いことだと思われているが、一方で、本当になんでも入れるのが良いことなのかについては考えていくようにして、フィードバックしたい。
ON-condition
An occurrence within a PL/I program of a condition that could cause a program interrupt, such as division by zero.
ON条件は PL/I のプログラム内で問題が発生した時にプログラムに割り込む事が可能になる。問題というのは例えば 0 で割った場合などを指す。
stack$pop(foo(mystack))
except
when empty:
% handler code
stream$putl(stderr, "popped empty stack")
when foo_ex(i: int)
stream$putl(stderr, "foo exception: " || int$unparse(i))
when bar, baz (*):
% ignore exception results, if any, of these
% bar and baz may have different number and types of exception results
others:
% all other exceptions handled here but results are lost
end
% flow continues here
Software exception handling developed in Lisp in the 1960s and 1970s. This originated in LISP 1.5 (1962), where exceptions were caught by the ERRSET keyword, which returned NIL in case of an error
1960年代から70年代にかけて、例外処理が開発されてきた。これはLISP 1.5 (1962年から) が起源であり、エラーの時に NIL を return する代わりに ERRSET キーワードによって例外をキャッチするものとして登場した。
Error raising was introduced in MacLisp in the late 1960s via the ERR keyword. This was rapidly used not only for error raising, but for non-local control flow, and thus was augmented by two new keywords, CATCH and THROW (MacLisp June 1972), reserving ERRSET and ERR for error handling.
エラーを上げることは MacLisp 内に ERR キーワードを使って 1960 年代後半に導入されました。これは急速に利用用途が広がり、いわゆるエラーを上げるという事だけではなく、ローカルの制御フローにも使われました。これにより2つの新しいキーワードが導入されます。 CATCH と THROW (1972年) をローカルの制御フロー用のものとして使い、 ERRSET と ERR はそのままエラーを上げる用途として残りました。
Node.js の assert は結構歴史が深いです。あまり直接使ってる人は少ないかもしれません。使うとしたら test で使ったりするケースでしょうか。 それも最近は jest に生えてる便利ライブラリを使うほうが多いのかもしれないですね。 unassertなんかで開発中に埋め込んでいるケースもあるかもしれません。このようにたまに使うこともあると思うので、覚えておくと良いでしょう。
なんでかよくわからないけど、エルフが出てきてバイナリーで話し始めたという所から独自のバイナリをデコードさせるっていう問題。とにかく仕様が複雑で、パケットの中にもサブパケットと呼ばれる入れ子構造になったパケットをデコードさせるので、再帰呼び出しで解く必要があり、また複雑なことにいくつかパケットのタイプが分かれてて、特別な処理が必要なパケットもあったりします。最後に leading zero で zero 値埋めがされているところとかも現実っぽい感じになっていて、とにかく「めんどくさい」問題でした。後半戦にはいったな、っていうことを思わせる問題でしたね。
ここで一回力が尽きます。 Day 23 も問題自体はシンプルです。いくつかの微生物がいて、そいつらがパズルのように動くので、動いたコストの最小値を求めよ、という問題です。パズルを解ければ OK なんですが、もう day 22 で一回力尽きてたので、やる気がどうしても起きず、一回答えを見た上で解きました。気が向いたら自分でも解いてみます。
このツイートに書いたとおりなんですが、 exercism は問題を解くだけじゃなくて、解いた後メンターが見てくれます。その上で、性能が遅いとか、もっと match 式を使えとか、こういう関数あるからこれでやれとか教えてくれます。 approve がもらえると嬉しいです。無くても解ければ次の問題にいけます。 main track と sub track があって、 main track は最後に小さい Stack ベースの言語書かされます。めっちゃ楽しい。
// https://gist.github.com/shqld/be21d1e82cec4dccfc933477f9b60356
main()
async function main() {const tasks = []
tasks.push(fail())
// Commenting out this line makes it work
await new Promise((resolve) => setTimeout(resolve, 0))
tasks.push(fail())
await Promise.allSettled(tasks)
console.log('Successfully handled')
}
async function fail() {thrownew Error('failed')
}
該当のスクリプトですね。この時も Unhandled Rejection になります。 main 関数の3行目の await new Promise((resolve) => setTimeout(resolve, 0))で起きます。一見うまくいきそうに見えるから不思議ですね。しかもこのコードをそのまま Chrome等で実行してみると特にエラーも何も出ずに成功したかのように見えます。
しかし、 Node.js/deno のときは Unhandled Rejection で process が落ちます。
Error: failed
at fail (/private/tmp/t3.js:10:11)
at main (/private/tmp/t3.js:5:11)
at Object.<anonymous> (/private/tmp/t3.js:2:1)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
main()
async function main() {const tasks = []
tasks.push(fail())
// Commenting out this line makes it work// await new Promise((resolve) => setTimeout(resolve, 0))
tasks.push(fail())
await Promise.allSettled(tasks)
console.log('Successfully handled')
}
async function fail() {thrownew Error('failed')
}
まぁどんな言語も同じだと思う。C言語だって生まれた当初はすごくクールでみんなをハッピーにしてた。今丁度「戦うプログラマー」を読んでるが、C++が出てきて、周りのエンジニアが C++を使おうとするシーンが出てくる。そこで、「あんなの使って何が良いんだ、Cで十分だろ」とWindows NT 開発リーダーのデーブカトラーが言ってたりする。ちょうどその頃(正確には NT リリースの少し後)に JavaScriptも生まれている。