Do not make end-users suffer because of your laziness or ineptness –Alan Kay

前言

(2024.10.31更新)我目前偏好 Squeak 而不是Pharo

过年的假期里写了篇文章: Smalltalk(Pharo)学习之旅, 提到

Bret让我相信 smalltalk 对我很重要.

我在文章里信誓旦旦地说 准备使用Pharo(smalltalk的一门方言)将Scratch重新带回smalltalk(Scratch的第一个版本便是用smalltalk写的),我甚至给这个计划起了一个好听的名字:回到未来。可惜在一个假期里习得的能力,并不足以支持我动手干这件事。一半原因也赖Pharo官方mooc教程,这实在不是一份好教程。

现在差不多有能力来做这件事了,接下来对Scratch的改进,大多数会用smalltalk来做。

如果你掌握了基本的编程概念(通过Scratch、或者玩20分钟Etoys足以掌握这些基础概念),UpdatedPharoByExample对你而言将是绝佳的Pharo教程。非常喜欢这份教程,它是我读过最好的编程教程之一,陪伴我渡过好几个美妙的夜晚。另一个印象深刻的编程教程是Head First Programming(这本书使用Python来讲解编程基本概念,面向毫无编程经验的新手,内容有趣又友好)

我倾心于建构主义者(西摩尔·派普特艾伦·凯Bret Victor…)的认知论和教育理论,阅读了他们许多文章和工作成果之后,越来越难以忍受今天的编程工具和环境,你从他们那儿瞥见了未来,目光再落回现实,便开始挑剔,震惊于周遭环境的原始和逼仄。

艾伦凯在smalltalk上的工作,向我们展示了未来的样子,关于什么是适合人类的创造环境,这是一个伟大的人文主义者为我们带来的伟大礼物。我认为艾伦凯首先是个人文主义者和教育者,其次才是计算机科学家。(他在Ted的自我介绍里,首先提到自己是个教育工作者,其次才说是计算机科学家),作为教育者的艾伦凯,充满了人文关怀; 而作为计算机科学家的艾伦凯,则充满了想象力和热情。

在所有哲学家中,我最喜欢伯特兰·罗素, 在所有计算机科学家中,我最喜欢艾伦凯。

Three passions, simple but overwhelmingly strong, have governed my life: the longing for love, the search for knowledge, and unbearable pity for the suffering of mankind. – Bertrand Russell


Bret VictorDouglas Engelbart去世的那天写了篇文章: A few words on Doug Engelbart

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Say you bring up his 1968 demo on YouTube and watch a bit. At one point, the face of a remote collaborator, Bill Paxton, appears on screen, and Engelbart and Paxton have a conversation.

"Ah!", you say. "That's like Skype!"

Then, Engelbart and Paxton start simultaneously working with the document on the screen.

"Ah!", you say. "That's like screen sharing!"

No. It is not like screen sharing at all.

If you look closer, you'll notice that there are two individual mouse pointers. Engelbart and Paxton are each controlling their own pointer.

"Okay," you say, "so they have separate mouse pointers, and when we screen share today, we have to fight over a single pointer. That's a trivial detail; it's still basically the same thing."

No. It is not the same thing. At all. It misses the intent of the design, and for a research system, the intent matters most.

很少有现代计算机编程语言不受smalltalk的影响。但正如许多伟大的事物一样(如上文Douglas Engelbart的The Mother of All Demos),人们将其断章取义地理解之后,造出无数糟糕得多的东西。

这些东西因为种种原因流行起来,于是胜利者们一副胜者为王的姿态,说"我是最流行的,我当然就是最好的,你如果真的那么好,为何没有流行起来"。舞台上的C++换上了Java,最近好像又差不多换上了Python。正如柏拉图换上了卢梭,然后是黑格尔、尼采、希特勒,他们轮番站上历史的聚光灯下,拥护者们重复着存在即合理胜者即正义的信条。

Pharo作为smalltalk的现代方言,它从Squeak出发,忠于smalltalk精神,继续向前。

Everything is an object, and objects communicate only by sending each other message.

我已经体验到Pharo带来的无尽乐趣和自由,在其中创造和表达是如此自在和舒适, 很难再回到原先使用的任何语言中了。

艾伦凯精心设计了smalltalk。他将使用者摆在第一位置,他们是有情感的人类, 他们不是机器,他们不善于记住一大堆规则,他们遇到未知会疑惑,遇到困难会烦躁。正如艾伦凯在What does Alan Kay think of using either Squeak or Pharo as the first language for introducing programming?谈到的,smalltalk在设计之初就考虑了

减少认知负担

并致力于在用户入门时提供

真正的演奏(real playing)

作为设计者, 艾伦凯说:

不要让用户因为你的懒惰或无能而受苦.

我不知道今天主流编程语言的设计者们看到这些话,作何感想。有许多编程语言设计者对自己闲着没事,花了一周就整了个编程语言津津乐道。当这些糟糕的语言竟被推上历史舞台,受苦的便是它的用户。Bret在LearnableProgramming一文中对Programming这门语言的攻击是非常精彩的。而Programming在糟糕语言排行榜里并不靠前。

更多关于smalltalk的思想来源,可以参考The Early History Of Smalltalk

缘聚缘散

Python并不坏,在所有目前流行的编程语言中,我最喜欢它。它有友好的社区、简洁的语法、完善的生态。如那句流行的口号说的:

人生苦短,我用Python.

我大约大三(2012-2013年)开始使用Python,之后一直将其作为主要编程语言。Python一路从小众语言成长为今天的主流语言。

与Python结缘,得从周日的一个晚上说起,当时在校园海报上,看到一个招募帖,有个技术团队在招募前端开发,我那时的兴趣完全在前端开发,它那么鲜活有趣。比php/asp可好玩多了。

团队由一位口才极好的石姓学长发起,他人很有趣,演讲也富有感染力。回想起来,这应该是改变我人生轨迹的一个夜晚,如果没有加入这个4人小团队,我不大可能从事计算机行业。

团队里写后端的是一位何姓学长,他使用Ubuntu/Vim/Python。看着光标在黑乎乎的命令行里移动如飞,这场景满足了我对黑客的所有幻想。这些工具被我一一记下,后来都在我的工具箱里。

那时学校里使用这门语言编程的人可能是个位数,我只知道寥寥三人,何姓学长是一位,我自己是一位,我还忽悠了@ymj换用这门语言。@ymj后来去了创新工场做人工智能;何姓学长杳无踪迹,可能隐姓埋名做了黑客;我则对计算机的许多领域都很好奇,Python的胶水特性十分适合我。

Python是那种理性的姑娘乐意选择一起生活的结婚对象(当然,理性的姑娘可能选择不婚),它贴心、随和、经济实用,它有很暖的社区。Python即便有缺点,也绝非不能忍受,最多就是坐在沙发上抠抠脚之类的生活琐碎细节。许多婚姻可能因为争夺遥控器破裂,但很少因为抠脚破裂的,别小看了争夺遥控器这件事,它可能是三观不和的征兆,你们彼此不满于对方的精神食粮。

遇见smalltalk,对我来说,大抵类似郭襄在风陵渡口的遭遇,你如此清楚地知道,这就是你的所有期待,无论往后岁月黯不黯淡,江山易不易主,江河干不干枯,它都熠熠生辉,如满月,如焰火,如雪夜围炉时,对方眼里倒映的光。

在很长一段时间内,我还会将Python用作我的工作语言,用它写些脚本来管理系统、科学计算、异步编程…

但创造和探索,或者如Scratch社区鼓励的:表达自己, 这些激动人心的活动,我都将使用smalltalk. 我将smalltalk视为一个创造友好的语言。我也将编程看作和木工、表演、绘画一样的创造性工作,它的人文属性并不弱于工程属性。个人计算机的早期推动者们 艾伦·凯Douglas Engelbart希望它拥有人文属性。 未来计算机的探索者们艾伦·凯Bret Victor也希望它有这种属性。

增量前进

Python在很长的一段时间里依然会是系统管理、信息安全(入侵渗透)、胶水工具、科学计算、人工智能的主力语言。

我也不希望将之前在这些领域里积累起来的技能都抛弃了,我喜欢增量地前进,而不是换个工具从头再来。

尽管在原则上我认同爱因斯坦说的:

什么是教育?把在学校里学到的所有东西全部忘光了之后留下来的东西才叫教育。

还记得基本思想能操作自如中间的鸿沟,是需要时间来填补的。有大量细碎的细节和习惯,固化在某个具体技术框架里,要完全迁移到另一个体系中,时间成本并太低。

所以,在往后的时间里,我即便使用smalltalk来构建新项目,恐怕也会混合Python代码,会用到一些基于Python的顺手工具。

如何在smalltalk中运行Python代码,让他们能够混合编程?是我接下来需要面对的问题。尤其在过渡阶段,当遇到困难,会想退回到之前熟悉的安全域里。如果smalltalk能够方便调用Python,我就能够放心地增量前进。每次前进一点点,进可攻,退可守。

这也正是我们之前坚持让Python与Scathch能够互操作地原因,之前在使用Python拓展Scratch的能力里讨论说:

如果这种过渡是必要的,我希望它们是渐进的,而不是割裂的,否则就不叫过渡了。初学者熟悉scratch,也喜欢它,我知道大多数使用scratch的孩子,对它的好感大都胜过文本语言。你不必抛弃scratch,如果你需要一些更强大的功能,使用Python去扩展它,这个过程应该很愉快,你写了很少的Python代码,立马就能应用到你喜欢的Scratch项目上,你看到你逐渐能做更多有趣的事,你感到充满乐趣,所学的新知识,立马应用在你感兴趣的项目里。
我们反对割裂式的教学,学习者从scratch切换到Python,很长时间内只能通过print看到输出,没有生动的反馈,于是许多人便对阶段感到沮丧,踏上一条从入门到放弃的路。

技术细节

最后记录下技术细节。在Pharo中调用Python是很简单的,所受的约束很小,可以自如地在Pharo中调用Python库,并允许采用Pharo语法来调用它们。

我目前采用Python3Generator. (PythonBridge的动态性更好)

操作方式非常简单,首先在Pharo(我目前使用Pharo 7.0.1)中安装依赖库

1
2
3
4
Metacello new
    baseline: 'Python3Generator';
    repository: 'github://juliendelplanque/Python3Generator/repository';
    load

然后就可以自如调用Python啦:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
"Use and initialize the FFI interpreter."
P3GInterpreter useFFIInterpreter.
P3GInterpreter current pathToPython: '/Library/Frameworks/Python.framework/Versions/3.7/bin/python3'.

instr := P3GInstructionsList new.

json := 'json' asP3GIdentifier.
file := 'file' asP3GIdentifier.
os := 'os' asP3GIdentifier.

instr addAll: {
    json import.
    os import.
    file <- ('open' asP3GIdentifier callWith: #('/tmp/osp3g.json' 'w')).
    (file=>#write) callWith: { (json=>#dumps) callWith: {{
                                                'os' -> (os=>#name).
                                                'uname' -> (os=>#uname) call } asDictionary} }.
    ((file=>#close) call)
}.

instr execute.

运行之后,查看/tmp/osp3g.json:

调用强大的第三方库(如numpymatplotlib)也是OK的!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
"Use and initialize the FFI interpreter."
P3GInterpreter useFFIInterpreter.
P3GInterpreter current pathToPython: '/usr/bin/python3'.

numpy := 'numpy' asP3GIdentifier.
mlab := 'matplotlib' asP3GIdentifier=>#mlab.
pyplot := 'matplotlib' asP3GIdentifier=>#pyplot.

instr := P3GInstructionsList new.

instr addAll: {
    "Import modules."
    numpy import.
    mlab import.
    pyplot import.

    "Set seed for random."
    (numpy=>#random=>#seed) callWith: #(0).

    "Example data"
    #mu asP3GIdentifier <- 100.
    #sigma asP3GIdentifier <- 15.
    #x asP3GIdentifier <- (#mu asP3GIdentifier + (#sigma asP3GIdentifier * ((numpy=>#random=>#randn) callWith: #(437)))).

    #num_bin asP3GIdentifier <- 50.

    #res asP3GIdentifier <- (pyplot=>#subplots) call.
    #fig asP3GIdentifier <- (#res asP3GIdentifier at: 0).
    #ax asP3GIdentifier <- (#res asP3GIdentifier at: 1).

    "Plot histogram of data."
    #res asP3GIdentifier <- ((#ax asP3GIdentifier=>#hist) callWith: {#x asP3GIdentifier.#num_bin asP3GIdentifier} with: {'normed' -> 1 } asDictionary).
    #bins asP3GIdentifier <- (#res asP3GIdentifier at: 1).

    "Add a 'best fit line'"
    #y asP3GIdentifier <- ((mlab=>#normpdf) callWith: {#bins asP3GIdentifier . #mu asP3GIdentifier . #sigma asP3GIdentifier}).
    (#ax asP3GIdentifier=>#plot) callWith: { #bins asP3GIdentifier . #y asP3GIdentifier . '--' }.

    (pyplot=>#show) call
 }.

instr execute

效果如下:

第三方库

尽管Pharo社区没有Python社区壮大,但社区里已经有很多高质量的第三方库,我整理了一些我喜欢的。 其中gtoolkitMooseDr Geo令我大吃一惊。整个Pharo社区充满了人文主义精神,这种精神体现在软件本身里,体现在软件的设计原则里,体现在软件的介绍里。他们秉承艾伦凯在smalltalk中展现的理念,继续做着令人震惊和振奋的工作。

参考