最新のプログラミング言語Runeに触れてみる
本記事は、eeic(東京大学工学部電気電子・電子情報工学科)Advent Calendar 2022の8日目の記事として書かれたものです。
はじめに
皆さん初めまして、gettsuです。特に記事を書いて来ていなかったたため初投稿です。EEIC2021の同期がアドカレを立ててくれたので参加してみようとエントリーしたものの、一文字も書けないまま前日になりました。1日で書き上げたのでクオリティの低さはごめんなさい。元々WebAssemblyかNeovim関係で何か書くつもりでしたが、あんまり面白くできなそうだったので新しい言語に触れてみた系の記事にしました。
Rune言語について
Rune言語(https://github.com/google/rune)は最近Googleが公開したプログラミング言語です。(Googleは7月にCarbonというプログラミング言語も公開しています。すごいですね)Googleの公式プロジェクトではないものの、バックについているのがGoogleのため、そこそこの影響力がありそうです。
Runeは
- セキュリティ的に安全な言語を目指している(メモリ安全、タイミング攻撃に対応)
- Pythonにインスパイアされたシステムプログラミング向け
- C/C++のライブラリとの相互運用に長けている
- ガベージコレクションやmalloc/freeではなく、参照カウントによるメモリ管理
- 静的型付け
という特徴があります。
以下、面白そうな特徴を説明します。
Python inspired
Pythonにインスパイアされたと聞くと、自分も含め多くの人が悪印象を抱くと思います。しかし、ᚣ Rune for Python Programmersを読む限り、Pythonに似ているとは感じないです。個人的にPythonの一番嫌いな文法である三項演算子もどきがありません。
def max(a, b):
return a if a >= b else b
func max(a, b) {
return a >= b ? a : b
}
上のように書きます。インデントが意味を持つこともなく、演算子オーバーロードがあったりとC++に近いところが多いです。
静的型付けなのもポイントが高いです。
Security first
Secrets
secretはRune言語がセキュリティを意識していることを象徴する特徴だと思っています。
password = secret("PaSsw0rd1")
if password == "password" { // This line is a compiler error.
throw "Don’t use \"password\" as the password!"
}
- secretと宣言された値を利用したbooleanで分岐することができず、コンパイルエラーになります。
- secretなintをインデックスとして配列にアクセスができません。
- タイミング攻撃への対処のために演算子の引数がsecretの場合、自動的に定数時間コードを生成します。
- 非secretな値とsecretな値の和はsecretになります。
- secretはデータ型であり、静的に検査できます。
ダングリングポインタへの対処
ダングリングポインタ(dangling pointer)はすでに解放された領域を指すポインタのことです。このポインタへのアクセスはメモリ破壊を起こしてしまうためメモリ安全ではありません。C言語では、プログラマがダングリングポインタへのアクセスをしないように気をつけるしかありません。Javaではガベージコレクションを実行し、他から参照されていないオブジェクトのみを解放するようにします(他から参照されていれば解放しません)。Rustではライフタイムや参照カウントを利用して対応しています。
Runeではコンテナ型の代わりに双方向のRelationshipを用いることと参照カウントによってダングリングポインタを作らないようにしています。
Relationship
class Foo(self) {
final(self) {
println "Destroying Foo ", <u32>self
}
}
class Bar(self, foo: Foo) {
foo.appendBar(self)
final(self) {
println "Destorying Bar ", <u32>self
}
}
// relation を作成する。ArrayListというRelationタイプ、他にもLinked ListやHeapqListなどがある
// https://github.com/google/rune/blob/main/doc/rune_reference.md#builtin-relations
// cascadeをつけるとFooが解放された時にその子要素であるBarも破壊されるようになる
relation ArrayList Foo Bar cascade
// Fooを作成
foo = Foo()
// Barを作成
bar0 = Bar(foo)
bar1 = Bar(foo)
// bar0を破壊する。bar0のfinalメソッドが実行される
bar0.destroy()
// fooをnullに。fooのfinalメソッドが実行される。また子要素であるbar1のfinalも実行される
foo = null(foo)
> rune arraylisttest.rn
> ./arraylisttest
Destroying Bar 0
Destroying Foo 0
Destorying Bar 1
これがrelationshipの使い方です。relationshipの概念が新鮮なものなのでめちゃくちゃ理解が大変ですね......心で理解してください......。
cascadeをつけなければ、参照カウントによって管理されます。このようにcascadeと参照カウントによってメモリ安全性が担保されます。
Structure of Arrays(SoA)
詳しくは https://en.wikipedia.org/wiki/AoS_and_SoA をみてください
データの持ち方が構造体の配列ではなく、配列をメンバに持つ構造体の形にすることです。
これにより、ある一定のメンバしか利用しないメソッドを実行したときにそのメンバの配列のみがキャッシュにロードされることで、キャッシュアクセスが高速化され、メモリ使用量が削減されています。AoSでは全ての配列がロードされてしまうためメモリを余計に利用してしまったり、キャッシュに収まらなかったりする可能性があります。
終わりに
時間の都合で内容が薄くなってしまいました......
ここで説明したのはリファレンスに書かれているため、詳しくはこちらを参照してください。また、ᚣ Rune for Python Programmersを読めば、基本的な文法や書き方が分かります。環境構築はUbuntu20.04でやりましたが、macやwindowsでは難しそうです。
GoogleはGoやDartなど便利さや読みやすさを優先した言語を開発しているイメージでした。Carbon言語は特徴的な点がなく、個人的には微妙でしたが、このRuneのようにメモリ管理や文法の点で尖った言語を開発したのは意外でした。
現状は実用から程遠いですが、どのように進歩していくのか楽しみです。
少し以前にZig言語にハマり色々作ったはいいものの、Zigのバージョンが上がり破壊的変更されたことで、コードが最新版では動かなくなってしまって悲しい思いをしたことがあるので早く安定版が出て欲しいと思っています。
Discussion