【问题标题】:Can a language ever have compile-time checking but the characteristics of dynamic typing?一种语言能否具有编译时检查但具有动态类型的特征?
【发布时间】:2016-04-05 21:44:24
【问题描述】:

阅读以下内容:

很多人对静态类型和动态类型的定义是尊重的 到检查变量类型的点。使用这个 类比,静态类型语言是那些类型检查是 在编译时完成,而动态类型语言是在 哪种类型检查在运行时进行。

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

Source

我在想我们定义静态和动态类型的两种方式:编译时检查和显式类型声明有点像苹果和橘子。所有静态类型语言的一个特征(据我所知)是引用变量具有定义的类型。是否有一种语言既具有编译时检查的优点(如 Java),又能够使变量不受特定类型的限制(如 Python)?

注意:在像 Java 这样的语言中并不完全是类型推断,因为变量仍然被分配了一个类型,只是隐式的。这种理论语言没有引用类型,所以不会有强制转换。由于混淆,我试图避免使用“静态类型”与“动态类型”。

【问题讨论】:

  • 那篇文章不太好。尤其是作者把“声明”、“定义”和“初始化”混为一谈,弄得大部分都是错的。
  • 是的,你是对的。它只是引发了一个问题:是否有一种语言结合了 Python 的动态类型的思想,但也像 Java 一样提供编译时检查的好处?
  • 给您的问题:您如何使该语言的两个“部分”相互作用? “类型化”部分如何处理非类型化值?
  • @Mat - 它就像 Python,但在编译时进行检查。我的问题是这可能吗?
  • 如果值的类型是在运行时确定的,如何在编译时进行类型检查?您无法验证您没有的信息。

标签: java c# c++ oop types


【解决方案1】:

可能有,但应该有吗?

想象一下假设的伪 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 的所有动态性(好的和坏的运行错误)都具有 C++ 或 Java 的雄辩和僵硬(耶!)。与 call/jmp 机器指令相比,增加了运行时膨胀和哈希表查找的效率。

在像 Python 这样的语言中,当您调用 blah.do_it() 时,它必须对字符串“do_it”进行潜在的多个哈希表查找,以确定您的 instance 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? [不,我不认为这是可能的......]

我认为您应该将其视为功能的结合。 但你会得到最好的两全其美的...

【讨论】:

    【解决方案2】:

    是否有一种语言既具有编译时检查的优点(如 Java),又具有使变量不受特定类型限制的能力(如 Python)?

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

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

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

    更流行的语言倾向于做出务实的实现选择。它们不是纯粹的一种或另一种类型,并且愿意借用样式,即使它们不像“纯”语言那样干净利落地处理它们。

    它们究竟允许编译器或程序员做哪些动态类型不能做的事情?

    普遍认为,越快发现错误,修复的成本就越低。当您第一次开始编程时,您认为维护成本并不高,但是一旦您拥有更多经验,您就会意识到一个成功的项目的维护成本远远高于开发和修复长期存在的错误的成本。代价高昂。

    静态语言有两个优点

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

    【讨论】:

    • 确实如此,但我难以理解的是静态类型的需求——它们究竟允许编译器或程序员做什么而动态类型却不能?我从来没有完全了解引用类型的原因。这可能是一个扩展的答案,所以如果有什么地方我可以找到答案......
    • @rb612 相反,我从来不明白人们是如何忍受动态语言的。 ;) 如果您没有提供参考类型,例如Object您将如何以安全或有效的方式使用它?
    • 这绝对是另一种思考的好方法! :D 但是来自维基百科:“据说一种编程语言在编译时而不是运行时执行类型检查时使用静态类型。在静态类型中,类型与变量而不是值相关联。“感谢您的编辑 -有没有办法可以解释为什么会这样,静态类型具有与变量关联的类型?
    • @rb612 静态类型可以通过分配寄存器或所需资源来优化,因为它确切地知道类型是什么以及需要多少空间。你对类型有什么疑问?顺便说一句,您提到的所有语言都有。 C 例如没有动态检查类型。
    • 没有明确类型的引用只是一个指针。你(或者更好的是,编译器)可以用它做什么?在知道它指向什么之前什么都没有。知道它指向什么就是给它一个类型。
    【解决方案3】:

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

    这两种方法在技术层面上是不同的(编译与解释),程序员必须选择何时需要哪一种,这会破坏同时拥有这两种方法的好处。

    在使用(通用)语言运行时的语言中,您确实可以通过反射获得一些您所要求的内容。但它的组织方式不同,并且仍然是类型安全的。这不是您所指的隐式绑定,但需要程序员的一些工作和意识。

    【讨论】:

      【解决方案4】:

      就动态类型不可能的静态类型而言:没有。它们都是图灵完备的

      静态类型的价值在于尽早发现错误。在 Python 中,只有在运行程序之前,不会捕获像拼写错误的名称这样简单的事情,即便如此,只有在运行拼写错误的代码行时才会被捕获。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-03
        • 1970-01-01
        • 2011-02-09
        • 1970-01-01
        • 2019-06-13
        • 2020-12-25
        • 1970-01-01
        • 2016-11-19
        相关资源
        最近更新 更多