Mojo について調査する

0.始めに

Python の使い勝手とCの性能を持ったと言われるプログラミング言語「Mojo」について調査してみました。(この記事の内容は2024年2月時点です。)

Pythonのスーパーセット(javascriptとtypescriptの関係)として設計しているためPythonを知っていると分かりやすいようです。
私が過去に作成した記事も良ければ見てください。

現在は、Mac、Linux、WSLで使用可能ということですが、私のPCはWindowsなのでWSLで試したいと思います。
(ちなみにブログにWindowsもサポート予定と書いてあったので、いずれ対応されるものと思います。本格的な確認はそこから始めようと思ってます)
VScodeにMojoの拡張機能もすでに存在するようです。ただWindowsに導入した場合は特に機能しません。

Mojo拡張機能

WSLへのインストールは以下のコマンドで可能です。

1)Ubuntu ターミナルで Modular CLIをインストール
curl https://get.modular.com | sh - &&
modular auth mut_31664957ab454f00873247b5c1981163
2) Mojo SDKのインストール
Install the Mojo SDK
3)Pathを通す
export MODULAR_HOME="$HOME/.modular"
export PATH="$MODULAR_HOME/pkg/packages.modular.com_mojo/bin:$PATH"

1.色んな実行方法

1)mojo コマンドで実行(終了時は:quit)
mojo
>print("Hello, world!")
Hello, world!

2)ファイル実行
「xx.mojo」や「xxx.🔥」と名前を付けたファイルを実行する。
実行時)mojo hello.mojo
>Hello World!

3)実行ファイルに変換
実行時)mojo build hello.mojo
実行ファイルに変換し以下のコマンドで実行
./hello

2.基本的な文法事項

以下のドキュメントを参考にしています。

1)関数

関数はfnとdefで宣言できますが、fnは型チェックとメモリセーブであることを必要とし、def はそれらを必要としないPythonと同じ性質のもののようです。
fn は面倒な代わりにコンパイル時にチェックしてくれるという利点があります。
現時点では、エントリーポイント(処理の始まり)としてmain()が必要で、それは def でも fn でもよいようです。

def main():
    print(def_greet("田中"))
    print(fn_greet("鈴木"))

def def_greet(name):
    return "Hello, "+name+"!"

fn fn_greet(name:String)->String:
    return "Hello, "+name+"!"

実行結果
'Hello, 田中!'
Hello, 鈴木!

2)引数について

引数について、Mojoでは「値」で渡すか「参照」で渡すかを指定できるようです。
デフォルトでは def の場合「値」で渡し、fnの場合「不変参照」で渡します。
ちなみに無駄なコピー(特に情報が大きいデータ)を作らない、使用しなくなったデータを破棄するといったことは、プログラミングの性能に関わる結構大事な部分です。
可変参照等を含めて指定する場合は以下のように記載します。

fn add(inout x: Int, borrowed y: Int):
    x += y

fn main():
    var a = 1
    let b = 2
    add(a, b)
    #a
    print(a)
    #b
    print(b) 

実行結果
3
2

inout は可変参照なので引数に入った値を変更できます。(aは変更されている)
borrowed は不変参照なので、引数に入った値を変更できません。(bは変更されていない)
他にもowned がありこれは所有権を関数が持つことになるものです。
(変数^で引数として渡すとデータのコピーをすることなく渡し、変数の寿命が付き、^なしで渡すと値のコピーが渡されます。)
defではownedがデフォルト、fnではborrowedがデフォルトになっています。

3)変数

変数が不変なときは let 変更したいときは var を使い、任意で変数の型を追記できます。
ひとつ前のコードで var と let の例を示しているので、型は以下のように追記します。

var a:Int = 1

def 内の変数はデフォルトでvar, fn内の変数はletのようです。

4)構造体

Python のクラスは将来的にサポートする予定のようですが、 Mojo では構造体にメソッドやフィールドの機能を持たせます。
コード例を以下に記載します。
長方形に関する構造体を作成して、面積を出力しています。

struct Rectangle:
    var height: Int
    var width: Int
    
    fn __init__(inout self, height: Int, width: Int):
        self.height = height
        self.width = width

    fn area(self):
        print(self.height*self.width)


fn main():
    let rect=Rectangle(2,4)
    rect.area()

実行結果>8

またトレイトと呼ばれる他の言語で言えばインターフェースのような機能があります。
トレイトをどう利用するかは難しいですが、以下のような例があると思います。
例)上の例で長方形、正方形、円みたいな色々な構造体を作る必要があるとします。
全てに共通して面積を出力するメソッドを持っていて、その面積を使って何かをする関数を考えているとします。
その時に正方形や円それぞれ分けて考えるのは面倒なので、トレイトを使って関数を作ることで一つ作れば良くなるという考え方です。

trait Figure:
    fn area(self): ...

struct Rectangle(Figure):
    var height: Int
    var width: Int
    
    fn __init__(inout self, height: Int, width: Int):
        self.height = height
        self.width = width

    fn area(self):
        print(self.height*self.width)

fn fun_with_traits[T: Figure](x: T):
    x.area()


fn main():
    let rect=Rectangle(2,4)
    fun_with_traits(rect)

5)ブロックや文

基本的にはPythonと同じようです。

fn loop():
    for x in range(5):
        if x % 2 == 0:
            print(x)

fn main():
    loop()

>実行結果
0
2
4

以下のように「.(ドット)」で改行するのも許容されるようです。

def print_hello():
    text = String(",")
          .join("Hello", " world!")
    print(text)

6)コメント

動作に関係ないコメントは以下の方法で記載できます。
1行コメント:#
複数行コメント:
"""
A
B
"""

3.全体的な感想

全体的な印象としては、Python + Rust のイメージです。(Rustより所有権の部分が見えやすいようにも思います。)
まだVersion も1.0になっておらず、リストや辞書型のような機能もまだ未実装なようです。
性能は正直比べにくいので何とも言えませんが、Pythonを静的に型付けすることができ、実行形式にできるのであればそれだけでも利点はあると感じています。
拡張機能も活きないので、Windows版がリリースされて、パッケージ管理、実行ファイル出力、単体テストに関するエコシステムがそろってきたら本格的に触ってみたい楽しみなプログラミング言語だなと感じています。



この記事が気に入ったらサポートをしてみませんか?