为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

Scratch 少儿编程 1840浏览 0评论

友情提示:视频教程观看时请手动设置清晰度。

自定义方法不带返回值会有多麻烦?

 

ET 社群里关于 Scratch 的自定义方法不带返回值,有过好几次讨论。我知道有老师心心念念期盼着它,我也遇到过编程猫的伙伴以此为例向我证明编程猫比 Scratch 更先进。确实啊,例如用递归的方法求斐波那契数列第 N 项的值,在编程猫里是这么写的:

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

但在 Scratch 里,因为方法没有返回值,只能用三个全局变量记住之前方法调用的运算结果,代码就变得这么复杂:

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

 

对于一些大型项目,变量更是多得让代码都没法阅读。比如 Scratch 官网上的 griffpatch 大神的平面 MineCraft 项目,有上百个变量和几十个列表。变量中的 _x 、x、_lsx、_ScrX、x_g、x_gg,怕是大神自己也需要翻翻开发日志才能想起是干嘛用的。而其中有不少,应该就是方法没有返回值的锅:大神不得不用全局变量来记住这些方法的运算结果。

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

griffpatch大神的PaperMineCraft作品中的部分变量

 

自定义方法不带返回值,不能 OR 不为?

 

有老师认为 Scratch 受到技术局限、添不了返回值,这显然是不合理的猜测。我们见过带返回值的图形化编程,完全没理由别家做得出MIT 的团队做不出。最不济在UI层面加一层 wrapper, 把函数堆栈的实现硬塞进来就好。就算老版本曾经不带返回值,现在要新加也并不会导致向后兼容就问题(毕竟加了后也还是允许无返回的呀),所以也不存在什么“历史遗留”。

 

所以,Scratch 的自定义方法不带返回值,并非不能,那是不为吗?

 

其实从 Scratch 对“自定义方法”的称呼就可以看出端倪:

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

历史版本中的“自定义方法”,来自 Scratch 官方 wiki

 

Scratch 3.0 管这个功能叫 define my blocks,而在 1.4 版本时用的词是 Proc 也就是 Procedure。计算机术语中,procedure(过程) 和 function(函数) 的区别,正在于 procedure 是不带返回值的。

 

所以,从名称上,就可以猜测不带返回值确实是有意为之。

 

有老师质疑:它可以提供这个功能但大家不用,为什么要自废武功把返回值给去掉呢?

 

从希望 Scratch 希望培养孩子们哪些能力考虑,我有这样的猜想:

用不带参数的 procedure 锻炼孩子们拆解问题、结构化思考的能力,我猜 Scratch 团队认为这是很有必要的(同时这也是 Papert 在《因计算机而强大》这本书中反复强调的)。但让孩子们写复杂算法、提升逻辑思维能力,我猜 Scratch 团队认为它的重要性不及创造力培养。

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

Papert 书中的例子从没用过返回值

 

李泽老师的《Scratch高手密码》一书是很好的证明:李老师写了一个模拟函数堆栈调用的实现,以便在 Scratch 里能完成复杂算法。一方面,我从程序员的角度,觉得这本书书真不错,提到的程序设计原则和开发方法都是很重要的,模拟函数对战调用的实现也已经是 Scratch 中最为干净的实现方式了;另一方面,从教育者的角度,我又不得不质疑:为啥要教孩子们这些呢?培养未来码农吗?那为什么不干脆让孩子们学 Python

 

所以,Scratch 有必要自废武功吗?有!尤其是在多数人会把编程和逻辑思维挂等号的中国。李老师的书定位给中学、大学的学生和老师,完全没有问题;但如果 Scratch 添加了函数功能后,小学生们学的也尽是写斐波那契数列,那就违背了 Scratch 的初衷。

 

Resnick 教授对“低门槛”的坚持

ET 社群在上周末的 Scratch Day 上办了两场工作坊。活动结束后我终于抓住机会问了 Resnick 教授这个问题。

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

其实我有一大堆问题要问教授,但时间有限就单挑了这个教授能很快答完的

Resnick 教授肯定了“Scratch 更关注创造力培养”这一点,同时他还特别强调“低门槛”。他指出:自定义方法不只是添加一个返回值的问题,还有很多其它交互细节。例如无返回值的应该用命令式的积木,返回数字或字符串的应该是椭圆的,返回布尔值的应该是六边形的。

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

Snap! 中的自定义函数有三种类型,但一旦定义成 reporter 或 predicate,就无法直接调用,例如上图的 makeDecision 就无法接在move后面。

 

编程猫允许同时以两种方式调用函数:只要函数定义中有返回语句,就会生成一个命令式积木块和一个椭圆的积木块,应对两种不同使用场景。能力强大了,但难免造成更多困扰。

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

除了积木块的形状,还有变量作用域等等问题。

 

Resnick 教授说好几年前 Scratch 团队曾尝试过写带返回值的自定义方法,做过一些原型,但最终都对其交互不满意,认为它们会提升孩子的使用难度,带来的坏处比好处多,所以后来也就放弃了。教授说如果谁能想出添加了返回值且不引起混淆的办法,他会很乐意加入到 Scratch 中。但目前的方法,门槛都还不够低。

 

Snap! 或编程猫的做法存在更大的问题

 

其实除了 Resnick 担心的混淆问题,Snap! 和编程猫的做法有一个更严重的问题——容易引发函数副作用。

举例:孩子们想计算角色到大门(0,0)的距离并将角色移动到大门位置。下面两种写法,那种正确呢?

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

 

虽然看起来演示结果一样,但其实第二种是错误的。它错误的原因在于,当人们看到椭圆形的“求距离”函数时,是不可能预料到它竟然还会改变角色的位置。所以下面这个想要计算两盆花的距离的代码,竟也会让角色跑到大门那里去。

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

千万不要以为这是一个很容易避免的错误。事实上我在 IT 公司工作时给同事做 code review,很经常挑出的毛病就是带副作用的函数。而程序员们遇到的奇奇怪怪的 bug,也往往和这有关。

 

也许你会想:提醒大家函数内避免使用特别是修改全局状态,不就 OK 了?这不是更有利于培养孩子们清晰的“拆分问题”的思维吗?

 

事实上是:这根本办不到。虽然 Snap! 或编程猫的函数有返回值了,但却还不是真正的函数:它不支持函数内的局域变量。这导致如果要进行复杂运算,必须把中间步骤的值保存在全局变量中,把全局当成局部的来用。框架都已经如此,又怎能要求使用者避免函数副作用?

 

倒不如干脆把 My Blocks 理解为过程片段,只要命名准确表达了积木块做的事情,就算读写全局变量也能接受。

 

回归 Scratch 的教育目标

 

综上,Scratch 的自定义方法不带返回值,非不能也,是不为也。保证 Scratch 的低门槛,远比提供强大的自定义方法重要得多。

 

有老师诟病 Scratch,认为它违背了 LOgo 的初衷:连输入和输出都不强调了,还多了广播等看着花里胡哨的东西。其实我在接触 Scratch 的最初半年也曾以为画笔相关功能块是 Scratch 中最精彩的部分,像 LOgo 的小海龟一样画画并通过这来学数学是 Scratch 的最重要的作用。

 

但后来,我逐渐发现舞台、角色等的精妙。Papert 在 《因计算机而强大》一书中强调的结构化、调试、身体共鸣等等,Scratch 里都很好的继承了。若看过 Resnick 在 2017 的演讲 The Seeds That Seymour Sowed,就更能明白他其实从没有背离过 Papert 的理念。

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

Resnick 演讲的最后这段话让人泪目

Scratch 与 LOGO 的差别,恰恰是时代的差异,正如 Papert 和 Piaget 观点的差异也是时代的差异。在四十年前,Papert 考虑的是如何用计算机帮助孩子们更好的学习数学、物理等别的学科;四十年后的今天,呼唤创新、更需要 X 型人才而非 A 型人才的今天,Resnick 会更多的考虑如何用 Scratch 帮助孩子们进行创作与表达。Scratch 不只是一个让孩子们做做动画或游戏的工具,和 4P 教学法、创意螺旋结合起来提升孩子们的创造力,才是它的正确用法。

 

女儿两年级时曾问过我一个很有意思的问题:“发明 Scratch 的人怎么知道有了这些类型的积木块就够了,可以写出各种我们需要的程序来了?”虽然后来聊过后她理解了要写真正的程序并不够,但从她能提出这个问题,可以知道在一个孩子眼中 Scratch 有多强大多能满足她的需要。没法写出带返回值、带局部变量的函数?这对孩子们来说又有什么关系呢!

 

为什么Scratch的自定义方法不带返回值?我终于听到了Resnick的亲口回答

授权转载    南瓜博士

原文作者    ElfeXu


Final

————谢  谢  观  赏————


转自公众号:
Scratch 格物堂

您必须 登录 才能发表评论!