Squeak 5.3-jaのご紹介

#はじめに

このたび久しぶりに[日本語版Squeak](https://ja.osdn.net/projects/squeak-ja/)を更新しました。なんと8年ぶりです!

この場を借りてインストールの仕方、動かし方などを書いてみたいと思います。

## Squeakとは?

Smalltalkのオープンソース処理系の一つです。1997年ごろから開発が始まりました。
2021年となった今でも、定番のSmalltalk処理系として、[Pharo](https://pharo.org/)と人気を2分した形で使われています。

「混じりけなしの純粋な」オブジェクト指向言語は実は世の中にあまり存在しないので、そういったものを体験してみたい方には面白い環境だと思います。

誕生の経緯などは[Squeak](https://squeak.org)のデビュー当時に私が書いた["What's "Squeak"?"](http://www.mars.dti.ne.jp/~umejava/smalltalk/squeak/) をご覧ください。時空を超えるプログラミング環境といったことが書いてあります。

また、各種LT用に作ったスライドもあるのでよろしければどうぞ。

- [「Why Smalltalk - Smalltalkを今の時代にやってみる理由」](https://www.slideshare.net/umejava/why-smalltalk)
- [「Smalltalkだめ自慢」](https://www.slideshare.net/umejava/smalltalk-38297600)

# Squeak5.3-ja着手に至るいきさつ

普段は[仕事でPharoばかりを使っている](https://www.slideshare.net/umejava/revealing-allstocker)のですが、ある時「DandelionをSqueak 5.3で動かすにはどうすれば良いですか」といった問い合わせを、海外の会社からいただきました。

[Dandelion](http://www.mars.dti.ne.jp/~umejava/smalltalk/stClasses/dandelion/index.html)とは、私が若い頃に作った、Smalltalkのコードを分析して出力するためのフレームワークです。Javadoc風のhtmlや、UMLのモデリングツールに読み込ませるための[XMI](https://ja.wikipedia.org/wiki/XML_Metadata_Interchange)など、さまざまなフォーマットに対応しています。

懐かしさもあるし動かしてみたいと思ったのですが、日本語も含めDandelionの出力結果を見るには、そもそも最新のSqueakにちゃんとした日本語環境が整っていないという問題がありました。
となるとSqueakの日本語環境も5.3に対応したほうが良かろうとなり、今回のレストアに到ったというわけです。(実はDandelionの修正よりもよほど手間がかかりました...)

日本語化というと、翻訳やフォントなどのリソースを用意すれば終わり、と思われるかもしれませんが、Smalltalkはそれ自体がOSのようなものなので、実際はもっと複雑です。Squeakではシングルバイト圏の開発者がほとんどということもあり、フォントのレンダリングや、IMEとの接続など、細かなところが微妙にマルチバイト環境で動かなかったり変な動作をしたりします。
日本語版作成にあたっては、そうした問題へのパッチを一通り作成した上で、翻訳などのリソースを適用するということをしています。

# All-in-one イメージのダウンロード

さて前置きが長くなりましたが、そろそろ動かし方に入ります。
暴れネズミとも言われるSqueakのダイナミックさを知るには、実際に動かしてみるのが一番です。

OSDNの[日本語版Squeakプロジェクト](https://ja.osdn.net/projects/squeak-ja/)のページから、"all-in-one 5.3"のセクションを選んで[Squeak5.3-19459-64bit-All-in-One-ja.zip](https://ja.osdn.net/projects/squeak-ja/releases/76341)をダウンロードします。
あるいはGitHubの[releases](https://github.com/mumez/squeak-ja/releases/tag/v5.3.0)から直接ダウンロードしても良いでしょう。

このzipには、Windows, macOS, Linuxの各種プラットフォーム用のVMと、VM上で動く仮想イメージ(VI)が同梱されています。実はVMware, Docker等が広まるずっと前から、Smalltalkはイメージベースの環境を提供していました。作業の途中であっても好きなタイミングでイメージを丸ごとスナップショットし、OSの区別なく復元できるのです。

zipを展開すると、以下のようなファイル構成になっています。

- ReadMe-ja.txt
- Squeak5.3-19459-64bit-All-in-One-ja.app
- squeak.bat
- squeak.sh

`Squeak5.3-19459-64bit-All-in-One-ja.app`はWindowsやLinuxではディレクトリですが、macOSからはバンドルとして1ファイルのように見えます。この中に、VMやVI、設定ファイルなどが納められています。

# All-in-one イメージの起動

Squeakを起動するには、Windowsであれは`squeak.bat`、Linuxであれば`squeak.sh`を使います。macOSの場合はセキュリティの問題から、まず`Squeak5.3-19459-64bit-All-in-One-ja.app`を「アプリケーション」フォルダ下に移動させる必要があります。その後、メニューで「開く」を選択し起動を許可すると、以後はダブルクリックで開くようになります。
![スクリーンショット 2021-12-21 22.14.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/8357622c-c775-b451-0aa0-e9fbd8c5bf76.png)

以下のような画面が立ち上がります。
![2021-12-03 16_58_13-Squeak 5.3 (64 bit).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/ade68b61-3917-ce3f-8ba3-8710c7a6ae0a.png)

Smalltalkに存在するものは、ウィンドウやプロセス、数字、文字列なども含め、全てがオブジェクトです。これらのオブジェクトに向かってメッセージを送っていくというのが、Smalltalkでのプログラミングスタイルになります。

# メッセージを送ってみる

試しに「ワークスペース」を開いて以下のように打ってみましょう。

```smalltalk
Smalltalk allClasses explore. 
```

デスクトップをクリックするとメニューが出現するので、"ワークスペース"を選択します。

![2021-12-07 23_19_29-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/5c63219b-b4af-3865-5ff8-b9b8ad7df6a5.png)


ワークスペースはコードのスニペットを書いて実行するためのツールです。今風に言うとPlaygroundですね。

文字列をハイライトしてメニューから"式を評価(d)"を選びます。(dはショートカットの意味です。WindowsであればControl-d, MacならCommand-dで評価することもできます。)

![2021-12-07 23_27_09-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/de169342-fd83-0677-c76e-5333933ff6f3.png)

これでSmalltalkに存在するクラス群を一覧することができます。3000近いクラスが既にシステム内に存在していることがわかります。

2962番目の`Object`を選択した状態で、下部に`self browse`と入力し"式を評価(d)"してみましょう。

![2021-12-08 23_15_54-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/322bd139-f2f0-de27-b795-725ecf85030a.png)

今度は`Object`クラスについてのシステムブラウザが開きます。システムブラウザの下半分はコードペインと呼ばれ、リストの選択に応じて、クラス定義や、メソッドの内容が表示されるようになっています。

![2021-12-08 23_26_22-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/4e21f156-7b17-f678-58a5-72f36998f0d9.png)

クラスベースでプログラミングをする際には、主にこのシステムブラウザを使います。詳しい使い方はここでは扱いませんので、後述の参考文献[「自由自在Squeakプログラミング(PDF版)」](https://swikis.ddo.jp/squeak/13)などを見てもらえればと思います。

次にワークスペースに

```smalltalk
Object allSubInstances size.
```

と打ち、今度はただの評価でなく、"式を表示(p)"(Control-pまたはCommand-p)してみてください。

システム内に存在するほぼ全てのオブジェクト群を数え上げる処理なので、結構時間がかかります。

`Object`は、Smalltalkのクラス階層の最上位にあるクラスです(更に上に`ProtoObject`というクラスになりきれていないクラスがありますがここでは割愛します)。`allSubinstances`というメッセージをクラスに送ることで、クラスの全てのサブインスタンスを得ることができます。
サブインスタンスとは、当該クラスとそのサブクラス群から生じた全てのインスタンスを指します。そのため、システム内のほぼ全てのオブジェクトが、この簡潔なメッセージ式で取得できるというわけです。

Smalltalkの環境下では常にオブジェクトが生まれたり死んだりしているので、実行する度に数は変わるでしょう。私の場合は`1013245`と表示されました。100万以上のオブジェクトが、あなたからのメッセージ送信を待っているのです!

![2021-12-16 23_31_43-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/33c0bc44-06b9-de0b-db41-61fe3e5f91f1.png)

# パッケージのインストール

では、もう少しパッケージなどを入れて、より便利にしていきましょう。Squeak 5.3-jaには、お勧めパッケージを追加するためのワークスペースが用意されています。

'ReadMe-Packages'とタイトルバーに書かれたワークスペースがデスクトップ左上のほうに隠れているので、タイトルバーをクリックして中身を見てみましょう。

![2021-12-08 23_37_32-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/e7d47fd7-5e6c-0179-1625-2b9fe80563fe.png)

TekkaとFileManの2つのパッケージを入れるためのコードが、解説とともに書いてあります。

## Tekkaを入れる

[Tekka](https://github.com/tomooda/tekka/)は小田さん([@tomooda](https://twitter.com/tomooda))が開発された、SqueakやPharoで動作する、SKK風のシンプルな日本語入力メソッドライブラリです。入力モードがないところが特徴で、Control-j(MacではCommand-j)をすると、日本語変換できそうな部分を選んで変換するようになっています。

ワークスペースの下記の行をハイライトして、"式を評価(d)"します。

```smalltalk
JaExPackageUtilForSqueak loadTekka. 
```

途中で変換用辞書をダウンロードするかダイアログで聞かれますが「はい」を選びます。これでTekkaが入りました。

モードレスな入力を試してみましょう。

`### Tekka`と書いてある末尾にカーソルを持ってきて、Control-j(MacではCommand-j)と何度か打ってみてください。

![2021-12-08 23_48_06-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/f527d41f-00a5-6378-2d93-d0c09926a928.png)
![2021-12-08 23_49_05-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/23e41fd3-9e6e-961c-90c8-13d390d971e1.png)
![2021-12-08 23_49_29-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/c05b4ea8-a69f-2c95-b175-1103d9821023.png)

'てっか'、'鉄火'、'テッカ'と文節が変化していきますね。こうして日本語入力を行っていくのです。Squeak 5.3では、プラグインの不具合で、ネィティブのIMEでインライン入力ができなかったりするので、Tekkaがあると重宝します。

## FileManを入れる

では、次に[FileMan](https://github.com/mumez/FileMan)を入れてみましょう。FileManとは、Smalltalk処理系やOSの違いを吸収してファイル操作を簡単に行うためのライブラリです。いろいろなSmalltalkでファイル操作の書き方が違ってしまうのが嫌だなと思っていた私が開発しました。

```smalltalk
JaExPackageUtilForSqueak loadFileMan.
```

をハイライトして、"式を評価(d)"で入ります。

単純な例として、「現在のディレクトリ下にある1Mバイト以上のファイルを、再帰的に取り出して表示する」というのをやってみたいと思います。

以下のコードをワークスペースに貼り付けて、全体を選んで"式を評価(d)"します。

```smalltalk
Transcript open. "Transcriptを開く"

dir := '.' asDirectoryEntry. "ディレクトリを取得"
minSize := 1024 * 1024. "絞り込み用のファイルサイズを指定"
dir allFilesDo: [:file | "ディレクトリ以下のファイルを再帰的に列挙"
	file fileSize >= minSize ifTrue: [
		"Transcriptにファイルサイズ、ファイル名の配列として結果を表示"
		Transcript cr; show: {file fileSize. file name}
	]
].
```
`Transcript`とは、プログラムの実行結果を表示するために使うツールです。

`'.' asDirectoryEntry`で、現在のディレクトリを表すオブジェクトが取得できます。これに対して、`allFilesDo:`のメッセージを送って、ディレクトリ以下のファイルを再帰的に辿るようにします。引数はブロッククロージャになっており、各ファイルが引数として渡され実行されていきます。

ファイルのサイズが1M以上だった場合は、Transcriptに結果を出力します。まず`cr`で改行させ、その後で`show:`を送って配列を表示させています。配列の内容は、ファイルサイズ、ファイル名となっています。

実行すると以下のようになりました。階層の深くにあるフォント関連のファイル(*.ttf)などもちゃんとリストアップされていますね。

![2021-12-09 12_38_10-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/2aeb3dda-3731-8753-71d0-370ca4a23506.png)

より詳しい使い方については[FileManで楽々ファイル操作](https://www.slideshare.net/umejava/fileman)をご覧ください。ちょっと前のプレゼン資料ですが、インターフェースは変わっていないので内容的には問題ありません。

## Dandelionを入れる

では最後に、今回のレストアのきっかけとなった、[Dandelion](https://github.com/mumez/Dandelion)を入れてみることにします。

今度は"SqueakMap Package Loader"というツールを使います。デスクトップメニュー「開く...」から「SqueakMapカタログ」を選ぶと立ち上がります。

![2021-12-09 22_00_30-Squeak 5.3 (64 bit).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/d572eb56-313c-4eb8-7d4a-92f919677e36.png)

メニュー選択が面倒という方は、ワークスペースに以下のメッセージ式を貼り付け、"式を評価(d)"しても良いでしょう。

```smalltalk
SMLoaderPlus open.
```

初回は何も表示されていない状態で開くので、「更新」ボタンを押してください。
インストール可能なパッケージのリストが、ネットワーク経由で取得されていきます。

![2021-12-09 22_09_36-Squeak 5.3 (64 bit).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/34d22ad4-b12a-f177-9779-190e7d374c88.png)

SqueakMapとは、パッケージを集約したカタログのようなものです。SqueakのパッケージはGitHubをはじめさまざまなリポジトリに置かれているのですが、それらをまとめて表示してくれるのであちこち探す手間が省けます。

![2021-12-09 22_11_52-Squeak 5.3 (64 bit).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/27e29e14-5965-fd10-1e49-322136a60a9b.png)

リストからDandelionを選択し、右クリックして「インストール」を選択します。

パッケージのロード中にどの出力フォーマット機能を入れるかを聞いてきます。これからHTMLでの出力を試すので最低限HTML出力機能は入れるようにします。

![2021-12-09 22_15_27-Squeak 5.3 (64 bit).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/82914214-9942-e418-4205-a114cafe5799.png)

ではHTMLでのドキュメントを生成してみましょう。対象とするのは、FileManのパッケージとします。

以下をワークスペースに貼り付けて"式を評価(d)"してください。

```smalltalk
dandelion := DlDandelionSystem new.
dandelion setPropertyArray: {{#systemTitle. 'FileMan'}}.
dandelion analyzeMatches: 'FileMan-*'. "FileMan-で始めるパッケージ群を解析"
dandelion outputHtml. "HTML形式でドキュメント出力"
```

コードの解析が行われて、HTML形式で出力が行われます。

![2021-12-10 23_44_32-Squeak 5.3 (64 bit).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/2123f894-330a-4151-1508-57a5dc248d8b.png)

リソースディレクトリ(`Squeak5.3-19459-64bit-All-in-One-ja.app/Contents/Resources`)に、`dendelionOutput`というサブディレクトリが生成されているので、`index.html`をWebブラウザで開いてみましょう。(Macの場合は`Squeak5.3-19459-64bit-All-in-One-ja`を選択して「パッケージの内容を表示」すると`Contents`フォルダが表示されます。)

![2021-12-11 00_50_07-FileMan Top page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/82b0677e-be19-5aa0-b144-17a9d074b866.png)

パッケージ内に含まれるクラス一覧、コメント、メソッド一覧などが、Javadocっぽいフォーマットで出力されていることが確認できます。

日本語の出力ができるかも見てみましょう。先ほどワークスペースで実行したコードをメソッド「FileManの出力例」として、サンプルコード格納用の既存のクラス`DlDandelionExample`に定義することにします。

普段はシステムブラウザからメソッドを追加するのですが、今回はツールの解説を省略しているので、ワークスペースから直接定義します。以下のコードをワークスペースに貼り付けて、"式を評価(d)"してください。

```smalltalk
code := 'FileManの出力例
  | dandelion |
  dandelion := DlDandelionSystem new.
  dandelion setPropertyArray: {{#systemTitle. ''FileMan''}}.
  dandelion analyzeMatches: ''FileMan-*''.
  dandelion outputHtml.
'.

"上記のコードをDlDandelionExampleの'examples-html'プロトコルのクラスメソッドとして定義"
DlDandelionExample class compile: code classified: 'examples-html'.
```

初回のメソッド定義時にはイニシャルを聞かれます。適当に入れておきましょう。

![2021-12-11 23_47_14-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/dbab4b91-fe61-68bf-2d09-f914d085ad85.png)

作成されたメソッドをクラスブラウザから確認してみます。ワークスペースに以下を追加して、"式を評価(d)"で開きます。

```smalltalk
ToolSet browse: DlDandelionExample class selector: #FileManの出力例.
```
普段は日本語名のメソッドを作ることはないので、違和感がありますが、きちんと定義されていますね。

![2021-12-11 23_50_41-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/650b28eb-eeba-e04f-fa14-6b1b520c48d0.png)

では、再びHTMLを生成してみます。'Dandelion-facade'カテゴリを対象に出力したいので、以下のコードで"式を評価(d)"します。

```smalltalk
DlDandelionSystem analyzeOutputMatches: 'Dandelion-facade*'.
```
Webブラウザをリロードし`DlDandelionExample`を辿っていくと、バッチリ出力されていました。

![2021-12-11 23_32_14-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61787/2dd83fb9-08bb-32e5-8cf5-07abff132bed.png)

メソッドの追加自体をメッセージ送信で行ってしまうような、メタプログラミング的なものが簡単に書けるのも、Smalltalkの大きな魅力の一つです。

# Happy Squeaking!!

さて、パッケージもいろいろと入りましたし、後は楽しくプログラミングといきましょう。

少し古いSqueakで解説していますが、私が昔に書いた、[「自由自在Squeakプログラミング(PDF版)」](https://swikis.ddo.jp/squeak/13)が参考になると思います。
細かなツールやライブラリの違いなどはありますが、Smalltalk自身は予約語が6つのミニマルな言語なので、本質は何も変わっていません。問題なく読み進められるでしょう。

ボリューム少なめが良い方は、よりオブジェクト指向入門にフォーカスした"[Happy Squeaking!!](https://www.ogis-ri.co.jp/otc/hiroba/technical/Squeak/squeak.html)"という記事もあります(この節のタイトルと同じですね)。
また、Webアプリ作成に特化した["SeasideへGO!!"](https://www.ogis-ri.co.jp/otc/hiroba/technical/seaside/)という記事もあるので、お好みに合わせてどうぞ。

少し覚えると言語自体を自分で拡張させていくことができるようになるというのも、Smalltalkの大きな醍醐味です。エイプリルフール向けに作った["SmallTalk"(Tが大文字)](http://smalltalk.smalltalk-users.jp/)という、変な機能てんこ盛りのパロディSmalltalk実装もあるので、こちらも参考までに。

プログラミングの楽しさは、その全能感にあると思います。皆さんもぜひ100万を超えるオブジェクト達と戯れ、操ってみてください!