代码之家  ›  专栏  ›  技术社区  ›  patzi

理解smalltalk中奇怪的逻辑运算符

  •  0
  • patzi  · 技术社区  · 6 年前

    所以我的问题是:

    当char=0时

    boolean = char ~= 0 & char ~= 256
    

    计算结果为true,如果我将语句反转为这样:

    boolean = char ~= 256 & char ~= 0
    

    我变假了。

    发生了什么事?。我希望这两种情况都是假的。

    2 回复  |  直到 6 年前
        1
  •  4
  •   Leandro Caniglia Charlie    6 年前

    正如@Uko所说,您必须了解消息的优先级:所有二进制消息(+=<~=等…)从左到右求值。

    因此,您评估:

    (((boolean = char) ~= 256) & char) ~= 0
    

    我想你是在追求:

    boolean := (char ~= 256) & (char ~= 0).
    

    那么你的表情呢?

    • boolean 可能是单位化的(因此为零)
    • char 为0。
    • boolean = char 是假的。
    • false ~= 256 是真的。
    • true & char 是char(见下文why)
    • char ~= 0 为false(因为char=0)

    如果反转0和256,则只有最后一步发生变化,并且为true。

    有趣的部分是消息的实现;在类True中:它可能不会断言参数是布尔值,看起来像:

    & aBoolean
        ^aBoolean
    

    如果你传递的不是布尔值的东西(比如你的例子中的0),它会返回这个东西,不管它是什么样的令人惊讶。。。

    如果您使用IDE(Squeak/Pharo/Visualworks/Dolphin…但不是gnu Smalltalk),我建议您使用菜单 Debug It 并在调试器中逐步计算表达式。

    最后,请注意,char在Smalltalk上下文中可能不是一个好名字:它可能会引起误解。实际上,如果它包含0,那么它是一个整数,而不是一个字符。

        2
  •  3
  •   Leandro Caniglia Charlie    6 年前

    我们在一些回答中重复了一些东西,我认为值得进一步澄清。我们说 评估从左向右进行 . 没错,但消息的实际语义是:

    首先评估接收者,然后依次评估参数;最后发送消息。

    由于Smalltalk虚拟机是基于堆栈的,因此该规则意味着:

    1. 首先评估接收器,并将结果推送到堆栈上。
    2. 参数按顺序求值,其结果推送到堆栈上。

    第3项意味着send调用的方法将按照上面定义的顺序在堆栈中查找接收方和参数。

    例如,在

    a := 1.
    b := 2.
    b := a - (a := b)
    

    变量 b 将评估为 (1 - (a := 2)) = -1 a 2 . 为什么?因为到任务完成的时候 a := b 由接收器评估 减法的值已经用当时的值推送,即。, 1 .

    还要注意,即使虚拟机碰巧使用寄存器而不是堆栈,也必须保留这种语义。原因是,求值必须保留语义,从而保留顺序。这一事实对本机代码可能实现的优化有影响。

    有趣的是,观察到这种语义和优先一元>二进制>关键字以简单的方式支持多态性。一种更优先于,例如, * + 假设 * 是乘法和 + 添加。然而,在Smalltalk中,由程序员决定这些(和任何其他)选择器的含义,而不需要语法妨碍实际语义。

    我的观点是,“从左到右”来自于我们用英语写的Smalltalk,它是从“左到右”阅读的。如果我们使用一种人们从“右到左”阅读的语言来实现Smalltalk,那么这条规则就会被违背。实际定义 将保持不变 ,是上面第1项、第2项和第3项中表达的,来自堆栈隐喻。