前言

近期重新进入 Squeak, 收获颇丰, 学会了将 Debugger 作为主要的编程工具。

我将 Squeak 视为学习和理解事物的环境, “软件只是心智成熟的副产品”。Dynatalk 是此次 Squeak 之旅的一个副产品。

不同的人可能有不同的学习偏好, 我怀疑这些偏好是天生的。

读初中时我特别喜欢物理。对物理的理解, 大多通过在院子里做实验得来。 有些实验的结果和书本说的不一样, 我一度相信牛顿是错的。由于实验涉及计算, 于是连带喜欢上了数学。

“动起手来理解东西” 特别合我胃口, 可惜这种学习风格不大受到应试教育的待见, 初中之后的很多年, 我都没找到学习的热情。 直到后来在野外意外遇到编程(课堂里接触的编程让我笃定这玩意压根不适合人类)。

从图书馆得知, 黑客们喜欢喜欢动起手来思考和解决问题, 如果手册说不行,那就黑到系统里修改它。更多的时候,连手册也不想看,按自己的想法胡乱捣鼓,直到碰了壁才愿意低头看看手册。这种倾向可能没必要地浪费时间(明明手册里都写清楚了)。 我并不是说这种倾向更好, 只是, 人可能真的有不同的倾向, 对我来说, 跟着教程一步一步做事让人抓狂。

受教育者最大的福祉或许是身处多元的教育系统和价值体系中, 我在成长的过程中没有这样的好运, 我受到的学校教育, 在最好的情况下只是浪费我的时间, 在最坏的情况下, 则增加我的恐惧, 消磨我的好奇心和热情。我的好运是成年之后能够访问开放互联网

之前跟着 《Squeak by example》《The Cuis Book》 学习 Smalltalk, 它们都是好书, 但我每时每刻都想逃离, 去做自己的项目,尽管也不知道去做什么。

好在, 有这些倾向的人, 构建了许多系统来支持那些不愿跟着书本一步一步学习的人。

Alan Kay 和 John Maloney 说过类似的话, 他们想构建出这样的系统, 用户不用看一堆手册,而是能够直观地与系统进行有意义的交互, 在过程中学习和建立理解。用更正式的话来说, 它们支持 “建构主义” 风格的学习。

此次进入 Squeak, 我决定不再跟着完整的教程, 而是一边玩,一边学, 遇到困惑的东西, 就临时去以下两个地方查一查:

我决定以我自己的风格来学习。 为了方便做实验, 我构建了一个 MyLab package, 里头有一个 Yard 类(我把它当作我小时候做实验的院子), 在其中随时做实验。我决定让计算机适应我而不是让我来适应它。

Alan Kay 说计算机可以是一切的媒介, 而媒介的作用是将思想具体化。 我逐渐适应了 Squeak 中的生活(不会再搞坏或丢失东西), 能够在 Squeak 中表达和实验日常琢磨不清的想法, 我喜欢在 Squeak 里把这些不清晰的想法, 勾勒出来, 模拟它们运行起来, 让它随着时间演变, 在它们运行期间, 用手戳一戳它们看看会有什么反应。 许多想法一开始模糊不清, Squeak 这样的动态环境不要求一开始就弄清楚它们, 而是提供许多设施(如极端的后期绑定), 让你可以慢慢发展和理解它们, 你可以在对象运行期间不断调整它们, 没有重启和打断, 因此你可以长时间处于心流状态中。

我发现有一整周的时间, 我都在一个单一的进程里。从一周前启动开始,就始终在与同个对象对话, 尽管它的类模版被多次重构, 这个对象始终活着!

Dan Ingalls 说我们今天使用的 Smalltalk image 40 多年来一直是延续的, image 中的对象有些在 40 年前创建之后, 就一直没有销毁过!

Squeak 有朝一日或许会成为一门生物学。


下面是我的学习笔记.

我的开发风格

image 管理

  • 不保存原始 image。 尽量使用 save as 而不是 save
    • 参考 Squeak help > The Project > Working with Squeak
    • 在 world 中 ctrl-s 不会自动保存 image, 需要 save as
  • 把 image 看作系统发行版, 应该有明确记录, 查看我维护的版本

一些偏好

  • 使用 etoys 快速开始项目 (当作 Scratch/Snap!)
    • dynatalk 可以在 etoys 使用
  • 打开 viewer, 在 etoys 中 任何 morph 都可以作为 Pen. (使用 halo move 即可将其当作笔来用), 之后可运行 clear 清理屏幕。
  • 查询语法和常用对象: Terse Guide(内置于 Squeak help)
  • (MacOS)使用 cmd+5 制作可执行的 hypertext (下文有详细介绍)

一些代码片段

  • Beeper beep : 看看代码是否在某处运行, John Maloney 在这里提到
  • 0 tinyBenchmarks : 性能测试
  • TimeStamp now utcMicroseconds: unix 时间戳
  • '{2} {1}' format: {'a'. 'b'}. "b a" : 字符串插值

其他笔记

对象自省能力

参考 Terse Guide: Class / Metaclass

  • Morph allInstances. : Morph 类的所有对象
  • Morph allInstVarNames. : Morph 类的所有实例变量
  • String sourceCodeAt: #parseAsJson. 某个方法的源代码
  • String selectors. String 类的消息选择器(String 类能够理解的所有消息)

debugger 的常见用法

Smalltalk 允许用户在 debugger 中完成所有探索/开发工作, 有很多中方式可以进入 debugger:

  • 探索任何表达式: 选中表达式, 右键 debug it (MacOS 快捷键: cmd + shift + D)
  • 在代码中添加断点: self halt.
  • 测试驱动开发过程中, 任何的错误都会进入 debugger

参考 Debugger

morph 的基本属性

morph 的基本属性:

  • position
  • extent
  • color
  • name
  • owner
  • submorphs

hypertext: Squeak 中的可执行文本

cmd+5 (MacOS)

  • 先写出可执行的脚本, 选中它们按 cmd+5, 选择 doit(其他的选项同理), 之后可以修改文本. 或者
  • Text<Transcript cr; show: 'Example2'> on the Transcript
    • 语法: text<expression>

参考 hypertext

blocks 的常见用法

参考 Terse Guide: Boolean

注意 ()[] 的区别 ! [] 是惰性执行。

  • 短路操作

      b := (x < 5) & (y > 1).     "boolean and"
      b := (x < 5) | (y > 1).     "boolean or"
      b := (x < 5) and: [y > 1].  "boolean and (short-circuit)"
      b := (x < 5) or: [y > 1].   "boolean or (short-circuit)"
    
  • 条件执行

      x > 10 ifTrue: [Transcript show: 'ifTrue'; cr].		"if then"
    

布局(layout): 如何排布 submorphs

AlignmentMorph 类已被消除。在新方案中, 每个 morph 都能够控制其 submorphs.

将 morph 的 layoutPolicy(右键) 设置为 TableLayout 是控制和对齐变形内对象的起点

思考布局的方式是: 思考一个 morph 如何控制它的 submorphs. 目标是控制显示对象内的对象如何排列,并控制它们在显示上的间距.

布局属性可以通过交互式操作调好, 可以应用在其他 morph 里:

更多控制细节参考: 一篇用动态媒介写的文章 。 这篇文章写得很早, 但依然适用于目前的系统(Squeak 6)

Git Browser 的使用

参考 Git Browser

Process

1
2
process := [(Delay forSeconds: 5) wait. Beeper beep] newProcess.
process resume.

参考 Process 的测试用例。

使用 cmd + . 可以打断阻塞的界面.

Promise

1
2
3
4
5
6
p := Promise new.
p resolveWith: 100.
"p rejectWith: Error new."
p wait.
"p then:[:v | Transcript showln: v]"
"p isResolved"

更多用法参考 Promise 的测试用例.

与其他系统互操作

Dynatalk

与 Python, JavaScript, MiroBlocks, Snap!, … 互操作

介绍 Dynatalk

Dynatalk 也可在 etoys script 中使用(需要先为 Player 打上补丁):

与之互动的 Snap 项目

OSCommand

  • APP -> Command Shell
    • 运行 python: /Users/wwj718/env310/bin/python -c 'print(1)'
    • 视角: “主环境” 使用 Squeak。 将 Python 视为 FFI, 只是简单调用。采用 lively “提升其他系统” 的观点,赋予它们更多动态性。
  • (OSProcess evaluate: 'ls /tmp') output 有返回值
    • OSProcess outputOf: 'ls /tmp'
  • OSProcess command: 'ls /tmp' 没有返回值

已知问题

音频功能损坏

运行过 Beeper beep 或其他有声音的程序(如etoys)之后,保存镜像,再运行会没有声音. 与 SoundPlayer process 有关。

解决方案: 镜像启动之后运行 SoundPlayer startUp

FAQ

对象何时被回收?

参考 Squeak help > Tutorials > The Squeak Image > Working with the Squeak Image

系统中的所有对象都有两个根:

  1. Smalltalk specialObjectsArray : 基本上包含虚拟机需要了解的所有内容,以及整个映像中的几乎每个对象
  2. thisContext : 当前的执行上下文,保存着临时对象

执行垃圾收集时,将从内存中删除这两个根都无法访问到的对象。

重新进入 Squeak 的原因是 Snap! 不够用吗 ?

我之前写过 Snap! 使用笔记: 将 Snap! 用作个人计算环境

我非常喜欢在 Snap! 中进行探索性编程。它依然是我最喜欢的编程环境之一(基本完全替代了 Scratch)。

有时候, 我需要类结构和 morphic 的时候, 我就会希望离开 Snap! 进入到 Squeak。

John Maloney 在给我的邮件中提到

I’d be inclined to discard the entire Scratch-like sprite system and build a Smalltalk-like program environment (e.g. with a Smalltalk-like browser) that uses Morphic directly for building UI components. The result might have more of a learning curve than Scratch but it would be more flexible and users would have to think about two totally different UI models (i.e. the stage/sprites model vs. morphic).

我倾向于放弃整个类似 Scratch 的角色系统,并构建一个类似 Smalltalk 的程序环境(例如,使用 Smalltalk 浏览器那样的东西)直接使用 Morphic 来构建 UI 组件。结果可能比 Scratch 有更多的学习曲线,但它会更灵活,(在 Scratch 中)用户将不得不考虑两种完全不同的 UI 模型 (即舞台/角色模型与 Morphic)。

当我的项目变得复杂的时候, 我也有类似的感受, 我想摆脱角色系统, 使用更加灵活通用的 morphic .

但大多数时候, Snap! 都是非常好的起点。

有一个有趣的方向: 把 Snap! 的角色系统迁移到 Etoys, 这样我们就有了易用的图形环境, 当需要更多的力量时, 可以无缝切换到 morphic。

参考