dram.me

Pascal、Modula-2和Oberon-07中的函数返回值

在Wirth设计的三大语言Pascal、Modula-2和Oberon-07中,对于函数的返回语句有不同的设计,具体的模式如下:

  1. 在Pascal中,FUNCTION的返回值通过对函数名赋值指定;

  2. 在Modula-2中,去除了FUNCTION语句,返回值可以在PROCEDURE过程体中任意位置通过RETURN语句指定;

  3. 在Oberon-07中,Wirth在Modula-2的基础上,去除RETURN语句,而将返回值的指定包含到PROCEDURE定义的最后部分,这样一来,PROCEDURE ... RETURN ... END基本等同于Pascal中的FUNCTION

知识的倒金字塔模型

如果将一个行业的知识体系比作倒金字塔,底层作为基础性知识,顶层作为各种应用性知识,介于中间的是知识的衍生以及基础应用的组合。

在知识学习中,知识的广度和深度是经常被强调的概念,但“深度”的概念是模糊的,很容易会直接将其简单地映射到对于基础知识的掌握。位于底部的基础性知识和原理很重要,但可能更为重要的是原理和应用之间的关联,也就是连通底层和顶层的纵向的线。

那么应该如何学习呢?完全的自底向上或者自顶向下都不是合适的方式。自底向上的模式有较高的难度,而自顶向下的学习速度缓慢。需要通过某一个点深入理解,从纵向打通。其中重要的一部分内容是理解单一知识链在不同层次间知识点的关联关系。

对纵向关联的理解可能包括两个层次。第一层次是对上下层知识的直接关联,可以称之为“术”。第二层次是发现这些关联中的内在的、规律性的联系,可以称之为“道”。

学校的教育往往侧重于基础性的知识,而工作上的知识往往是顶层的应用性知识,所以个人自学则往往会浅尝辄止。

通过对纵向关联的不断积累,找到其中的规律性,可以从上层应用推测出底层的原理,也可以从底层知识发散出基于其的应用。

关于设计的轨迹和原理

在《设计原本》第16章中,Frederick Brooks强调了记录设计轨迹及其背后原理的重要性。

这一点非常重要,但真要实施起来却也非常困难。例如在开源项目中,大量的知识和信息都隐藏在项目发展的过程中。虽然借助于版本管理、项目管理、bug跟踪等工具和系统,有部分信息被记录了下来,但依然有很大的遗漏,另外记录的信息也是相对零散的。

在邮件记事存储系统构想中,也曾提到借由“补遗”记录过程的方式。但总体感觉这种方式更适合于个人使用。

这里举一个记录历史的重要性的例子。当前RESTful API的使用已经非常广泛,在RESTful中,将传统的CRUD操作映射到HTTP的POSTGETPUTDELETE方法。

由于没有系统性学习过RESTful,一直以来我认为在RESTful中PUT方法被设定为支持部分更新。而实际上RESTful的设计者Roy Fielding是将PUT指定为全量更新,而HTTP/1.1新增的PATCH方法也是Roy Fielding提出的,正是作为PUT的补充。

所幸的是,这一重要历史信息被记录在RFC 5789的附录中。由此可以对PUTPATCH在RESTful API中的应用有更深入的理解。

关于概念完整性

概念完整性是Frederick Brooks《人月神话》以及之后的《设计原本》中都一直非常强调的设计理念。

但想要保证概念完整性难度非常大。下面来说说最近接触到的一个例子。

Wirth设计的系列语言有高度的概念完整性,例如Pascal、Modula-2和Oberon。这些语言有一个共同特点,就是非常强调安全性:例如类型安全、边界检查等。

安全性这一概念在Wirth的语言设计中有很好的贯彻(除个别情况外,例如Modula-2符号数与非符数兼容,这里为了便捷性放弃了部分安全性)。但在此基础上开发的系统库,有时就没有将这一理念很好地保持。比如多个实现中包含的Strings.Assgin方法在存储溢出时不是抛出错误而是自动截断字符串,再如整数转字符串的过程中如果存储不足也会发生自动截断。

Wirth语言家族

补遗

  1. 重新引入Pascal中FUNCTION的概念,只是语义上更为严格,在不允许赋值非本地变量的基础上,同时也不能在函数体中调用其他PROCEDURE、不能包含VAR参数。—— 2017-01-12

  2. 设计原则上确保只做有意义的更改,例如不考虑语法层面无谓的改动。—— 2017-01-12

  3. 借鉴Component Pascal中的INOUT参数的机制。在IN参数不能更改和OUT需要未初始化的基础上,去处VAR变量。这样传参包括三种方式:值传递、只读引用、可写引用。这样也部分实现了单次赋值的机制。增加这些限制后,如果有需要对数据多次处理的情况,不能再多次传入过程,可以借助子过程规避,对子过程来说,外层参数不是入参,可以在多个子过程中对其处理。—— 2017-01-12

  4. 前期也可以考虑基于P5实现,ACK的Pascal作为bootstrap使用。—— 2017-01-15

Pascal的设计者Niklaus Wirth设计过多种编程语言,但设计的思路是一以贯之的。详细的列表可以参考这里

另外还有一块是直接基于Wirth的语言发展设计的语言。例如ISO Pascal、ISO Extended Pascal、ISO Modula-2、Modula-3、Oberon-2、Component-Pascal等。

每一种语言都有它特定的理念和目标领域。我现在考虑是否可以在Modula-2的基础上设计新的语言(暂命名为Modo),主要基于以下想法:

  1. 继承Wirth语言安全性的特性(据此Modula-2 variant record的特性是否需要保留需要考虑下,可以借鉴Mesa对此的处理,另外Algol-68以及新近语言多有采用的类型枚举机制也可以考虑);

  2. 继承Wirth语言简洁的特性(直观、易于学习、易于全然掌握,据此倾向于使用传统的命令式语言,而不引入复杂的类型系统、函数式、以及面向对象特性,也因此不采用Oberon中的可扩展结构体的对象特性);

  3. 贯彻自顶向下的编程模式(所以继承Modula-2模块定义和实现分离的模式,而不采用Oberon中两者整合的方式);

  4. 保持一定的便捷性(例如可以便捷地对数组和结构体赋值,可以参考Algol-68、Mesa、ISO Pascal、ISO Modula-2的设计,再如可以在文件中包含多个模块,只有模块定义文件中包含的模块为对外可见,其他为私有模块,再如增加STRING类型)。

实现方面,暂时考虑基于NuttX项目的Pascal,并借鉴参考ACK中的Modula-2以及Pascal-P5实现。

← older posts