autolisp的boundp函数存在明晃晃的bug
背景
bound是bind的过去分词,bind是绑定的意思,bound就是已经绑定。
绑定在lisp中的意思,就是某个“符号”是否与一个值相对应,或者说,某个“符号”是否代表着某个值。
发送给lisp解释器interpreter的所有代码,会当作一系列“符号”来处理,interpreter
会判断这些“符号”是否与某个值绑定,
绑定了就用那个值去替换那个符号,这就是求值eval
的过程。
基于前述的eval
过程的原理,lisp interpreter
都会维护1个符号表,记录当前已经定义的符号,以及符号对应的值。
如何查看当前定义了哪些符号呢?
有1个专门的函数可以达到这个目的:atoms-family
,这个函数会返回当前已经定义所有符号。不同的lisp实现,
可能对于这个功能的函数有不同的命名,不过,通常都会提供1个拥有相同功能或者类似功能的这么样的一个函数。
boundp
函数是干啥的
根据autocad的官方帮助文档,boundp
函数接受1个符号作为入参,功能是“Verifies if a value is bound to a symbol”,
意思是“判断1个符号是否绑定了1个值”,它的返回值为t
或nil
。
t
是经典(传统、老派)lisp语言的真值,相当于其他编程语言中的boolean
型的true
,nil
则对应于false
。
某些新的lisp实现、某些lisp方言以及lisp的最大、最主流的变种scheme
,把t
和nil
改成了#t
和#f
,#t
又可以写作#true
,
#f
又可以写作#false
。
官方文档关于返回值的更进一步的说明,有3句话。
-
T if sym has a value bound to it.
如果那个符号绑定了某个值,那么就返回t
。 -
If no value is bound to sym, or if it has been bound to nil, boundp returns nil.
如果那个符号没有绑定任何值,或者,绑定的值是nil
,那么返回值就是nil
。 -
If sym is an undefined symbol, it is automatically created and is bound to nil.
如果那个符号是未定义(其他编程语言中的未声明)的符号,那么,解释器会自动创建(声明)那个符号, 并将它绑定(赋值)到nil
值。
到这里,boundp
的功能就很明确了。
简单来讲,在调用1次boundp
函数之后,1个没有身份的变量,从此就有了身份。因为,它从此就被定义了,就进入了符号表了。
boundp
的异常行为
在autolisp中,直到AutoCAD 2023版,boundp
函数,它的行为依然与官方文档的描述不相符。这里的“不相符”的意思是,
调用boundp
之后,原先不存在的符号,依然无法通过atoms-family
检索出来,仍然不存在。
所以,这就有了2种可能性,
boundp
有bug,atoms-family
有bug。
我更倾向于第1种可能,因为,atoms-family
的bug更加令人无法接受,作为1个快40年历史的编程语言来说,不太可能在atoms-family
这种非常底层的函数上留存bug。
到底是boundp
异常还是interpreter
出错
boundp
函数这个奇怪的表现,我在autocad官方论坛发帖反映之后,收到了很多脑残回复。小部分人在劝我不要纠结这个问题,
其余的占大部分比例的回复的意思都是把这个当做autolisp解释器的1个feature
特性,这是我总结之后的说法,
那些脑残的原话并不是这样的,不过,意思就是这么个意思。
那么,这个所谓的feature
到底是什么呢?
就是vm虚拟机在不该gc的时候,做了gc,把一部分有户口的变量直接干成了黑户。
为什么会是这个样子呢?
因为,对于lisp
来说,任何符号(变量)只有2种值,nil
值(假值、false
、null
、void
、undefined
)
和非nil
值(真值、t
、各种其他值),vm做gc把nil
值清理掉,这似乎是合情合理的做法。
然而,这种激进的gc策略,其实是错误的做法,完全不符合lisp
解释器的工作原理。
因此,把boundp
的这种异常行为解释成autocad的autolisp
解释器的feature
,这种说法是说不通的,
因为解释器根本不可能设计成这个样子。其他的autolisp解释器,比如zwcad中望cad,boundp
就是按照预期的方式在工作的,
原本无法从atoms-family
返回值中查询到的符号,使用boundp
之后就能够查询到了。
结论
综上,与其相信autocad的autolisp
解释器有问题,或者,这个解释器具有与众不同的特殊的feature
,
我更愿意相信是某个内置函数存在bug,比如boundp
函数。
为什么不能是atoms-family
函数有问题呢?前面已经说过了,atoms-family
函数本质上和boundp
是一个层级(等级)的底层函数,
但是,boundp
的具体实现有可能是依赖于atoms-family
做出来的,从实际操作层面上讲,atoms-family
可能比boundp
更加底层
更加接近于解释器。
基于“解释器不太可能出错”、“不允许解释器出错了几十年而不去解决”这样的大前提,只能是boundp
存在着bug却长期没有得到修复。
文章作者 Jack Hsu
上次更新 2023-11-15
许可协议 Copyright © Jack Hsu. All Rights Reserved.