第1章 Mojo とは何か・位置づけ

1.1 この章で学ぶこと

この章で学ぶ内容は以下のとおりです。

表1-1: この章で学ぶこと

学ぶこと

ポイント

Mojo とは何か

Python に似た構文を持つ、コンパイル型の高性能言語

Python との違いの第一印象

変数・関数・構造体の書き方が Python とどう異なるか

Mojo の 3 つの強みの入口

型・所有権・Python interop のキーワードを掴む

この本の読み方

どの章で何を学ぶかの地図

1.2 Mojo とは何か

Mojo は Python に似た構文を持つ、コンパイル型のシステムプログラミング言語です。 2023 年 5 月に Modular(Modular Inc.)が公開しました。 ただし当初はクローズドソースであり、標準ライブラリは 2024 年 3 月にオープンソース化されました。 言語コンパイラ自体のオープンソース化は 2026 年秋が予定されています。

「Python の書き心地のまま、C と同等のパフォーマンスを」というビジョンで設計されており、次の 2 点を同時に実現しています。

  • Python との相互運用:既存の Python ライブラリ(NumPy、PyTorch、MLX など)をそのまま呼び出せる

  • コンパイル時最適化:型、所有権、メタプログラミングにより、実行前に機械語レベルで最適化できる

Python を知っているなら、最初の数行はそのまま読めます。 ただし一歩踏み込むと、Mojo は Python とは異なる設計の言語です。 本章ではその「入り口の似ているところ」と「踏み込んだ先の違い」を並べて紹介します。

表1-2: Mojo とは何か

Python

Mojo

実行方法

インタープリタが 1 行ずつ解釈

コンパイルして機械語を生成

型の決定

実行時(動的)

コンパイル時(静的)

メモリ管理

GC(参照カウント + サイクル検出)

所有権 + 参照カウント(決定的タイミング)

Python との相互運用

ネイティブ

Python.import_module() で呼び出せる

GPU 対応

外部ライブラリ経由

言語レベルでサポート

Python vs Mojo の特性比較

図1-1: Python と Mojo の特性比較

左(Python)はインタープリタ、動的型付け、GC(参照カウント)。 右(Mojo)はコンパイラ、静的型付け、所有権モデル、GPU 対応、高速パフォーマンス。 中央の橋(相互運用性)を経て、NumPy や PyTorch などの Python ライブラリを Mojo から直接呼び出せる。

1.3 Hello World を並べる

ここから Mojo の文法を概観していきます。 変数、関数、構造体、所有権、Python 相互運用と、各節でひとつずつ取り上げますが、この章ではあくまで「雰囲気をつかむ」ことが目的です。 細かい規則や例外は後続の各章(第6章〜第15章)で詳しく説明します。 まずはコードを眺めながら、Python との違いを感じ取ってください。

最初の Mojo コードは Python とほぼ同じに見えます。

Python:

def main():
    print("Hello, Mojo")

Mojo:

def main():
    print("Hello, Mojo")

リスト1-1: hello_mojo_minimal.mojo

def main():print(...) も構文は共通です。 しかし実行のしくみは異なります。 Python は実行時にインタープリタが 1 行ずつ解釈しますが、Mojo は事前にコンパイルして機械語を生成します。

コンパイルの流れとアセンブリは後続の章で

Mojo コードが x86-64 の機械語になるまでの経路(MLIR → LLVM IR → ネイティブバイナリ)は第2章で解説します。 実際の逆アセンブル出力を 1 命令ずつ読む演習は、第5章「最小サンプル main のアセンブリを読む」で扱います。

1.4 変数と型

Python では変数に型を書きません。 Mojo では var で宣言し、型を付けます。

Python:

x = 42
name = "Alice"
pi = 3.14159

Mojo:

var x: Int = 42
var name: String = "Alice"
var pi: Float64 = 3.14159

var y = 3.14   # 型推論(Float64 と推論される)

型は省略して推論させることもできます。 コンパイル時定数には alias を使います。

alias MAX_SIZE = 1024     # コンパイル時に確定する定数
alias PI = 3.14159265358979

alias は Python の CONSTANT = 1024(慣例的な大文字)と似ていますが、Mojo ではコンパイラが値をその場に展開します。 実行時に変数を読みにいく処理が不要になります。

表1-3: 変数と型

Python

Mojo

変数宣言

x = 42(型なし)

var x: Int = 42

型推論

常に動的

var x = 42 でコンパイル時推論

コンパイル時定数

X = 42(慣例、強制なし)

alias X = 42(コンパイラが展開)

再代入

常に可能

var で宣言した変数のみ可能

詳細は第6章「概要・関数・変数」で扱います。

1.5 関数の定義

Mojo の関数定義は Python とよく似ています。

Python:

def add(a, b):
    return a + b

def greet(name: str) -> str:   # 型ヒント(任意)
    return f"Hello, {name}"

Mojo:

def add(a: Int, b: Int) -> Int:
    return a + b

def greet(name: String) -> String:
    return "Hello, " + name

Python との大きな違いは型アノテーションが実質必須である点です。 Python では型ヒントは任意ですが、Mojo ではコンパイラが型を利用するため、引数と戻り値の型を明示的に書きます。

詳細は第6章で扱います。

1.6 構造体(struct)

Python では class でデータと振る舞いをまとめます。 Mojo では struct を使います。

Python:

class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    def distance(self) -> float:
        return (self.x**2 + self.y**2) ** 0.5

p = Point(3.0, 4.0)
print(p.distance())   # 5.0

Mojo:

struct Point:
    var x: Float64
    var y: Float64

    def __init__(out self, x: Float64, y: Float64):
        self.x = x
        self.y = y

    def distance(self) -> Float64:
        return (self.x**2 + self.y**2) ** 0.5

def main():
    var p = Point(3.0, 4.0)
    print(p.distance())   # 5.0

リスト1-2: point_distance.mojo

見た目は Python の class に近いですが、重要な違いがあります。

表1-4: 構造体(struct)

Python class

Mojo struct

メモリの配置

ヒープ(参照型)

スタック(値型)

フィールドの型

実行時に決まる(動的)

コンパイル時に確定(静的)

継承

多重継承あり

なし(trait で振る舞いを宣言)

__init__ の第1引数

self

out self(所有権の初期化を表す)

struct値型です。 代入するとコピーが作られます。 参照を渡したいときは所有権修飾子(次節)を使います。 詳細は第9章「struct・参照型・パッケージ」で扱います。

1.7 所有権の雰囲気

Mojo では関数の引数に「この値をどう受け取るか」を修飾子で明示します。

def show(read data: List[Int]):
    # data を読むだけ。コピーしない
    print(data[0])

def append_zero(mut data: List[Int]):
    # data を変更する。呼び出し元に反映される
    data.append(0)

def consume(var data: List[Int]):
    # data の所有権ごと受け取る
    data.append(99)
    # この関数を抜けると data は解放される

def main():
    var nums: List[Int] = [1, 2, 3]
    show(nums)             # 1
    append_zero(nums)      # nums の末尾に 0 を追加
    print(nums[len(nums) - 1])   # 0
    consume(nums^)         # 所有権を移譲して渡す

リスト1-3: ownership_conventions.mojo

表1-5: 所有権の雰囲気

修飾子

意味

Python との対応イメージ

read

読み取り専用の参照

引数をそのまま受け取る(変更不可)

mut

変更可能な参照

リストを受け取って中身を変更する

var

所有権を移譲して受け取る

(Python には対応概念がない)

Python には「この引数は変更しない」という宣言がありませんが、Mojo ではコンパイラが強制します。 うっかり変更するとコンパイルエラーになります。 詳細は第10章「値・所有権・ライフサイクル」で扱います。

1.8 Python との相互運用

Mojo から既存の Python ライブラリを呼び出せます。

from std.python import Python

def use_numpy() raises:
    var np = Python.import_module("numpy")
    var arr = np.array(Python.list(1.0, 2.0, 3.0, 4.0))
    print(arr.mean())   # 2.5

def main() raises:
    use_numpy()

リスト1-4: numpy_mean.mojo

Python.import_module() で Python のモジュールを PythonObject として受け取り、そのままメソッドを呼べます。 NumPy、PyTorch、MLX など、Python のエコシステムをそのまま活用できます。

速くなるのは「Mojo で書いた部分」だけ

Python ライブラリを呼び出す部分は Python のコードがそのまま動いています。 Mojo が高速なのは Mojo で書いたコードのみです。 「Mojo から NumPy を呼ぶだけで速くなる」わけではありません。 詳細は第13章「Python 相互運用」で扱います。

1.9 この本の読み方

本書は 3 部構成です。 各章で扱う内容と対応する Mojo の概念を示します。

第1部:Mojo を知る(第1章〜第5章)

タイトル

内容

第1章

Mojo とは何か・位置づけ

← 本章。Python との比較で全体像を掴む

第2章

作者・誕生の背景・MLIR

なぜ Mojo が生まれたか、MLIR の役割

第3章

設計思想

所有権・compile-time・interop の 3 本柱

第4章

Python との比較・入口

Python 経験者がはまる落とし穴

第5章

最小サンプルのアセンブリを読む

hello_mojo_minimal.mojo を機械語レベルで追う

第2部:言語仕様(第6章〜第15章)

タイトル

内容

第6章

概要・関数・変数

def/fnvar/alias、型アノテーション

第7章

コンパイル結果のアセンブリを読む

前章のコードの逆アセンブル解析

第8章

型・演算子・制御・エラー

Int/Float64/SIMDif/for、エラー処理

第9章

struct・参照型・パッケージ

値型 structtrait、モジュール構成

第10章

値・所有権・ライフサイクル

read/mut/var__del__、RAII

第11章

メタプログラミング

comptime if/for、ジェネリクス、パラメータ

第12章

ポインタ・GPU・レイアウト

UnsafePointer、GPU スレッドモデル、テンソルレイアウト

第13章

Python 相互運用

PythonObject、境界の越え方、速度の誤解

第14章

Pythonista 向けの読み替えとコード例

Python の書き方を Mojo に変換するパターン集

第15章

相互運用の実例・導入判断・まとめ

NumPy 連携の実例、Mojo を使うべき判断基準

第3部:microgpt 実装(第16章〜第31章)

タイトル

内容

第16〜22章

microgpt の解説

Karpathy の miniGPT 実装を Python で読む

第23章

microgpt.py を Mojo で書き直す

Tape・SoA・所有権を活かした Mojo 実装

第24〜28章

MAX での高速化

MAX Graph API で推論を最適化

第29〜30章

PyTorch・MLX 版

MPS・Unified Memory を活かした実装

第31章

まとめ

全バリエーションの速度比較と Mojo の立ち位置

推奨ルート:

  • Python は使えるが Mojo は初めて → 第1〜4章を読み、第6、8、9、10章を順に進む

  • アセンブリやコンパイラに興味がある → 第5、7章を重点的に

  • すぐに ML の実装を動かしたい → 第16章から始め、詳細は必要に応じて参照