Mojo🔥とは
PythonのシンプルさとRustのスピードとメモリの安全性を組み合わせた、新しいプログラミング言語。
Pythonの35000倍速いとされており、Pythonの弱点である「遅さ」を補うと期待されている。また、書き方もPythonと似ているので移行もしやすいです。
そんな言語が2023年10月19日より、Appleシリコン搭載Macに対応したとのことで、早速触ってみました。
本家のドキュメントはここにまとまっています。
Mojo🔥のセットアップ
ターミナルやVSCodeで使えるようにセットアップが必要です。
以前記事にまとめたので、そちらをご覧ください
Mojo🔥の基本
主にPythonとの比較をしながら書いていきます。
前提
・Mojo🔥はコンパイル言語であり、他のコンパイル言語たち同様、エントリーポイントとして main()
が必要
・Pythonのすべての構文とセマンティクスをサポート(Pythonの書き方でも実行可能)
変数 var, let
var x: Int = 1
let y: Int = 2
varは可変な変数、letは不変な変数の定義に用います。Intなどの型タイプは省略も可能です。
関数 : def → fn
Python:
def main():
x = 1
x += 1
print(x)
Mojo🔥
fn main():
var x: Int = 1
x += 1
print(x)
ただ、defのままでも実行できます。fnにすると型の安全性を強制するようにできます。
なので、fnの中でvarなどを削除するとエラーになります。
また、関数に引数や返り値を設定する場合は、型タイプを明記する必要があります。書かないとエラーが出ます
・OKな例
fn add(x: Int, y: Int = 1) -> Int:
return x + y
・ダメな例
fn add(x, y):
return x + y
引数のデフォルト値の設定方法はPythonと同じです
borrowed と inout と owned
関数の引数はimmutableな変数(変更不可)として読み取られます。
従って、以下はエラーになります
fn add(x: Int, y: Int) -> Int:
x += 1
return x + y
borrowedはそのことを明記する(保証する)役割らしいです
→関数がそのオブジェクトの所有権を持たず変更しないことを保証している
※borrowedは、特に何も書いていない上のfn add()
と同じ挙動になります。
→デフォルトでborrowedが省略されていると考えれば良い?
fn add(borrowed x: Int, borrowed y: Int) -> Int:
return x + y
さらに、inoutというものがあります。
fn add(inout x: Int, inout y: Int) -> Int:
return x + y
inoutとして設定すると、引数をmutableな変数(変更可能)とできます。そして関数内部で加えられた変更は外部にも影響します。
fn main():
var a = 1
var b = 2
let c = add_inout(a, b)
print(a)
print(b)
print(c)
fn add_inout(inout x: Int, inout y: Int) -> Int:
x += 1
y += 1
return x + y
これを実行すると、
2
3
5
となります。aは元々1, bは2でしたが、fn add_inout()
の中で1ずつ足されたので、それぞれ2, 3になっています。
ownedは、引数をmutable(変更可能)とするものの、関数の外には影響を与えないとするものです。
先ほどのコードでinoutをownedに変更すると、
fn main():
var a = 1
var b = 2
let c = add_inout(a, b)
print(a)
print(b)
print(c)
fn add_inout(owned x: Int, owned y: Int) -> Int:
x += 1
y += 1
return x + y
結果は
1
2
5
となって、aもbも変更されていないことがわかります。
クラス class → struct
完全に静的なclassのようなもので、メソッド、フィールド、オーバーロード、デコレータなどを定義できます。
struct MyPair:
var first: Int
var second: Int
fn __init__(inout self, first: Int, second: Int):
self.first = first
self.second = second
fn dump(self):
print(self.first, self.second)
fn main():
let mine = MyPair(2, 4)
mine.dump()
第一引数にself
を渡すところや__init__()
を定義するところはPythonのclassと同じです
出力は
2 4
となります。Pythonのclassと違うところとして、__init__()
で定義するself.first
やself.second
は事前にvar first: Int
と定義しておく必要があることが挙げられます。これがないとエラーになってしまいます。
error: 'MyPair' value has no attribute 'first'
self.first = first + 1
また、__init__()
の引数はinout
として渡します。
これは、イニシャライザはオブジェクトの初期化を担当する部分であり、このメソッド内でself
オブジェクトを変更するので引数はmutableでなければなりません。したがってborrowed
は適しません。
さらに、self
オブジェクトを変更してこのメソッド外においてもその変更を適用させたいのでowned
も適しません。したがって、inout
とする必要があります。
まあ、一言で言えば、「selfはインスタンスを示すので、__init__で行われるインスタンスの初期化をクラス内の他のメソッドでも適用させたいため、inoutとする」ということです。
Pythonライブラリを使う Python integration
ドキュメント通りのコードを実行するとエラーが出る。。。
numpyをうまく読み込めないっぽい。色々調べたけど治らず。
まだ情報が少ないからこういう問題が発生した時の対処が大変です。。
最後に
まだまだMojo🔥は発展途中の言語で、ドキュメントにもそのことは繰り返し書かれていました。Pythonに似ていて書きやすいので今後の発展が楽しみです。
次はPythonとの速さの比較の記事を書こうと思っているので、読んでもらえたら嬉しいです!
また、X(Twitter)では日々データサイエンスやAIに関する勉強記録・情報発信をしています。フォロワーはもうすぐ5500人に到達します。
少しでも刺激になるようなことを発信できたらいいなと思っているので、気になった方は見てみてください🔥
では👋