LiveScriptでasync/await

# 【祝】LiveScript1.6が無事リリース

下記のような回避策は一切無しでasync/await使い放題になってます。
安心してご利用ください。

```bash
$ npm install -g livescript
/Users/miyabi/.nodebrew/node/v11.1.0/bin/lsc -> /Users/miyabi/.nodebrew/node/v11.1.0/lib/node_modules/livescript/bin/lsc
+ livescript@1.6.0
added 2 packages from 10 contributors, removed 1 package and updated 2 packages in 0.8s

$ lsc -v
LiveScript version 1.6.0
```

## ご挨拶

全国推定50人の[LiveScript]のファンの皆様こんにちは。
まだ[LiveScript]使ってますか？

2018/04/24現在、まだ[LiveScript]のバージョンは1.5.0から更新されていません。
1.5.0はES7で実装された[async]/[await]に対応しておらず、Promiseを上手に扱う事が出来ません。

そこで、今回はGitHub環境に上がっている開発中のバージョンを導入して、
[async]/[await]を有効化してしまおう！という事を紹介していきます。

## LiveScriptでasync/awaitが使いたければこれで導入すると良い

GitHubのプロジェクトに[1.6.0 release planning #1016](https://github.com/gkz/LiveScript/issues/1016)というIssueが建っており、そこで紹介されているインストール方法です。

```Bash
# 何故かoptionatorとsource-mapも一緒に入れる必要があったので記載
$ npm install -g github:gkz/LiveScript optionator source-map

$ cat test.ls
get-user = ->> name: \taro
main = ->> console.log await get-user!
main!

$ lsc -bc test.ls
// Generated by LiveScript 1.5.0
var getUser, main;
getUser = async function(){
  return {
    name: 'taro'
  };
};
main = async function(){
  return console.log((await getUser()));
};
main();

$ lsc test.ls
{ name: 'taro' }
```

インストールは成功し、`->>`でasyncの関数を生成出来ているのが確認出来ますね。
確かに`console.log`の中身が二重括弧になってたりとちょっと微妙ですが、実行には支障がなく十分使える範囲と言えるでしょう。

因みにその[Issue (2018/3/18)](https://github.com/gkz/LiveScript/issues/1016)ではそろそろ1.6出したいからスケジュール決めようと話しているようです。
しかし、開発者は「品質がまだまだ低くて自信を持ってリリース出来ない、使いたい人はこの方法でインストールしてみて」と仰っているようです。

## ネイティブJSに戻った私の日記

私は業務で素の[Node.js]を書いていたので暫く離れていました。

最初は「えー、今更ネイティブかよ…」と嫌々書いてたんですけど、[ES6]で追加された構文が本当にパワフルで、プチ[CoffeeScript]だと思いながらわりと快適に書くことが出来ました。
更に[Ramda.js]がプロジェクトで使えたので併用することで表現力の少なさによる不満も解消でき、非常に満足です。

そして、私は[async]/[await]の便利さに目覚めました。
関数とか作らずに[Promise]にパコッと[await]を被せるだけで、
[Promise]の状態がpendingから変化するまで一生待って、値を取り出してくれるとか強すぎでしょう。

長らく[構文がES5のままでオワコン](https://qiita.com/raccy/items/fae9fc5923d78112d935)と言われていた
[CoffeeScript]も後追いですが2.0になり多くの[ES6]やES7の武器を[取り込み復活を遂げました](https://qiita.com/raccy/items/43eb2e6929ebd0166dd0)。
[async]/[await]ももちろん使えるようになっています。
[Ramda.js]さえあればカリー化もポイントフリースタイルも余裕でパワフルな表現力が出せます。

意外かもしれませんが、[CoffeeScript]に慣れ親しんでいた皆さん、[Ramda.js]とセットで戻ってみて下さい。
[CoffeeScript]で括弧を作らずR.pipeで繋げて行く感覚は本当にヤバいです。

後必須級と言えるのはパイプライン演算子だけでしょう。
ライバルのTypeScriptはもう対応しているらしいので、[CoffeeScript]も実装してどうぞ。

## ES6登場後のLiveScript

[ES6]で追加された機能は沢山ありますが、
どれもこれも[LiveScript]からすれば「何？今更俺の良さに気づいて真似したくなった？？？」といったレベルです。

久々に触りましたが、表現力の凄まじさは健在でした。
[ES6]のコードから更に半分以下に収まりますからね…
プライベートで書くコードは基本的に全て[LiveScript]でやっていこうと思います。
これが[私にとってのLISP][1]です！

アロー関数が使えませんが昔ながらのthis束縛で十分です。
再代入禁止のconstもネイティブJSでは必須ですが、
[LiveScript]では行数が半分以下に抑えられてコードがスッキリしていますし、変数を大量に宣言する用事もないので困りません。

## ES7登場後のLiveScript

ところが、そんな[LiveScript]にも表現仕切れないものが出来てしまいました。
その筆頭がES7の[async]/[await]です！

```LiveScript
get-user = ->
  new Promise (resolve, reject)-> resolve name: \taro, score: 80
main = ->
  user <- get-user!.then
  user.score |> console.log
```

ご覧のように[LiveScript]には[バックコール](https://qiita.com/kiri/items/d7aafd54a9bdf40ef0d8)というチートな構文があり、そこまで表現力は落ちません。
しかし問題はrejectを返された時で、エラーハンドリングが出来なくなります。

ナンテコッタイ
仕方ないので普通にthenやcatchで繋ぐ方式に…
丸括弧地獄にはならないのでネイティブと比べるとかなりマシですけどね。

```LiveScript
get-user = ->
  new Promise (resolve, reject)-> resolve name: \taro, score: 80
main = ->
  get-user!
    .then -> it.score |> console.log
    .catch -> it |> console.error
```

しかし、流行りの非同期処理ライブラリを使い倒すようなシステムの場合、
大抵がPromiseを返す設計なので、thenを大量に重ねるようなケースでは[CoffeeScript]やネイティブのJavaScriptに表現力で劣るケースがあります。

これはまずい……

## LiveScriptにもasync/awaitを…

[LiveScript]くん、そろそろ更新してくれてもいいんじゃないかい？
[npmのLiveScriptのページ](https://www.npmjs.com/package/LiveScript)を見に行くと、貫禄の**last publish: 4 years ago**。

どう見てもオワコン言語です。本当にありがとうございました。
これ以外の機能は依然AltJSの中でもトップクラスだと胸を張って言える程なんだけどなぁ…

という訳で何とかならないか調査です。
[ES7 `async`/`await` implementation with concise syntax #836](https://github.com/gkz/LiveScript/pull/836)

どうやらプルリクは全てmasterにマージされており、使う事ができそうですね。
ではちょっと[LiveScript]の公式サイトで試してみましょう。
ペチペチ…「Compile」ボタンをポチっ！

```LiveScript
get-user1 = (id)->> name: \taro
get-user2 = async (id)-> name: \taro
async function get-user3 (id)
  name: \taro
// Parse error on line 1: Unexpected 'COMPARE'
```

全然ダメじゃないか！！

## async/await入りLiveScriptのインストール方法

まぁまぁ、masterにマージされているのは確実なんで、
masterブランチのものをnpmで使えば使えそうです。

冒頭では[Issue](https://github.com/gkz/LiveScript/issues/1016)にあったものを採用しましたが、GitHubから直接ダウンロードして導入してもいけます。

```Bash
$ git clone https://github.com/gkz/LiveScript.git
$ cd LiveScript
$ npm install

# -g付き名前無しでインストールすると今のものがグローバル領域に行く、自作のスクリプトをコマンド化したいときとかに便利
$ npm install -g

# 一度プロジェクトの外に出てからtest.lsを作ってみる
$ cd ../
$ vim test.ls
$ cat test.ls
get-user = ->> name: \taro
main = ->> console.log await get-user!
main!

# 実行！
$ lsc test.ls
{ name: 'taro' }
```

動きましたね！

## 構文紹介: async

まず、[async]/[await]の[Isuue](https://github.com/gkz/LiveScript/pull/836)で紹介されていた構文を試してみます。

```LiveScript
get-user1 = (id)->> name: \taro
get-user2 = async (id)-> name: \taro
async function get-user3 (id)
  name: \taro
```

コンパイルするとこのファイルに

```JavaScript
// Generated by LiveScript 1.5.0
var getUser1, getUser2;
getUser1 = async function(id){
  return {
    name: 'taro'
  };
};
getUser2 = async(function(id){
  return {
    name: 'taro'
  };
});
async function getUser3(id){
  return {
    name: 'taro'
  };
}
```

なんかダメな子がいますね、2番目の構文が非対応のままです。
その理由は[こちらのコメント](https://github.com/gkz/LiveScript/pull/836#issuecomment-256167286)にあります。

> **summivox** commented on 26 Oct 2016

> The proposed syntax for LSC does not conflict with existing code, and is intended for early adopters specifically targeting ES7 (and quite possibly including further transpiling toolchain)

意訳するとasyncというキーワードは普通の関数適用に使っている既存コードがあるからだそうで、
後方互換を意識して`->>`と`async function`と明示した時だけ利用可能にしたいという趣旨の事を言っているようです。
更に追っていくと2番目の書き方はremoveということで取り除かれて使えなくなった事が分かります。

確かにnpmに[asyncライブラリ](https://www.npmjs.com/package/async)ありますからね。
こちらは単なる関数なので[async]/[await]とは完全に別物です。
従来のコールバック関数を渡す処理ではこの[asyncライブラリ](https://www.npmjs.com/package/async)は非常に強力なので、
私は別にこれ使えばいいじゃん、無理にPromiseに変換する必要ないとまで思ってます。

## 構文紹介: await

もう見たまんまです。
ネイティブと同じなんで特に言うことはありません。

```LiveScript
get-user = ->> name: \taro
main = ->> console.log await get-user!
main!
```

しかし、awaitは完璧とは言えません。
2018/04/25現在、[Issue](https://github.com/gkz/LiveScript/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+await)で漁るとレアケース下で不具合が残っているようです。

- [`await` doesn't work in `for..let` loops](https://github.com/gkz/LiveScript/issues/1021)
- [`yield` and `await` don't work in `let` blocks](https://github.com/gkz/LiveScript/issues/1019)

両方要するに[LiveScript]のlet構文が原因ですね。
[LiveScript]はES5時代に登場した言語で、letは関数ブロックを作る事で対処していたようです。

> **let, New**
> let is short for `(function(a){...}.call(this, b))`.

ところが`yield`や`await`キーワードは特殊な関数の配下でしか使えないワードです。
従って、letを使う際は親の関数が、`function`, `async function`, `function*`の3通りで切り替えなければなりませんが、
その切替がどうも上手く動作していないようですね。

`for..let`とか誰が使うんだよと思ってましたが、
`await`を軸に据える場合、ループ処理では使う事になりそうなので気をつける必要がありますね。

## まとめ

いかがでしたでしょうか。
これを機に最強のAltJSである[LiveScript]で再始動してみるもの良いかもしれません。


[LiveScript]: http://livescript.net/
[CoffeeScript]: http://coffeescript.org/
[Node.js]: https://nodejs.org/ja/
[ES6]: https://developer.mozilla.org/ja/docs/Web/JavaScript/ECMAScript_6_support_in_Mozilla
[Ramda.js]: http://ramdajs.com/
[Promise]: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise
[async]: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function
[await]: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/await
[1]: https://www.amazon.co.jp/%E3%83%8F%E3%83%83%E3%82%AB%E3%83%BC%E3%81%A8%E7%94%BB%E5%AE%B6-%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E6%99%82%E4%BB%A3%E3%81%AE%E5%89%B5%E9%80%A0%E8%80%85%E3%81%9F%E3%81%A1-%E3%83%9D%E3%83%BC%E3%83%AB-%E3%82%B0%E3%83%AC%E3%82%A2%E3%83%A0/dp/4274065979