エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

Ioが面白い・その0 の その2 まだ準備運動

1日目後半

7つの言語 7つの世界

7つの言語 7つの世界

List

リスト。順序付きコレクション。IoのListは、linked listの類ではなくてarrayとかvectorとかの仲間のようです。


listメソッドで新しいリストを作成できます。

Io> hoge := list("foo", "bar")
==> list(foo, bar)
Io> hoge size
==> 2

要素の追加。

Io> hoge append("baz")
==> list(foo, bar, baz)
Io> hoge size
==> 3

要素として追加するオブジェクトの種類は問いません。というか、そもそもIoではすべてのオブジェクトが個別のオブジェクトですし。

Io> hoge append(1)
==> list(foo, bar, baz, 1)

算術演算のためのメソッドの例。

Io> hoge := list(1,2,3,4)
==> list(1, 2, 3, 4)
Io> hoge average
==> 2.5
Io> hoge sum
==> 10

末尾への要素の追加と末尾の要素の取り出し。

Io> hoge push(5)
==> list(1, 2, 3, 4, 5)
Io> hoge
==> list(1, 2, 3, 4, 5)
Io> hoge pop
==> 5
Io> hoge
==> list(1, 2, 3, 4)

あるいは

Io> hoge append(5)
==> list(1, 2, 3, 4, 5)
Io> hoge
==> list(1, 2, 3, 4, 5)
Io> hoge removeLast
==> 5
Io> hoge
==> list(1, 2, 3, 4)

先頭への要素の追加と先頭の要素の取り出し。

Io> hoge prepend(0)
==> list(0, 1, 2, 3, 4)
Io> hoge
==> list(0, 1, 2, 3, 4)
Io> hoge removeFirst
==> 0
Io> hoge
==> list(1, 2, 3, 4)

appendprependは複数の要素を追加できます。prependのばあい、追加される要素の順序に注意。

Io> hoge append(5, 6, 7)
==> list(1, 2, 3, 4, 5, 6, 7)
Io> hoge prepend(0, -1, -2)
==> list(-2, -1, 0, 1, 2, 3, 4, 5, 6, 7)

isEmptyメソッド。

Io> hoge := list(1, 2)
==> list(1, 2)
Io> hoge pop
==> 2
Io> hoge isEmpty
==> false
Io> hoge pop
==> 1
Io> hoge isEmpty
==> true

Map

マップ。key-valueのペアを格納するコンテナ。
7つの言語 7つの世界」で「シンタックスシュガーはない」と書かれていますが、自分でどうにかできるみたいです(3日目に出てきます)。


マップの作成と、値の設定と、値の取り出し。

Io> hoge := Map clone
==>  Map_0x36bad0:

Io> hoge atPut("foo", 1)
==>  Map_0x36bad0:

Io> hoge at("foo")
==> 1

atPutメソッドはマップ自身を返すのでメソッドチェインできます。

Io> hoge atPut("bar", 2) atPut("baz", 3)
==>  Map_0x36bad0:

Io> hoge size
==> 3
Io> hoge keys
==> list(foo, baz, bar)
Io> hoge values
==> list(1, 3, 2)
Io> hoge asList
==> list(list(foo, 1), list(baz, 3), list(bar, 2))

見てのとおり順序は考慮されません。

asObjectメソッドでオブジェクトにも変換できます。各キーをスロットに持つオブジェクトになります。

Io> hoge2 := hoge asObject
==>  Object_0x497c90:
  bar              = 2
  baz              = 3
  foo              = 1

Io> hoge2 foo
==> 1
Io> hoge2 bar
==> 2

true, false, nil, singleton

Io> 4 < 5
==> true
Io> 4 <= 3
==> false
Io> true and false
==> false
Io> true and true
==> true
Io> true or true
==> true
Io> true or false
==> true
Io> 4 < 5 and 6 > 7
==> false
Io> true and 6
==> true
Io> true and 0
==> true

読み進めると「true, false, nil, singleton」という節が出てきます。どうしてここでシングルトンが一緒に言及されているのか、と思ったら。truefalsenilはシングルトンオブジェクトだという話。クローンを作ろうとしても元のオブジェクトが得られるだけでクローンを作ることができません。

==> false
Io> true clone
==> true
Io> false clone
==> false
Io> nil clone
==> nil

cloneスロットに自分自身が設定されているため、自分自身が返るだけでクローンが作成されないというしくみとのこと。

Io> true getSlot("clone")
==> true


つまりcloneスロットに自分自身を設定することで簡単にシングルトンオブジェクトを作ることができます。

Io> hoge := Object clone
==>  Object_0x3eb020:

Io> hoge clone := hoge
==>  Object_0x3eb020:
  clone            = Object_0x3eb020

Io> hoge2 := hoge clone
==>  Object_0x3eb020:
  clone            = Object_0x3eb020

Io> hoge == hoge2
==> true


Ioの真偽値が面白いのは、演算子がオブジェクト自身に定義されていることです。

Io> true slotNames
==> list(justSerialized, not, type, then, ifTrue, asString, asSimpleString, else, ifFalse, elseif, clone, or)
Io> false slotNames
==> list(justSerialized, not, ifFalse, then, isTrue, asString, asSimpleString, type, else, ifTrue, and, elseif, clone, or)
Io> nil slotNames
==> list(justSerialized, asString, isNil, isTrue, elseif, else, and, ifNil, ifNilEval, asSimpleString, clone, not, type, then, ifNonNil, or, pass, ifNonNilEval, catch)

なので否定は後置になります。

Io> true not
==> false
Io> false not
==> true
Io> nil not
==> true

ifTrueメソッドを使えばSmalltalkのような書き方ができます*1

Io> a := 4
==> 4
Io> b := 5
==> 5
Io> (a < b) ifTrue("a is less than b" println)
a is less than b
==> true

if(...) then(...) else(...)という書き方もありますが、それは2日目に…。

*1:というか、Smalltalkでは条件式をこんなふうに書くということを、これで初めて知りました。