= オペレータ

オペレータとは、演算子のことです。
こんなに気取った言い方をしなくてもいいのですが、
演算子というのも何となく日本語の語感から外れている気がするので、
オペレータと呼んでいます。

ここでは、Konoha が提供するオペレータの概要をみていきましょう。

== 代入、セレクタ、セパレータ

代入は、今さら説明の必要もないでしょうが、
変数に値を割り当てる操作のことです。

Konoha では、未宣言な変数に対し代入を行うと、
右辺式から型推論し、勝手に型宣言をしてくれます。

{{{
>>> x = 1
>>> typeof(x)
int

}}}

定数への代入は、未定義な定数に限り、定数定義として行えます。

{{{
PNAME = "naruto"      // 定数定義（型は推論される）

}}}

右辺には、変数以外であっても、
プロパティ変数、フィールド、インデックサなどに対して代入が行えます。
ただし、これらは setter メソッドへのシンタックスシュガーであるため、
後述する多重代入などには利用できません。

{{{
$name = "naruto"
p.name = "naruto"
p[0] = "naruto"   
p["name"] = "naruto"

}}}

=== 多重代入

変数への代入は、それ自身は式として扱われます。
次のように書くこともできます。

{{{
>>> x = y = 1      // x には、(y = 1) の値が代入
>>> x
1
>>> y
1

}}}

右辺も左辺も同数のカンマ(,)で区切ると、多重代入となります。

{{{
>>> x, y = 1, 2
>>> x
1
>>> y
2

}}}

多重代入は、右辺式を全て評価したあと、代入操作を行います。
次のように書けば、いわゆる値を入れ替えるスワップとなります。

{{{
>>> x, y = y, x
>>> x
2
>>> y
1

}}}

=== セレクタ、セパレータ

セレクタ、セパレータは、Konoha のユニークな操作のひとつです。
もともと、SQL の select に発想をえており、
データから要素の値を取り出すときに利用します。

セレクタは、名前ベースでオブジェクトから値をセレクトする機能です。
要素の名前と変数名が一致している場合のみ、正しく機能します。

{{{
>>> class Person {String name; int age; }
>>> p = Person{name: "naruto", age: 17}
>>> name, age = p;　　　// セレクタ
>>> name
"naruto"
>>> age
17

}}}
 
セパレータは、構造ベースでオブジェクトから値を取り出す操作です。
シーケンスなど、要素の順序が決まっているオブジェクトに対し、
インデックサからセレクトするときに用いることができます。

{{{
>>> s = ["naruto", "sakura"]
>>> a, b = s　　　　// s をセパレートする
>>> a             // s[0] と同じ
"naruto"
>>> b             // s[1] と同じ
"sakura"

}}}

== コール

コールオペレータ () は、メソッドやフォーマッタに対し、
パラメータを結びつけて機能を呼び出すときに用います。

{{{
>>> System.gc()     // パラメータなし
>>> fibo(10)
55
>>> %bits(1)
000000000 000000000 000000000 0000000001

}}}

コールオペレータの特殊な場合として、
第1パラメータが文字リテラルで始まるとき、
丸カッコ()自体を省略することができます。

{{{
>>> c.query """
select name, salary from PERSON_TBL
  where age > 45 and age < 65;
"""

}}}

== 比較

比較オペレータは、
２つの式 x, y の 同値(==, !=)、大小(<, <=, >, >=)を比較するときに用います。

{{{
>>> x = 1
>>> x == 3
false
>>> x + 2 == 3
true
>>> x < 1
false
>>> x <= 1
true

}}}

Konoha は、すべての型に対して比較オペレータが導入されています。
また、異なる型どうしであっても比較することが可能です。
ただしこれは、常に一意な結果を保証するだけで、
「意味のある結果」を保証するものではありません。

{{{
>>> 1 == [1]          // 型が異なれば値も異なる
false
>>> 1.1 < 2           // 数値どうしは比較可能
true

}}}

Java 言語は、オブジェクトの参照を比較していたため、
オブジェクトの値の比較は、equals() メソッドを用いていました。
Konoha では、オブジェクトの値を比較しているため、
文字列の比較も比較オペレータで行えます。

{{{
>>> s = "naruto"
>>> s == "naruto"
true
>>> s < "sakura"
true

}}}

=== 特殊な比較演算

マッチングオペレータは、
Perl に由来する正規表現によるパターンマッチングを行えます。

{{{
>>> s = "hello, world"
>>> s =~ /w.*d/
true

}}}

=== instanceof 

オブジェクト指向モデルは、クラス階層を半順序関係として定義します。
それに基づくオペレータ
instanceof は、
Java に由来し、
x がクラスCのインスタンスであるか判定します。

Konohaは、「全ての値がオブジェクト」であるため、
常に instanceof を適用することができます。
次の例では、整数 1　はFloatのインスタンスではありませんが、
Numberのインスタンスとなります。

{{{
>>> 1 instanceof Float
false
>>> 1 instanceof Number
true

}}}

null は、どのクラスのインスタンスでもないため、
常に false となります。
ただし、Any 型の場合だけは例外で true になります。

{{{
>>> null instanceof Object
false
>>> null instanceof Any
true

}}}

== 論理オペレータ

論理オペレータは、
論理式を論理的に連結し、より複雑な論理式を組むときに用います。

{{{
>>> a, b = 1, 2
>>> a == 1 && b == 2
true
>>> a == b || a < b
true
>>> !(a == b)   // a != b の方がよい
true

}}}

Konoha は、C言語スタイルの論理オペレータ(&&, ||, !)に加え、
Python スタイルの and, or, not もサポートしています。
どちらのスタイルを用いても好みの問題ですが、
and, or, not を使った方が、
誰にとっても読みやすいコードになります。

{{{
>>> a, b = 1, 2
>>> a == 1 and b == 2
true
>>> a == b or a < b
true
>>> not a == b   // a != b の方がよい
true

}}}

=== 優先度よりグルーピング

論理オペレータは、not, and, or の優先度で連結されます。
しかし、オペレータの優先度を正しく理解し、
それをソースコードをよむ全ての人が同じように正しく解釈するというのは、
ほとんど期待できない話です。

オペレータの優先度を覚えるよりは、
先に評価したい式を()でグルーピングして、
読みやすいコードを書くようにしましょう。

{{{
>>> a, b = 1, 3
>>> not a == 1 and b == 3 or a < b  // 悪夢
true
>>> not a == 1 or b == 3 and a < b  // 同じく
false
>>> (!(a == 1)) or b == 3) and a < b
true

}}}

=== 条件オペレータ

3項演算子は、代表的な条件オペレータです。
最初の論理式の結果によって、評価する式を切り替えるときに使います。

{{{
>>> a, b = 1, 2
>>> a = (a < b) ? a + b : a - b;
3

}}}

Konoha は、コロン(:)記号をラベルやタグにも利用しているので、
しっかりと前後に空白を入れましょう。

オペレータ {{{x ?? y}}} は、
C# でおなじみの null チェック用の条件オペレータです。

3項演算子{{{(x != null) ? x : y}}}と同じ意味になりますが、
nullチェックを連続するときは、
こちらの方がはるかに読みやすくかけます。

{{{
>>> d = {}
>>> key = d{"name"} ?? d{"id"} ?? "unknown";

}}}

== 算術オペレータ

算術オペレータは、2つの数値 x, y に対し、
四則演算を行うときに用います。

演算の順序は、四則演算の優先順位にしたがいますが、
やはり読みやすさを考えると、
グルーピングしてかいた方がよいでしょう。

{{{
>>> 1 + 2 * 3
7
>>> (1 + 2) * 3
9
>>> 1 + 2 - 3 * 4 / 2
-3

}}}

モジュロ % は、C/C++, Javaで広く採用されていますが、
Konoha ではフォーマッタと区別しにくいので、
代わりに mod を使うことが推奨されています。

{{{
>>> 7 mod 2    // 7 % 2 と同じ
1

}}}

算術代入は、
代入オペレータと算術オペレータを組み合わせたシンタックスシュガーです。

{{{
>>> x, y = 4, 2;
>>> x += y;         // x = x + y
5
>>> x -= y;         // x = x - y
4
>>> x *= y;         // x = x * y
8
>>> x /= y;         // x = x / y
4
}}}

=== ビット演算

Konohaは、整数に対して、
ビット反転({{{~x}}})、
論理積({{{x & y}}})、
論理和({{{x | y}}})、
排他論理和({{{x ^ y}}})、
左シフト({{{x <<< y}}})、
右シフト({{{x >> y}}})など、
C言語と同様なビット演算オペレータを用意しています。

もっとも Konoha のビット演算で画期的な点は、
フォーマッタ%bitsによって、
ビット演算オペレーションの結果を簡単にみれる点でしょう。

{{{
>>> x = 1
>>> y = 2
>>> %bits(~x)
11111111 11111111 11111111 11111110

}}}

== シーケンス

シーケンスとは、順序を保って並んだ値の集合のことです。
文字列や配列が代表的なシーケンスとなります。

Konoha は、シーケンスに対して、その操作に関する一連のオペレータを提供しています。

もっとも基本的な操作は、
要素は0 番目から始まる
配列スタイルのインデックスによる操作です。

{{{
>>> a = [0, 1, 2, 3]
>>> |a|            // シーケンスのサイズ
4
>>> a[1]           // シーケンスの値
1
>>> a[1] = 0
>>> a
[0, 0, 2, 3]
>>> a[-1]          // 範囲外のインデックス
 ** OutOfIndex!!: 

}}}

演算子 <<は、シーケンスに要素を追加するオペレータで、
複数の要素を連続して追加するときに便利です。

{{{
>>> a = [1]
>>> a << 2 << 3 << 5 << 7;
>>> a
[1, 2, 3, 5, 7]

}}}

ちなみに、加算オペレータ + は、シーケンスの連結操作となり、
しかも新しいシーケンスが生成されます。

{{{
>>> a, b = [1, 3, 5], [0, 2]
>>> a + b
[1, 3, 5, 0, 2]

}}}

スライシングは、シーケンスから部分シーケンスを取り出す操作です。
Konohaでは、部分シーケンスの範囲を指定するため、
![n to m] と ![n until m] の２種類の方法を用意しています。
前者は、m番目が含まれますが、後者はm番目の要素は含まれません。

{{{
>>> a
[1, 2, 3, 5, 7]
>>> a[1 to 3]
[2, 3, 5]
>>> a[1 until 3]     // 3番目は含まない
[2, 3]

}}}

== データ変換

Konoha の特徴は、オブジェクト間のデータ変換を統一された変換オペレータで行える点です。

データ変換の操作をオペレータで統一するメリットは、
オブジェクトの変換を行うメソッド名を覚える負担が減ることに加え、
マッピング推論によって自動的に変換を合成できることがあげられます。
この話を始めると長くなるので、
詳しくは、「[kbook.transformer データ変換]」を参照してください。

変換オペレータは、C言語やJava言語でおなじみのキャストと文法的に統合され、
プログラマは希望する型を要求すれば、
Konoha コンパイラがキャストか変換か自動的に判断します。

{{{
>>> Object o = "123";
>>> s = (String)o;   // ダウンキャスト
>>> n = (int)o;      // 変換
>>> n
123

}}}

オペレータ (*)x は、一見、ポインタ演算子にみえてドキッとしてしまうかも知れませんが、
要求された型への変換を意味します。

{{{
>>> n = 123;
>>> String s = (*)n;    // (String)n と同じ
>>> s
"123"

}}}

最後に、ひとつ特殊な変換オペレータ x.. を紹介しておきます。
これは、foreach 文における型推論で使われているオペレータで、
イテレータの型を特定することなく、
標準イテレータに変換するオペレータです。

難しいことを気にしなければ、便利につかうことができます。

{{{
>>> s = "naruto"
>>> s..
"n"
"a"
"r"
....

}}}

== オペレータのまとめ

||代入、コール|| ||
||{{{x = y}}}|| yの評価値を変数xに代入する||
||{{{f(x...)}}}|| fをパラメータ x... でコールする||
||比較|| ||
||{{{x == y}}}||等しいか？||
||{{{x != y}}}||等しくないか？||
||{{{x < y}}}||より小さいか？||
||{{{x <= y}}}||以下か？||
||{{{x > y}}}||より大きいか？||
||{{{x >= y}}}||以上か？||
||{{{x case y}}}||xは、パターン yと等しいか？||
||{{{x =~ y}}}||xは、パターン yと等しいか？||
||{{{x instaceof C}}}||x は、クラスCのインスタンスか？||
||論理、条件|| ||
||{{{x && y}}}|| x かつ y||
||{{{x ｜｜ y}}}|| x または y||
||{{{!x}}}||x の否定||
||{{{x and y}}}|| {{{ x && y}}}と同じ||
||{{{x or y}}}|| {{{x ｜｜ y}}}と同じ||
||{{{not x}}}||{{{!x}}}と同じ||
||{{{x ? y : z}}}|| xがtrueのときy、そうでなければz||
||{{{x ?? y}}}|| xがnullのときy||
||算術|| ||
||{{{x + y}}} || 加算 ||
||{{{x - y}}} || 減算 ||
||{{{x * y}}} || 乗算 ||
||{{{x / y}}} || 除算 ||
||{{{x % y}}} || 余り（モジュロ）||
||{{{x mod y}}} || {{{x % y}}} と同じ ||
||{{{~x   }}} || ビット反転 ||
||{{{x & y}}} || 論理積 ||
||{{{x | y}}} || 論理和 ||
||{{{x ^ y}}} || 排他論理和(XOR) ||
||{{{x << y}}} || 左シフト ||
||{{{x >> y}}} || 右シフト ||
||シーケンス || ||
||{{{|s|}}} || シーケンス s のサイズ ||
||{{{s[n]}}} || シーケンス s の n番目の値 ||
||{{{s[n] = x}}} || n番目に値xをセットする ||
||{{{s[] = x}}} || 全部に値xをセットする ||
||{{{x in s}}} || s に xが含まれているか？ ||
||{{{s << x}}} || s への x の追加 ||
||{{{s[x to y]}}} || x番目からy番目(含む)まで ||
||{{{s[x until y]}}} || x番目からy番目(含まない)まで ||
||変換|| ||
||{{{(T)x}}} || xのT型への変換 ||
||{{{(*)x}}} || 要求された型への自動変換 ||
||{{{x..}}} || x のデフォルトイテレータへの変換 ||


[[include(KbookIndex)]]
[[include(KbookFooter)]]
