書いて覚えるSwift入門

第22回謹賀新言語

あらためてSwiftを始めませんか?

本稿を執筆しているのは(とくに政治的に)波乱含みどころか波乱しかなかった感のある2016年末ですが、皆さんに届くころには新年気分も過ぎ、2017年という表記に読者の皆さんも慣れているころだと思います。新言語を学びはじめるにはちょうどいいころあいかと。

本連載はこれまで連載ということもあって、すでにSwiftという言語には本連載開始時点から慣れ親しんでいる読者を対象にしてきたのですが、本誌をはじめて手にとった方、つまり本誌にはある程度の理解はあるけれどもSwiftはまだ知らないという読者に向けて、Swiftとはどんな言語なのかを紹介するころあいでしょう。

安全、高速、豊かな表現力

いったいSwiftとはどういう言語なのでしょう? 公式サイトのAbout Swiftには3つの特長が掲げられています。

  • 安全(Safe)
  • 高速(Fast)
  • 豊かな表現力(Expressive)

Swiftは静的型を採用していますが、これは安全性に寄与しています。たとえばvar i = 42Int型として初期化されたものにi = "one"とStringを代入しようとしても、コンパイル時にエラーとして弾きます。SwiftはCやC++やObjective-Cを置き換えることを標榜しているだけあって、同じことを同じように書いた場合、速度はそれらにまさるとも劣りません。それでいて、動的型を採用しているJavaScriptやPerlやPythonやRubyに匹敵する表現力を持ちます。動的言語のように速く書けて、静的言語のように速く実行できる。そのような言語はすべての言語デザイナの夢ですが、Swiftはその夢に最も近い言語だと筆者は感じています。

Getting Started

ではさっそくはじめてみましょう。え、Macなんて持ってない? ご安心を。Swift Sandboxのおかげで、今やSwiftはWebブラウザさえあればお試しできるのです図1⁠。

図1 Swiftのsandbox
図1 Swiftのsandbox

もともとはApple製品専用開発言語としてスタートしたSwiftですが、オープンソース化にともない、MacだけでなくLinuxも公式にサポートされています。Linux版はWindows 10 Anniversary Editionに搭載されたLinux on Windowsでも動きます。本稿に限らず、本連載ではなるべくプラットフォームに依存しないように当初から心がけているので、本書の連載を理解するにあたってApple製品は必須ではありません。

とはいえ、Swiftの醍醐味をもっとも堪能できるのは、MacのXcodeということになります。とくにPlaygroundは現状Mac版とiPad版しか存在しません。Swiftを100%したかったら、やはりMacが第一選択肢となります。

演習:言語処理系を実装してみる

では、さっそく言語処理系を作ってみましょう。え、いきなりハードルが高い? 心配ご無用。ここで実装するのは、その言語でプログラムするよりその言語の処理系を書くほうが簡単と定評のあるBrainfuckです図2⁠。リスト1はわずか36行ですが、それでも写経するのが面倒だというのであれば、gistにソースを用意しておきましたので利用ください。

図2 PlaygroundでBrainfuck
図2 PlaygroundでBrainfuck
リスト1 brainfuck.swift
let datasize = 65536
var framework = "Darwin"
#if os(Linux)
framework = "Glibc"
#endif
let bf2swift:[Character:String] = [
    ">": "sp += 1",
    "<": "sp -= 1",
    "+": "data[sp] += 1",
    "-": "data[sp] -= 1",
    "[": "while data[sp] != CChar(0) {",
    "]": "}",
    ".": "putchar(Int32(data[sp]))",
    ",": "data[sp] = {c in CChar(c < 0 ? 0 : c)}
(getchar())"
]
func bf2swift(src:String) -> String {
    var lines = [
        "import \(framework)",
        "var data = [CChar](repeating:CChar(0),count:ュ
¥(datasize))",
        "var (sp, pc) = (0, 0)",
    ]
    for c in src.characters {
        if let l = bf2swift[c] {
            lines.append(l)
        }
    }
    lines.append("")
    return lines.joined(separator: "¥n")
}
extension String {
    func bfCompile()->String {
        return bf2swift(src: self)
    }
}
let src = "+[,<>.]-"
print(src.bfCompile())

リスト1を実行してみると、図3のとおりに標準出力されます。図3はMacの例ですが、Linuxでは最初のDarwinGlibcになった以外同じものが出力されるはずです。

図3 brainfuck.swiftの実行時出力
import Darwin
var data = [CChar](repeating:CChar(0), count:65536)
var (sp, pc) = (0, 0)
data[sp] += 1
while data[sp] != CChar(0) {
data[sp] = {c in CChar(c < 0 ? 0 : c)}(getchar())
sp -= 1
sp += 1
putchar(Int32(data[sp]))
}
data[sp] -= 1

これをたとえばecho.swiftというテキストファイルにセーブしたうえで、次のようにシェルからコンパイルして実行してみます。

$ swiftc echo.swift
$ ./echo < echo.swift

echo.swiftの中身がそのまま出力されれば成功です。

では処理系中の最後から2番目のsrc+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.にしたうえで、もう一度同じようにしてみてください。Hello, world!と表示されましたか?

それではあらためて処理系のソースコードを見てみましょう。こんな小さなコードからでも、次のことが読み解けるはずです表1⁠。

  • 変数varや定数letを定義するにはどうすればよいか
  • 文字列中に変数を展開(interpolate)するにはどうすればよいか
  • 型を指定すればどうなるか
    • →指定しない場合はどうなるか?
    • bf2swift:[Character:String]:[Character:String]を消したらどんなエラーが出るか
  • 辞書(Dictionary)をどう初期化してどう使うか
  • 配列(Array)をどう初期化してどう使うか
  • 文字列を1文字ごとに処理するにはどうすればよいか
  • 既存のデータ型(String)にメソッドを追加するにはどうすればよいか(extension⁠
  • アーキテクチャごとに処理を変えたい場合はどうすればよいか(#if)
表1 CとSwift実装比較
BFCSwift
>sp++;sp += 1
<sp--;sp -= 1
+data[sp]++;data[sp] += 1
-data[sp]--data[sp] -= 1
[while(data[sp]){while data[sp] != CChar(0) {
]}}
.putchar(data[sp])putchar(Int32(data[sp]))
,data[sp] = getchar()data[sp] = {c in CChar(c < 0 ? 0 : c)}(getchar())

BF:Brainfuck

余裕があったら、次の課題にも挑戦してみてください。

  • BrainfuckにはBrainfuck自身で書かれた処理系が存在するが、その処理系を本処理系で生成してみる
  • 現状ソースコード中のsrcにハードコードされたBrainfuckコードではなく、任意のソースファイルをコンパイルできるようにしてみる
  • Swift処理系をBrainfuckで実装してみる

最後はさすがに冗談ですが、ある言語で簡素な言語の処理系を実装するというのは、その言語を覚える一番の近道の1つ。さすがにBrain fuckほど簡単ではありませんが、Lispの実装などはなかなか楽しそうです。

では、今月はこのへんで。

Software Design

本誌最新号をチェック!
Software Design 2022年9月号

2022年8月18日発売
B5判/192ページ
定価1,342円
(本体1,220円+税10%)

  • 第1特集
    MySQL アプリ開発者の必修5科目
    不意なトラブルに困らないためのRDB基礎知識
  • 第2特集
    「知りたい」「使いたい」「発信したい」をかなえる
    OSSソースコードリーディングのススメ
  • 特別企画
    企業のシステムを支えるOSとエコシステムの全貌
    [特別企画]Red Hat Enterprise Linux 9最新ガイド
  • 短期連載
    今さら聞けないSSH
    [前編]リモートログインとコマンドの実行
  • 短期連載
    MySQLで学ぶ文字コード
    [最終回]文字コードのハマりどころTips集
  • 短期連載
    新生「Ansible」徹底解説
    [4]Playbookの実行環境(基礎編)

おすすめ記事

記事・ニュース一覧