Kuinの設計の理由からプログラミング言語自体の設計という技術への理解を深めてみる

技術書典6で「Kuinプログラミング入門 くいなちゃんとはじめるゲーム& 実用アプリ開発」という本を出します。 その過程の一環で、Kuinの公式サイトにあるプログラミング言語の「設計の理由」をまとてみました。

techbookfest.org

Kuinは「設計の理由」が公式サイト上に掲載されているため、それを通じてプログラミング言語の設計に対する理解を深めることができます。 プログラミング言語自体の設計力という、レアな技術を理解する良い機会です。

Kuin言語仕様1 命名と予約語

Kuin言語仕様1 命名と予約語 - プログラミング言語「Kuin」

大文字と小文字の規則

このルールは「キャメルケース」と呼ばれますが、このルールを採用した理由はタイプ数もコード量も少なくなるためです。

また、グローバル変数とローカル変数とがぶつからないように別の命名規則を定めることがよく行われますが、Kuinではグローバルなものには先頭に「@」を付けるという構文ルールがあるためキャメルケースで統一しています。

筆者補足: キャメルケースとは、小文字で命名して複数の単語が連結しているときには、2番目以降の単語の先頭を大文字にすること。「readSomeFile」など。

型名の接頭辞の規則

クラスを定義してそれと同名の変数を作りたくなるというケースはしばしばありますが、そのときに名前がぶつかるのを防ぐためにこのようなルールにしています。

筆者補足: Kuinでは列挙型名やクラス名など、ユーザが定義した型名の先頭は大文字にする。

ソースコード名の規則

Windowsではファイル名の大文字・小文字を区別しないため、同じファイル「ABC」に対し「abc」や「Abc」など別ファイルと扱われる余地があって不具合の元になりましたので、すべて小文字で統一しました。

筆者補足: Kuinではソースコード名はすべて小文字で命名し、複数の単語が連結しているときは間に「_」を挟む。

略語の規則

全く省略しなければ混乱のおそれもありませんが、プログラムが長くなることはそれだけ複雑になって把握しづらくなりますので、可能な限り省略する方針にしました。

Kuinの予約語

Kuinは識別子とそうでないものが構文的に区別可能なため、実は「if」や「for」などを変数名として許可しても問題になりません

ただ変数名に「if」などを使うのはやはり混乱の元になりますので、予約語として弾きました。

Kuin言語仕様2 型とリテラル

Kuin言語仕様2 型とリテラル - プログラミング言語「Kuin」

整数型 (int)

C言語のように様々なサイズの整数型を用意したとしてもメモリ消費量をそこまで切り詰めたいケースは少ないため、Kuinでは簡潔さのために通常用途の整数型は1種類に絞っています。

通常はオーバーフローを利用した処理を書くケースは少なく、逆にオーバーフローはバグの元になるため、デバッグ時にはオーバーフローを例外として検出する仕組みにしました。

サイズを意識したりオーバーフローを利用する場合は、ビット型を利用してください。

整数リテラル

16進数の「ABCDEF」が大文字のみを許可している理由は、小文字アルファベットは指数表記やビット型リテラルなどで使うためです。

浮動小数点型 (float)

intと同様、Kuinでは簡潔さのために浮動小数点型は1種類に絞っています。

NaNを計算に使いたいケースはほとんど無くバグの元になるため、NaNが発生する演算を行った時点で例外として検出する仕組みにしました。

筆者補足: NaNはNot a Numberのことです。

文字型 (char)

サロゲートペアの文字を考慮した場合、1文字を4byteとしたUTF-32で扱ったほうが便利になりますが、サロゲートペアの文字を使用する頻度は高くないため、WindowsAPIとの相性が良くメモリ消費量も少ないUTF-16で扱うことにしました。

参考:サロゲートペアとは?

vividcode.hatenablog.com

文字列の改行コード

Windowsでは改行コードは主に、C言語のエスケープシーケンスで「\r\n」(0x0d、0x0a)として表されますが、状況によっては「\r」が不要になったりと煩雑なため、Kuin上では改行は常に「\n」で統一し、内部で適宜「\r\n」に変換を行うようにしています。

ビット型 (bit8, bit16, bit32, bit64)

int型を汎用的に扱える整数型として設計したため、メモリ上の表現を意識しなければならない場合の整数型としてビット型を別に用意しました。

その名の通りビット演算も扱えるので、int型と場面に応じて使い分けると良いでしょう。

配列 ([])

文字列を専用の型ではなくchar型の配列にしている理由は、配列のために用意された各種機能がそのまま利用できるからです。

Kuin言語仕様3 演算子

Kuin言語仕様3 演算子 - プログラミング言語「Kuin」

冪 (^)

この演算子「^」はBASICに由来します。 日常的に使われるほど身近な演算ですので、演算子として直感的に書けたほうが良いと考え採用しました。

筆者補足: intもしくはfloatの2つの値「a」「b」に対し、「a ^ b」とすると、aのb乗の値が返る。

ディープコピー (##)

参照のコピーではなく中身のコピーを行いたいことは多いですが、これを用意している言語は意外と少なくユーザ側でコピー処理を実装する必要があったため、Kuinでは標準で用意しました。

筆者補足: 配列、list、stack、queue、dict、クラスの値の前に「##」を付けると、その値が別のメモリ領域にコピーされ、その参照が返る。

配列連結 (~)

この演算子「~」はD言語に由来します。 JavaやC#で見られる「+」では数値の加算と曖昧になり、PHPの「.」ではメンバの呼び出しと曖昧になりますので「~」を採用しました。

筆者補足: 配列の2つの値「a」「b」に対し、「a ~ b」とすると、aとbを連結した配列が新規のメモリ領域に確保されて返る。

比較演算子 (<>)

不一致の演算子「<>」はBASIC、Pascal、SQLなどで見られるものです。 演算子の1文字目を読み込んだ時点で優先順位が決定できるとコンパイルが速く行えるため、1文字目が「!」と重複する「!=」ではなく「<>」を採用しました。

条件演算子 ?(,)

この演算子「?(,)」はC言語に由来します。 C言語では「?:」ですが、式が長くなったり複数の「?:」を組み合わせた場合に優先順位が解りにくくなるため、明示的な括弧を用意して「?(,)」としました。 「?」と「(」の間にスペースを入れてはならない仕様にしたのは、この間が離れると、数式の括弧と混同しやすくなるためです。

スワップ演算子 (:$)

2つの変数の中身を入れ替える処理はよく行われますが、これを演算子や標準ライブラリで用意している言語がなぜかほとんど無かったため、Kuinでは用意しました。

代入演算子 (::)

代入演算子「::」はKuinの最も風変わりな設計の一つですが、これはPascalの代入演算子「:=」に由来します。 演算子の1文字目を読み込んだ時点で優先順位が決定できるとコンパイルが速く行えるため、1文字目が「=」と重複する「==」ではなく、かつ「:=」より入力が容易な「::」に決定しました。

Kuin言語仕様4 変数と関数

Kuin言語仕様4 変数と関数 - プログラミング言語「Kuin」

Kuinの変数定義 (var)

変数定義の書き方はほぼPascalでの書き方と同じです。 行頭で変数定義であることが判断でき、可読性もコンパイル速度も向上するため採用しました。

Kuinの関数定義 (func)

関数定義の書き方はほぼPascalでの書き方と同じです。 行頭で関数定義であることが判断でき、可読性もコンパイル速度も向上するため採用しました。

Kuin言語仕様5 文とブロック

Kuin言語仕様5 文とブロック - プログラミング言語「Kuin」

Kuinの文とブロック

; 関数ブロック
func f()
    var y: float :: 1
    ; ifブロック
    if(y >= 1)
        ; do something
    end if
    ; forブロック
    for(0,14)
        ; do something
    end for
end func

ブロック終端の「end ブロック名」でブロック名を指定させている理由は、C言語の「}」やPascalの「end」などのブロック終端記号が並んだときにどのブロックに対応するものかが解りにくくなるという可読性上の理由です。

コンパイル時の型チェックと同様に、ユーザが意図したコードになっているかをなるべくコンパイラがチェックしたほうがバグが減らせるため、多少冗長になってもブロック名を指定させて、コンパイル時に対応関係をチェックするようにしました。

break文

多くの言語では直近のブロックしか抜けることができないため、多重ループを抜ける場合にはフラグの変数を追加するなどの回りくどい方法を行う必要がありました。 そこでKuinでは抜けるブロックの識別子が指定できるようにしました。

またKuinではifブロックを含む多くのブロックがbreak文で抜けられるため、抜けるブロックを混乱しないように識別子は省略できないようにしました。

筆者補足:「break 識別子名」で、指定した識別子のblockブロック、forブロック、ifブロック、switchブロック、tryブロック、whileブロックの処理を抜ける。

do文

単なる式の実行に「do」という構文を必要とする理由は、必ず行頭で処理の意味を示すというルールを一貫することで可読性とコンパイル速度を向上させる狙いがあります。

とはいえ式の実行は高頻度で行われるため、なるべくタイプ数が少なくなるように2文字に抑えました。

ret文

多くの言語では「return」ですが、x86アセンブリでは省略形の「ret」が使われるため、短いほうを採用しました。

skip文

多くの言語では「continue」ですが、長く入力が大変なため「skip」に決定しました。 多くの言語のドキュメントのcontinueの説明に「ループ内の残りの処理をskipする」と書かれているため、「skip」の語のほうが直感的ではないかと思います。

throw文

多くの言語では例外クラスをユーザ側で派生させることで高度な例外処理が行えるようになっていますが、逆に煩雑になり適切に活用されないことが多いため、実用的に扱いやすい「例外コード」だけに絞ることにしました。

forブロック

for(0,14)
    ; do something
end for

多くの言語のforでは、初期値、終値、カウント値のそれぞれで変数を指定する必要があり、間違った変数を指定するとバグの元になっていたため、Kuinではより数え上げに特化させてシンプルな設計にしました。

このため他の言語のように「2倍ずつ増加させる」などの処理が行えなくなっていますが、そのような複雑な処理はwhileを使うべきだと考えます。

ifブロック

elifは、Pythonなどの一部の言語で用いられている、いわゆる「else if」の略です。

switchブロック

C言語などでは、caseの最後でbreakを行わないと次のcaseに突入してしまいますが、次のcaseに突入したいケースは少なくバグの元になりやすいため、Kuinではbreakが無くても自動的にブロックを抜けるようにしました。

その代わりに複数の値に対して同じ処理が行えるよう、case節の条件の書き方を充実させています。

whileブロック

この「skip」は、C言語などの「do-while」に相当します。

Kuin言語仕様8 組み込みメソッド

Kuin言語仕様8 組み込みメソッド - プログラミング言語「Kuin」

sar

「sar」という名前はx86アセンブリに由来します。 「Shift Arithmetic Right」の略称です。

筆者補足:「sar」はビット型の右算術シフトを求めるメソッド

shl

「shl」という名前はx86アセンブリに由来します。 「SHift logical Left」の略称です。

筆者補足:「shl」はビット型の左論理シフトを求めるメソッド

shr

「shr」という名前はx86アセンブリに由来します。 「SHift logical Right」の略称です。

筆者補足:「shr」はビット型の右論理シフトを求めるメソッド

Kuin言語仕様10 その他の構文

Kuin言語仕様10 その他の構文 - プログラミング言語「Kuin」

複数行コメント

複数行コメントに「{」「}」を使う記法は、Pascalに由来します。

C言語のコメント「/*」「*/」は入れ子にできないため、コメントアウトした部分にコメントが含まれていると、途中の「*/」にマッチして正しくコメントアウトできないことがありました。 そこでKuinではコメントが入れ子にできるようにしました。

単一行コメント

単一行コメントに「;」を使う記法は、x86アセンブラに由来します。

コメントの記号に「{」「}」「;」を採用した理由は、演算子等で使う記号と重複しないほうが望ましいために消去法で決定しました。

行分割

Visual BasicやC言語のマクロなどでは、行の途中で改行する場合に行末に特定の文字を記述しますが、Kuinは行頭に重要な情報が集まりますので、改行中かどうかが行頭で判断できるようにしました。

Kuin言語仕様11 コンパイラとIDE

Kuin言語仕様11 コンパイラとIDE - プログラミング言語「Kuin」

入力ファイルの特殊な仕様

  • 指定した.kn内に1文字も存在しなかった場合は「Hello, world!」を出力するプログラムになる。
  • 指定した.kn内に「q」の1文字だけ書かれていた場合は「q」を出力するQuineプログラム(自身のソースコードを出力するプログラム)になる。
  • 指定した.kn内に「f」の1文字だけ書かれていた場合は「Fizz Buzz」プログラムになる。
  • 指定した.kn内に「9」の1文字だけ書かれていた場合は童謡「99 Bottles of Beer」の歌詞を出力するプログラムになる。
  • これらには、改行やスペースなど他の文字を含めてはならない。

これらのプログラムは他のプログラムに比べてとても頻繁に書かれるため、Kuinコンパイラはその需要に応えるべきだと考えます。

さいごに

Kuinは、「くいなちゃん」によって考えられた言語仕様が反映されたプログラミング言語です。

私たちは、それを通じてプログラミング言語の設計における着眼点を学ぶことができます。 言語そのものに対する設計の考察を知る機会は少ないので、ぜひとも読んで見てはいかがでしょうか?

お知らせ

2019/04/14(日) に「池袋サンシャインシティ2F 展示ホールD」で開催される技術書典6にて、Kuinの入門本を頒布します。

techbookfest.org

締め切りが近いにも関わらず、まだ本は出来上がっておりませんが。毎週ブログを書くノルマがあるので、こうしてブログを書いております(苦笑。