タグ付きテンプレート(tagged template strings)でなんちゃって演算子オーバーロード

# はじめに

 * ES2015(ES6)で追加されたタグ付きテンプレート(tagged template strings)
  * 参考：[JavaScript の テンプレートリテラル を極める！](http://qiita.com/kura07/items/c9fa858870ad56dfec12)
 * その実体は特殊な関数
  * ぱっと見は関数に見えない
 * それをつかって”なんちゃって”演算子オーバーロードをやってみようという記事
  * __※注：実用性は低いです__

# 前提：「演算子オーバーロード」とは

JavaScript(ECMAScript)には無い概念。

 * 参考: [wikipedia](https://ja.wikipedia.org/wiki/%E5%A4%9A%E9%87%8D%E5%AE%9A%E7%BE%A9#.E6.BC.94.E7.AE.97.E5.AD.90.E3.81.AE.E5.A4.9A.E9.87.8D.E5.AE.9A.E7.BE.A9)

JSで言えば、`+`とか`-`の演算子(operator)は`number`（`+`は`string`）にしか対応していない所を、例えば配列同士にも対応させようというもの。

```js:実際には”1,2,34,5,6”という結果になる
var sum = [1,2,3] + [4,5,6]
console.log(sum)	//[5,7,9]
```

# タグ付きテンプレートリテラル

タグ付きテンプレートリテラル（tagged template strings）とは、通常のテンプレート文字列の前にタグの文字列がついたものだ。

```js:タグ付きテンプレートの例
var str = tag`文字列${変数}`
```

文字列と呼ばれているが、実は中身は関数へのシンタックスシュガーになっており、returnする中身も`string`である必要はない。


```js:文字数(number)を返すタグ付きテンプレート
"use strict";

function count(a,...args){
  let aSum = 0;
  a.map((v,i,a)=> aSum += v.length)
  let argSum = 0;
  args.map((v,i,a)=>{argSum += v.length})
  return aSum + argSum
}

var str = "お米"
console.log( count`おいしい${str}` )  //6
```

## タグ付きテンプレートになる関数の特徴

 * 第一引数は`raw`というプロパティを持った特別な配列
  * TypeScriptでは`TemplateStringsArray`
  * それ自体、および`raw`プロパティは文字列の配列
  * キャッシュされる
 * 第二引数以降は、`${}`で括った変数の値がそのまま入る
  * 文字列に限らない

# パッと見、関数に見えないので…

タグ付きテンプレートの特徴を使ってなんちゃって演算子オーバーロードをやってみる。

```js:配列同士の加算

var sum = A`${[1,2,3]} + ${[4,5,6]}`

console.log(sum) //[5,7,9]

```

```js:Aの中身

function A(arr, a1, a2){
  const op = arr[1].replace(/[\s]/g,"");
  switch(op){
    case "+":
      const longer = (a1.length >= a2.length)? a1 : a2
      const shorter = (a1.length < a2.length)? a1 : a2
      const l = shorter.length
      for(let i=0;i<l;i++){
        longer[i] = longer[i] + shorter[i]
      }
      return longer;
      break;
    default:
      throw Error();
  }
}

```

## 制限

 * 上記の例では加算のみ
 * 項目が２つまで
  * ただし次のようにする事はできる:

```
A`${[0,1]} + ${ A`${[1,1]} + ${[5,5]}` }`
```
 * 記号が多い
  * `A([0,1,2],"+",[3,4,5])`の方が見やすい！？

## 一応メリット

 * 文字列なのでどんな演算子でも自由に定義できる
  * `|>`とか
 * TypeScriptの場合、[`valueOf`を使った疑似演算子オーバーロード](https://github.com/rauschma/op_overload)はエラーになるが、この方法だとならない
  * `valueOf`の返す型情報を参照しないため
  * 参考：[SIMD型の演算子オーバーロード例](http://www.typescriptlang.org/Playground#src=%2F%2F%2F%20%3Creference%20path%3D%22simd.d.ts%22%20%2F%3E%0Atype%20SIMDData%20%3D%20SIMD.Float32x4%20%7C%20SIMD.Int32x4%20%7C%20SIMD.Int16x8%20%7C%20SIMD.Int8x16%20%7C%20SIMD.Uint32x4%20%7C%20SIMD.Uint16x8%20%7C%20SIMD.Uint8x16%0A%0Afunction%20m%3CT%20extends%20SIMDData%3E(str%3ATemplateStringsArray%2C%20a%3AT%2C%20b%3AT)%3AT%7B%09%09%0A%09%09const%20ctor%20%3D%20a.constructor%3B%09%09%0A%09%09switch(str%5B1%5D.replace(%22%20%22%2C%22%22))%7B%0A%09%09%09%2F*%20basic%20arithmatic%20operator%20*%2F%0A%09%09%09case%20%22%2B%22%3A%0A%09%09%09%09return%20%3CT%3E(%3Cany%3Ector).add(a%2C%20b)%3B%0A%09%09%09case%20%22-%22%3A%0A%09%09%09%09return%20%3CT%3E(%3Cany%3Ector).sub(a%2C%20b)%3B%0A%09%09%09case%20%22*%22%3A%0A%09%09%09%09return%20%3CT%3E(%3Cany%3Ector).mul(a%2C%20b)%3B%0A%09%09%09case%20%22%2F%22%3A%0A%09%09%09%09return%20%3CT%3E(%3Cany%3Ector).div(a%2C%20b)%3B%0A%09%09%09%2F*%20compare%20operator%20%20*%2F%0A%09%09%09case%20%22%3D%3D%22%3A%0A%09%09%09%09return%20%3CT%3E(%3Cany%3Ector).equal(a%2C%20b)%3B%0A%09%09%09case%20%22!%3D%22%3A%0A%09%09%09%09return%20%3CT%3E(%3Cany%3Ector).notEqual(a%2C%20b)%3B%0A%09%09%09case%20%22%3C%22%3A%0A%09%09%09%09return%20%3CT%3E(%3Cany%3Ector).lessThan(a%2C%20b)%3B%0A%09%09%09case%20%22%3C%3D%22%3A%0A%09%09%09case%20%22%3E%22%3A%0A%09%09%09case%20%22%3E%3D%22%3A%0A%09%09%09case%20%22%3E%3E%22%3A%0A%09%09%09case%20%22%3E%3E%3E%22%3A%0A%09%09%09case%20%22%3C%3C%22%3A%0A%09%09%09default%3A%0A%09%09%09%09throw%20SyntaxError(%22unknown%20or%20unsupported%20operator%22)%0A%09%09%7D%0A%09%7D%0A%09%0A%09let%20a%20%3D%20SIMD.Int32x4.splat(1)%3B%0A%09let%20b%20%3D%20SIMD.Int32x4.splat(2)%3B%0A%09%0A%09let%20c%20%3D%20m%60%24%7Ba%7D%20-%20%24%7Bb%7D%60)[^1]

# 補足

## `valueOf`を使った疑似演算子オーバーロード

 * より実用的な方
 * [Fake operator overloading for JavaScript](https://github.com/rauschma/op_overload)

## `Reflect.defineOperator`

 * [提案](http://www.slideshare.net/BrendanEich/extensible-operators-and-literals-for-javascript)
 * まだ[ES.nextのstage0](https://github.com/tc39/ecma262/blob/master/stage0.md)にすらなってない


[^1]: エラーは`SIMD`型の定義が無いから。[simd.d.ts](https://github.com/ConquestArrow/simd.d.ts/blob/master/simd.d.ts)をDLしてください。