Skip to content

AHABHGK

Io

Io 语法只不过把消息全部串联起来,每个消息都返回一个对象,每条消息都也都带有括号内的可选参数 Io 中,一切皆为消息,且每条消息都会返回另一条接受消息的对象 Io 没有类,只需要与对象打交道,必要时把对象复制一下就行,这些被复制的对象叫原型,原型语言中,每个对象都不是类的复制品,而是一个实实在在的对象

1brew install io

所有事物都是对象,对由于对象交互的都是消息

消息:左边的是对象,右边的是消息,把消息发给对象

1"Hello, Io" print // "Hello, Io" 对象接收 print 消息
2// => "Hello, Io"
3Vehicle := Object clone // Object 是跟对象,发送 clone 消息,返回一个新对象,并赋值给 Vehicle
4Vehicle description := "gogogo" // 对象上有槽,:= 没有则创建并赋值,= 只赋值,没有则报错
5Vehicle type // => Vehicle,每个对象都有 type 槽
6Vehicle slotNames // => list(type, description)

原型

1Vehicle proto // => Object
2Car := Vehicle clone
3ferrari := Car clone
4ferrari slotNames // => list() type 应该是大写开头
5ferrari type // => Car 得到原型
6
7Car drive := method("Vroom" println)
8ferrari drive // => "Vroom"
9ferrari proto // => Car
10
11Lobby // 主命名空间

List

1nums := list(1, 2, 3, 4)
2nums size // => 4
3nums append(5)
4nums average // => 3
5nums pop
6nums prepend
7nums isEmpty // => false

Map

1elvis := Map clone
2elvis atPut("home", "Graceland")
3elvis at("home") // => "Graceland"
4elvis atPut("style", "ror")
5elvis asObject // => home = "Graceland" style = "ror"
6elvis asList // => list(list("home", "Graceland"), list("style", "ror"))
7elvis size // => 2
8elvis keys // => list("home", "style")

true false nil 都是单例

1true proto // => Object
2true clone // => true
3
4// 实现单例
5Highlander := Object clone
6Highlander clone := Highlander

条件和循环

1i := 1
2while(i <= 3, i println; i = i + 1); "end" println // ; 会把两个消息连接执行
3// 1
4// 2
5// 3
6// end
7
8for(i, 1, 11, 2, i println)
9// 1
10// 3
11// 5
12// 7
13// 9
14// 11
15// => 11
16
17loop("dead loop" println) // ...
18
19if(true, "it's true", "it's false") // "it's true"

运算符

1OperatorTable
2// ==> OperatorTable_0x7facc5448ee0:
3// Operators
4// 0 ? @ @@
5// 1 **
6// 2 % * /
7// 3 + -
8// 4 << >>
9// 5 < <= > >=
10// 6 != ==
11// 7 &
12// 8 ^
13// 9 |
14// 10 && and
15// 11 or ||
16// 12 ..
17// 13 %= &= *= += -= /= <<= >>= ^= |=
18// 14 return
19
20// Assign Operators
21// ::= newSlot
22// := setSlot
23// = updateSlot
24
25// To add a new operator: OperatorTable addOperator("+", 4) and implement the + message.
26// To add a new assign operator: OperatorTable addAssignOperator("=", "updateSlot") and implement the updateSlot message.

消息:由 sender target arguments 组成

1// call 可以访问消息的元信息
2a myTargets := method(call target)
3a mySender := method(call sender)
4a myMessageName := method(call message name)
5a myMessageArgs := method(call message arguments)
6
7a myTargets // => a
8a mySender // => Object proto
9a myMessageName // => myMessageName
10a myMessageArgs(1, 2) // => list(1, 2)
1myif := method(
2 (call sender doMessage(call message argAt(0))) ifTrue(
3 call sender doMessage(call message argAt(1))) ifFalse(
4 call sender doMessage(call message argAt(2)))
5)
6
7myif(foo == bar, write("true\n"), write("false\n"))

DSL

🤣做 XOR

1OperatorTable addOperator("🤣", 11)
2OperatorTable println
3true 🤣 := method(bool, if(bool, false, true))
4false 🤣 := method(bool, if(bool, true, false))
5
6true 🤣 true print // => false
7true 🤣 false print // => true

解析 JSON

1// Make the : an operator so we can parse JSON kv-pairs
2OperatorTable addAssignOperator(":", "atPutNumber")
3
4// Because atPut already stringifies the key, we string the extra quotes
5Map atPutNumber := method(
6 self atPut(
7 call evalArgAt(0) asMutable removePrefix("\"") removeSuffix("\""),
8 call evalArgAt(1)
9 )
10)
11
12// Fires whenever the parser encounters curly brackets
13curlyBrackets := method (
14 writeln("Parsing curly brackets")
15 r := Map clone
16 call message arguments foreach(arg,
17 writeln("An arg: ", arg)
18 r doMessage(arg)
19 )
20 r
21)
22
23s := File with("phonebook.json") openForReading contents
24// doString evaluates text as Io source code
25phoneNumbers := doString(s)
26
27phoneNumbers keys println // => list("Bob Smith", "Mary Walsh")
28phoneNumbers values println // => list("5195551212", "4162223434")

method_missing:编写简易 HTML

Io 中的 method_missing 是类的 forward

1Builder := Object clone
2Builder forward := method(
3 writeln("<", call message name, ">")
4 call message arguments foreach(
5 arg,
6 content := self doMessage(arg);
7 if(content != nil, if(content type == "Sequence", writeln(content)))
8 )
9 writeln("</", call message name, ">")
10)
11
12Builder ul(
13 li("Io")
14)
15// <ul>
16// <li>
17// Io
18// </li>
19// </ul>

JavaScript 中通过模版字符串实现类似功能

并发

Io 并发

异步消息:@ 前缀的消息返回 future,@@ 前缀的消息返回 nil 并在自身上下文中触发消息

协程:“轻量级线程”

可以想象成带有多个入口和出口的函数,每次 yield 都会保存当前上下文,并把控制权交给另一上下文当中

1// coroutine.io
2odd := Object clone
3odd numbers := method(
4 1 println
5 yield
6 3 println
7 yield
8)
9
10even := Object clone
11even numbers := method(
12 yield
13 2 println
14 yield
15 4 println
16)
17
18odd @@numbers
19even @@numbers
20
21Coroutine currentCoroutine pause
22
23// $ io coroutine.io
24// 1
25// 2
26// 3
27// 4
28// Scheduler: nothing left to resume so we are exiting

actor:能接收消息并基于其执行运算,也可以发送消息给其他 Actor。Actors 之间相互隔离,它们之间并不共享内存

一个 actor 只能改变自身的状态,并通过严格的队列接触其他 actor,而线程可以不受限制的改变彼此状态,有竞争条件的并发问题

Io 中发送异步消息的对象就是 actor

1slower := Object clone
2faster := Object clone
3slower start := method(wait(2); writeln("slowly"))
4faster start := method(wait(1); writeln("fastly"))
5
6slower start; faster start
7// 2s => "slowly"
8// 3s => "fastly"
9
10slower @@start; faster @@start; wait(3) // slower actor 接收 start 消息到队列,执行;faster actor 接收 start 消息到队列,执行
11// 1s => "fastly"
12// 2s => "slowly"

future:@ 调用消息时返回,一段时间后会变成结果值,如果未产生结果是使用 future 就会阻塞直到产生结果

类似于 JavaScript 中的 async/await(async/await 通过 Promise 实现,但写法上 future 更像 async/await)

feeling

占用空间小,容易安装

对象与消息,简单强大

简洁的语法,Lisp + OOP

很自由,DSL 能力强大

先进的并发模型

性能不行

社区太太太太小