【问题标题】:How do we determine a language is dynamic or static? an example is Swift我们如何确定一种语言是动态的还是静态的?一个例子是斯威夫特
【发布时间】:2019-03-18 01:15:17
【问题描述】:

我一直在阅读一些帖子,但总是让我感到困惑。

1,有人说一种语言是静态/动态的,取决于type 在运行时或编译时的确定方式。但是我们应该说语言是static/dynamic typing language 而不是static/dynamic language

2,在 swift 与 Objective-c 的一些比较中。我们知道,objective-c 使用它的运行时来进行动态方法分派。还有人以此为由说language/objective-c is dynamic,这是真的吗?!

3,我有时对 OOP 的多态性感到困惑,有人说为了使其工作,该语言必须支持方法动态调度。是这样吗?

4,对于 swift,我知道它是一种静态类型语言,但它是静态还是动态方法调度语言?它是静态语言还是动态语言??

【问题讨论】:

  • 即使是静态类型的语言也有动态调度。明显的例子:Swift、ObjC。如果您有let car: Car = SportsCar(),并且您调用car.vroom(),则运行时必须动态调度该方法调用,以确定正确的方法实现是什么。该类型仍然是静态已知的:它是Car,或者它的某个子类型。
  • @Alexander 我想这是对我的问题 #3 的部分回答。根据您的描述,听起来如果该语言支持 OOP 的多态性,这意味着该语言能够method dynamic dispatch。但总是这样吗?

标签: objective-c swift oop


【解决方案1】:
  1. 我从未听说过“静态语言”或“动态语言”这个词。我听说过的常用术语是“静态类型语言”或“动态类型语言”。

  2. “动态”在这个上下文中不是一个定义的术语,所以这里没有太多要说的。

  3. 多态有多种不同的含义,所以我假设你的意思是subtype polymorphism。在这种情况下,是的,动态调度是必要的。整个想法是,您希望不同类型的对象以自己的方式响应相同的消息(方法调用)。做到这一点的唯一方法是将消息和函数调用解耦,以便在运行时根据消息接收者的类型调用适当的函数。

  4. Swift 是一门静态类型的语言,贯穿始终。这可能会被类型推断所掩盖。如果你有这样的表达方式

     func someFunction() -> Int { return 123 }
     let x = someFunction()
    

    类型推断并不意味着“x 有某种类型会在运行时被计算出来。”相反,它的意思是“x的类型可以在运行时推断出来,因为我们已经知道someFunction的类型。”

    Swift 中的所有类型在编译时都是已知的。在最坏的情况下,a 必须至少具有类型Any,它仍然是一个类型。它不是一个特别有用的类型(因为没有多少 Any 保证能够做到),但它仍然是一个类型。

    在编译时类型和运行时类型的讨论中存在一些混淆。这是一个例子:

         class Car {
             func vroom() { print("vroom") }
         }
    
         class SportsCar: Car {
             override func vroom() { print("VROOOOOM") }
         }
    
         let car: Car = SportsCar()
    
         func driveSportsCar(_: SportsCar) { print("driving") }
         // Compile types are what determine usage compatibility
         driveSportsCar(car) // ? cannot convert value of type 'Car' to expected argument type 'SportsCar'
    
         // Runtime types are what determine method implementations
         car.vroom() // => "VROOOOOM"
    

    在此示例中,car 的编译时类型为 Car,运行时类型为 SportsCar。编译时类型决定了它可以如何使用,它可以传递到哪里等等。例如,你不能将car传递给driveSportsCar()函数,因为即使它的运行时类型是SportsCar,它的编译时间类型为Car,不兼容。

    对象的运行时类型决定了要调用的方法实现。

【讨论】:

  • 谢谢,但我还是有点困惑,尤其是来自 stackoverflow.com/questions/29924477/… 的 41 次投票。他说 swift 是静态的,因为它在编译时是静态类型,这对我来说很有意义。但是,他接着说 Objective-c 是动态的,因为你可以进行方法调配等。他使用了“swift 是静态的,目标是动态的”这样的术语,这与你所说的相矛盾,这让我更加困惑。跨度>
  • 我认为混淆源于术语“动态”和“静态”,它们没有真正定义(与“动态类型”、“静态类型”不同)。 Objective C 和 Swift 一样是静态类型的。他们在这方面没有区别。不同之处在于,Objective C 没有利用静态类型信息来静态分派方法。这样做会使系统运行得更快,但会禁止你在运行时做的所有很酷的事情(在运行时创建新的子类、方法调配、代理对象、方法转发等)。
  • 从根本上说,Objective C 运行时是一个可以拦截所有方法调用的单点。在 Objective C 中,all 方法调用通过objc_msgSend(及其变体)。这样做的好处是您有一个可以进行更改的地方。类具有关联方法名称(选择器)和函数指针(实现的)的方法表。如果你想调配两种方法,你只需交换名称到函数指针的映射。由于所有方法调用总是在这些表中进行查找,所有调用都会立即受到影响
  • 另一方面,如果您允许方法内联和其他优化(Swift 大量使用),那么您会将单个方法的主体“复制粘贴”到一大堆地方。这样做无需跳转指令、保存先前的寄存器、恢复寄存器和返回。它使您的代码更快,但您失去了单个拦截点的便利。如果不对应用程序二进制文件进行一些不可能的边界修改(以交换适当的指令),您就无法调整这些方法。
  • 因此 Objective C 可以说是更“动态”,因为它支持运行时特性而不是性能,而 Swift 则非常支持性能。但是,在 Swift 中,您有 dynamic 关键字,可以根据需要“选择加入”运行时功能。但同样,这并不是一个严格定义的术语。这只是一种特定设计优先级高于其他设计的模式。
【解决方案2】:
  1. Swift 是一种静态“类型化”语言,这意味着它会在运行时执行类型检查。
  2. Swift 根据不同的情况使用直接派发、带有见证表的表派发或消息派发(obj-c),你可以看看这篇文章:https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/ 一些例子已经过时,但概念会说得更清楚
  3. 静态分派不支持多态性,因为它需要知道在编译时将执行哪个方法的实现。 希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-12
    • 2019-07-12
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 2022-08-11
    • 1970-01-01
    • 2012-12-29
    相关资源
    最近更新 更多