Io
Io 语法只不过把消息全部串联起来,每个消息都返回一个对象,每条消息都也都带有括号内的可选参数 Io 中,一切皆为消息,且每条消息都会返回另一条接受消息的对象 Io 没有类,只需要与对象打交道,必要时把对象复制一下就行,这些被复制的对象叫原型,原型语言中,每个对象都不是类的复制品,而是一个实实在在的对象
1brew install io
所有事物都是对象,对由于对象交互的都是消息
消息:左边的是对象,右边的是消息,把消息发给对象
1"Hello, Io" print // "Hello, Io" 对象接收 print 消息2// => "Hello, Io"3Vehicle := Object clone // Object 是跟对象,发送 clone 消息,返回一个新对象,并赋值给 Vehicle4Vehicle description := "gogogo" // 对象上有槽,:= 没有则创建并赋值,= 只赋值,没有则报错5Vehicle type // => Vehicle,每个对象都有 type 槽6Vehicle slotNames // => list(type, description)
原型
1Vehicle proto // => Object2Car := Vehicle clone3ferrari := Car clone4ferrari slotNames // => list() type 应该是大写开头5ferrari type // => Car 得到原型67Car drive := method("Vroom" println)8ferrari drive // => "Vroom"9ferrari proto // => Car1011Lobby // 主命名空间
List
1nums := list(1, 2, 3, 4)2nums size // => 43nums append(5)4nums average // => 35nums pop6nums prepend7nums isEmpty // => false
Map
1elvis := Map clone2elvis 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 // => 28elvis keys // => list("home", "style")
true false nil 都是单例
1true proto // => Object2true clone // => true34// 实现单例5Highlander := Object clone6Highlander clone := Highlander
条件和循环
1i := 12while(i <= 3, i println; i = i + 1); "end" println // ; 会把两个消息连接执行3// 14// 25// 36// end78for(i, 1, 11, 2, i println)9// 110// 311// 512// 713// 914// 1115// => 111617loop("dead loop" println) // ...1819if(true, "it's true", "it's false") // "it's true"
运算符
1OperatorTable2// ==> OperatorTable_0x7facc5448ee0:3// Operators4// 0 ? @ @@5// 1 **6// 2 % * /7// 3 + -8// 4 << >>9// 5 < <= > >=10// 6 != ==11// 7 &12// 8 ^13// 9 |14// 10 && and15// 11 or ||16// 12 ..17// 13 %= &= *= += -= /= <<= >>= ^= |=18// 14 return1920// Assign Operators21// ::= newSlot22// := setSlot23// = updateSlot2425// 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)67a myTargets // => a8a mySender // => Object proto9a myMessageName // => myMessageName10a 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)67myif(foo == bar, write("true\n"), write("false\n"))
DSL
🤣做 XOR
1OperatorTable addOperator("🤣", 11)2OperatorTable println3true 🤣 := method(bool, if(bool, false, true))4false 🤣 := method(bool, if(bool, true, false))56true 🤣 true print // => false7true 🤣 false print // => true
解析 JSON
1// Make the : an operator so we can parse JSON kv-pairs2OperatorTable addAssignOperator(":", "atPutNumber")34// Because atPut already stringifies the key, we string the extra quotes5Map atPutNumber := method(6 self atPut(7 call evalArgAt(0) asMutable removePrefix("\"") removeSuffix("\""),8 call evalArgAt(1)9 )10)1112// Fires whenever the parser encounters curly brackets13curlyBrackets := method (14 writeln("Parsing curly brackets")15 r := Map clone16 call message arguments foreach(arg,17 writeln("An arg: ", arg)18 r doMessage(arg)19 )20 r21)2223s := File with("phonebook.json") openForReading contents24// doString evaluates text as Io source code25phoneNumbers := doString(s)2627phoneNumbers keys println // => list("Bob Smith", "Mary Walsh")28phoneNumbers values println // => list("5195551212", "4162223434")
method_missing:编写简易 HTML
Io 中的 method_missing 是类的 forward
1Builder := Object clone2Builder 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)1112Builder ul(13 li("Io")14)15// <ul>16// <li>17// Io18// </li>19// </ul>
JavaScript 中通过模版字符串实现类似功能
并发
异步消息:@ 前缀的消息返回 future,@@ 前缀的消息返回 nil 并在自身上下文中触发消息
协程:“轻量级线程”
可以想象成带有多个入口和出口的函数,每次 yield 都会保存当前上下文,并把控制权交给另一上下文当中
1// coroutine.io2odd := Object clone3odd numbers := method(4 1 println5 yield6 3 println7 yield8)910even := Object clone11even numbers := method(12 yield13 2 println14 yield15 4 println16)1718odd @@numbers19even @@numbers2021Coroutine currentCoroutine pause2223// $ io coroutine.io24// 125// 226// 327// 428// Scheduler: nothing left to resume so we are exiting
actor:能接收消息并基于其执行运算,也可以发送消息给其他 Actor。Actors 之间相互隔离,它们之间并不共享内存
一个 actor 只能改变自身的状态,并通过严格的队列接触其他 actor,而线程可以不受限制的改变彼此状态,有竞争条件的并发问题
Io 中发送异步消息的对象就是 actor
1slower := Object clone2faster := Object clone3slower start := method(wait(2); writeln("slowly"))4faster start := method(wait(1); writeln("fastly"))56slower start; faster start7// 2s => "slowly"8// 3s => "fastly"910slower @@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 能力强大
先进的并发模型
性能不行
社区太太太太小