变量设计二事

创建于 8/17/2023

编程语言的变量,我认为更好的设计

一、变量不应可变

当前大多编程语言,变量都可变。我想,这不好。变量应当不可变。

怎么办?

变量不可变了,那怎么变?当然不是让全部人去用 Haskell。要的是 OCaml。

变量不可变,对象的属性依然可变啊!完全可以实现以下功能:

js
const a = ref(1)
a.content // 1
a.content = a.content + 1

更进一步,提供语法糖:

js
!a // 1
a := !a + 1

为啥办?

JavaScript 常有问题:

js
for (var i = 0; i < 10; i++)
    setTimeout(() => console.log(i), 10)
// 为何上下两段不一样?!!
for (let i = 0; i < 10; i++)
    setTimeout(() => console.log(i), 10)

如果变量不可变,则无问题。有问题也一眼可知:

js
// 无问题
forRange(0, 10, 1, i =>
    setTimeout(() => console.log(i), 10))
// 一眼可知,i从头到尾都是同一个ref
for (const i = ref(0); !i < 10; i := !i + 1)
    setTimeout(() => console.log(!i), 10)

于是,“更改对象的属性”和“更改变量”,成了同一件事。一切变得更直白了!

没有了“引用类型”“按引用调用”之争。闭包捕获也更加简单、清晰。

同时,还避免了没有指针带来的问题:如何把“给变量赋值的权限”交出去?

有指针的语言,就会好一些,无此问题。

二、变量 Shadow

大多编程语言,不允许作用域中变量重名。美其名曰避免错误。但是,此中语言,大都支持作用域中的变量与作用域外的变量重名。这是双标。如下:

js
let a = 1;
// let a = 2; 错误!
{
    let a = 3; // 欸!这就可以了!
}

我认为,现代的编程语言,不应如此。或者允许变量 Shadow,像 Rust 一样;或者禁止定义当前能访问到的变量,像 Zig 一样。

做到前者无技术含量,后者就可能有历史包袱。

JavaScript 可能难以做到后者。因其无法知道全局变量存在与否,需动态检查。若是运行到一半,全局环境被改了,于是莫名其妙地显出重定义错误,岂不怪哉?!

不知 C 是否能做到后者?