一种语言可以有编译时检查但具有动态类型的特性吗

Can a language ever have compile-time checking but the characteristics of dynamic typing?

本文关键字:动态 类型 检查 编译 一种 语言      更新时间:2023-10-16

读取以下内容后:

很多人在定义静态类型和动态类型时到检查变量类型的点。使用此类比,静态类型语言是那些类型检查在编译时完成,而动态类型语言是该类型检查是在运行时完成的。

这个类比导致了我们在上面定义静态和动态键入。我相信理解静态和根据需要显式声明的动态类型变量,而不是作为编译时和运行时类型检查。

我在想,我们定义静态和动态类型的两种方式:编译时检查和显式类型声明有点像苹果和桔子。所有静态类型语言的一个特点(据我所知)是引用变量具有定义的类型。有没有一种语言既有编译时检查的好处(比如Java),又能让变量无限绑定到特定类型(比如Python)?

注意:在Java这样的语言中,并不完全是类型推理,因为变量仍然被指定了一个类型,只是隐式的。这种理论语言不会有引用类型,因此不会有强制转换。我试图避免使用"静态类型"answers"动态类型",因为混淆了。

可能存在,但应该存在吗?

假设伪C++中的想象:

class Object
{
public:
    virtual Object invoke(const char *name, std::list<Object> args);
    virtual Object get_attr(const char *name);
    virtual const Object &set_attr(const char *name, const Object &src);
};

你有一种安排的语言:

  • 使Object类成为所有类的根基类
  • blah.frabjugate()转化为blah.invoke("frabjugate")的句法糖
  • blah.x = 10转换为blah.set_attr("x", 10)

再加上一些结合了boost::variant和boost::any属性的东西,你就有了一个很好的开始。Python的所有动态性(好的和运行时的bug坏的),以及C++或Java的雄辩和刚性(耶!)。与调用/jmp机器指令相比,增加了哈希表查找的运行时膨胀和效率。

在Python等语言中,当您调用blah.do_it()时,它必须对字符串"do_it"进行潜在的多个哈希表查找,以确定每次调用实例blah或其类时是否有一个名为"doit"的可调用对象。这是可以成像的最极端的后期结合:

flarg.do_it() # replaces flarg.do_it()
flarg.do_it() # calls a different flarg.do_it()

您可以让您的假设语言对绑定发生的时间进行一些控制。类似C++的标准方法是粗略地静态绑定到表观引用类型,而不是实际实例类型。C++虚拟方法是后期绑定到对象实例类型的。类似Python的属性和方法非常后期绑定到对象实例的当前版本。

我认为你肯定可以用动态风格的强静态类型语言编程,就像你可以用C++或Java之类的语言构建解释器一样。一些语法挂钩可以使它看起来更加无缝。但也许你也可以反过来做:也许是一个自动检查参数类型的Python装饰器,或者是一个在编译时进行检查的MetaClass?[不,我认为这不可能…]

我认为你应该把它看作是一个特征的结合但你会得到最好的两个世界中最糟糕的。。。

有没有一种语言既有编译时检查的好处(比如Java),又能让变量无限绑定到特定类型(比如Python)?

事实上,大多数语言都支持两者,所以是的。不同之处在于哪种形式是优选的/更容易的和通常使用的。Java喜欢静态类型,但也支持动态类型转换和反射。

这种理论语言不会有引用类型,因此不会有强制转换。

你必须考虑到语言也需要表现得相当好,所以你必须考虑如何实现它们。你可以有一个超级类型,但这会使优化变得非常困难,你的代码很可能要么运行缓慢,要么使用更多的资源。

更流行的语言倾向于做出务实的实现选择。他们不是纯粹的一种或另一种类型,即使他们不像"纯粹"的语言那样干净地处理风格,他们也愿意借用风格。

它们到底允许编译器或程序员做什么,而动态类型不能做什么?

人们普遍认为,越快发现错误,修复成本就越低。当你第一次开始编程时,维护成本在你的脑海中并不高,但一旦你有了更多的经验,你就会意识到一个成功的项目的维护成本远高于开发成本,修复长期存在的错误可能会非常昂贵。

静态语言有两个优点

  • 你迟早会发现虫子。越快越好。使用动态语言,如果代码从未运行过,您可能永远不会发现错误
  • 维护成本更容易。静态语言使最初编写代码时的假设更加清晰,并且如果您没有足够的测试覆盖率,则更有可能检测到问题(顺便说一句,您永远不会有足够的测试复盖率)

不可以。这里的区别可以归结为早期绑定和晚期绑定。早期绑定意味着在二进制级别上预先匹配所有内容,并在代码中进行修复。其结果是严格的、类型安全的和快速的代码。后期绑定意味着涉及某种运行时解释。这导致了灵活性(潜在的不安全性),并以性能为代价。

这两种方法在技术层面上是不同的(编译与解释),程序员必须选择何时需要,这将使两者都无法发挥作用。

然而,在使用(公共)语言运行库的语言中,您确实可以通过反射获得一些所需的内容。但它的组织方式不同,仍然是类型安全的。它不是你所指的那种隐含的绑定,而是需要程序员做一些工作和提高意识。

对于静态类型来说可能的是动态类型不可能的:什么都没有。它们都是图灵完全

静态类型的价值在于及早发现错误。在Python中,只有在运行程序时,才会发现拼写错误的名称这样简单的东西,即使在运行了拼写错误的代码行时也是如此。

class NuclearReactor():
  def turn_power_off(self):
    ...
  def shut_down_cleanly(self):
    self.turn_power_of()