鸭子打字,必须是动态的吗?

发布于 2024-08-15 22:50:59 字数 1451 浏览 16 评论 0原文

维基百科过去常说*关于duck-typing

在计算机编程中 面向对象的编程语言, 鸭子打字是一种动态风格 输入当前对象的位置 方法和属性集 确定有效的语义,而不是 比它从特定的继承 特定的类或实现 界面。

(*编者注:自从这个问题发布后,维基百科文章已被编辑以删除“动态”一词。)

它谈到了结构类型

结构类型系统(或 基于属性的类型系统)是一个主要的 类型系统的类,其中类型 兼容性和等效性是 由类型的结构决定, 而不是通过显式声明。

它将结构子类型与鸭子类型进行了对比:

[结构系统]与 ...鸭子打字,其中只有 访问结构的一部分 检查运行时的兼容性。

然而,在我看来,术语“鸭子类型”至少直观地包含了结构子类型系统。事实上维基百科说:

概念名称[duck-typing] 指鸭子测试,归因于 詹姆斯·惠特科姆·莱利 (James Whitcomb Riley) 可以表述为 如下:“当我看到一只鸟走路时 像鸭子一样游泳像鸭子一样 像鸭子一样嘎嘎叫,我称那只鸟为 鸭子。”

我的问题是:为什么我不能将结构子类型称为鸭子类型?是否存在不能也归类为鸭子类型的动态类型语言?

后记:

As reddit.com 上有一个名为 daydreamdrunk 的人,因此雄辩地提出-it“如果它像鸭子一样编译并且像鸭子一样链接......”

Post-postscript

许多答案似乎基本上只是重复我已经在这里引用的内容,而没有解决更深层次的问题问题是,为什么不使用术语“鸭子类型”来涵盖动态类型和结构子类型?如果您只想谈论鸭子类型而不是结构子类型,那么就称呼它是什么:动态成员查找我的问题是,鸭子类型这个术语对我来说没有任何意义,这只适用于动态语言。

Wikipedia used to say* about duck-typing:

In computer programming with
object-oriented programming languages,
duck typing is a style of dynamic
typing in which an object's current
set of methods and properties
determines the valid semantics, rather
than its inheritance from a particular
class or implementation of a specific
interface.

(* Ed. note: Since this question was posted, the Wikipedia article has been edited to remove the word "dynamic".)

It says about structural typing:

A structural type system (or
property-based type system) is a major
class of type system, in which type
compatibility and equivalence are
determined by the type's structure,
and not through explicit declarations.

It contrasts structural subtyping with duck-typing as so:

[Structural systems] contrasts with
... duck typing, in which only the
part of the structure accessed at
runtime is checked for compatibility.

However, the term duck-typing seems to me at least to intuitively subsume structural sub-typing systems. In fact Wikipedia says:

The name of the concept [duck-typing]
refers to the duck test, attributed to
James Whitcomb Riley which may be phrased as
follows: "when I see a bird that walks
like a duck and swims like a duck and
quacks like a duck, I call that bird a
duck."

So my question is: why can't I call structural subtyping duck-typing? Do there even exist dynamically typed languages which can't also be classified as being duck-typed?

Postscript:

As someone named daydreamdrunk on reddit.com so eloquently put-it "If it compiles like a duck and links like a duck ..."

Post-postscript

Many answers seem to be basically just rehashing what I already quoted here, without addressing the deeper question, which is why not use the term duck-typing to cover both dynamic typing and structural sub-typing? If you only want to talk about duck-typing and not structural sub-typing, then just call it what it is: dynamic member lookup. My problem is that nothing about the term duck-typing says to me, this only applies to dynamic languages.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

栖迟 2024-08-22 22:50:59

C++ 和 D 模板是非动态鸭子类型的完美示例。肯定是:

输入其中
对象的当前方法集和
属性决定有效
语义,而不是其继承
来自特定班级或
实施具体的
界面。

您没有显式指定您的类型必须继承的接口才能实例化模板。它只需要具有模板定义中使用的所有功能。然而,一切都会在编译时得到解决,并编译为原始的、难以理解的十六进制数字。我称之为“编译时鸭子类型”。我已经从这种心态编写了整个库,即隐式模板实例化是编译时鸭子类型,并认为它是最不受重视的功能之一。

C++ and D templates are a perfect example of duck typing that is not dynamic. It is definitely:

typing in which an
object's current set of methods and
properties determines the valid
semantics, rather than its inheritance
from a particular class or
implementation of a specific
interface.

You don't explicitly specify an interface that your type must inherit from to instantiate the template. It just needs to have all the features that are used inside the template definition. However, everything gets resolved at compile time, and compiled down to raw, inscrutable hexadecimal numbers. I call this "compile time duck typing". I've written entire libraries from this mindset that implicit template instantiation is compile time duck typing and think it's one of the most under-appreciated features out there.

神经大条 2024-08-22 22:50:59

结构类型系统

结构类型系统将一个完整类型与另一个完整类型进行比较,以确定它们是否兼容。为了使 AB 两种类型兼容,AB 必须具有相同的结构 - 即, AB 上的每个方法都必须具有相同的签名。

鸭子类型

对于当前的任务,鸭子类型认为两种类型是等效的(如果它们都可以处理该任务)。对于两种类型 AB 相当于一段想要写入文件的代码,AB< /code> 两者都必须实现 write 方法。

摘要

结构类型系统比较每个方法签名(整个结构)。鸭子类型比较与特定任务相关的方法(与任务相关的结构)。

Structural Type System

A structural type system compares one entire type to another entire type to determine whether they are compatible. For two types A and B to be compatible, A and B must have the same structure – that is, every method on A and on B must have the same signature.

Duck Typing

Duck typing considers two types to be equivalent for the task at hand if they can both handle that task. For two types A and B to be equivalent to a piece of code that wants to write to a file, A and B both must implement a write method.

Summary

Structural type systems compare every method signature (entire structure). Duck typing compares the methods that are relevant to a specific task (structure relevant to a task).

音栖息无 2024-08-22 22:50:59

鸭子类型意味着如果它恰好适合,那就没问题

这适用于动态类型

def foo obj
    obj.quak()
end

或静态类型的编译语言

template <typename T>
void foo(T& obj) {
    obj.quak();
}

要点是,在这两个示例中,都没有有关给定类型的任何信息。仅当使用时(无论是在运行时还是编译时!),都会检查类型,如果满足所有要求,则代码可以工作。值在声明时没有显式类型

结构类型依赖于显式类型您的值,就像往常一样 - 区别只是具体类型不是通过继承来标识的,而是通过它的结构来标识的。

上面示例的结构类型代码(Scala 风格)是:

def foo(obj : { def quak() : Unit }) {
    obj.quak()
}

不要将此与 OCaml 等结构类型语言将其与类型推断相结合以防止我们显式定义类型的事实相混淆。

Duck typing means If it just fits, it's OK

This applies to both dynamically typed

def foo obj
    obj.quak()
end

or statically typed, compiled languages

template <typename T>
void foo(T& obj) {
    obj.quak();
}

The point is that in both examples, there has not been any information on the type given. Just when used (either at runtime or compile-time!), the types are checked and if all requirements are fulfilled, the code works. Values don't have an explicit type at their point of declaration.

Structural typing relies on explicitly typing your values, just as usual - The difference is just that the concrete type is not identified by inheritance but by it's structure.

A structurally typed code (Scala-style) for the above example would be

def foo(obj : { def quak() : Unit }) {
    obj.quak()
}

Don't confuse this with the fact that some structurally typed languages like OCaml combine this with type inference in order to prevent us from defining the types explicitly.

清风疏影 2024-08-22 22:50:59

我不确定它是否真的回答了你的问题,但是......

模板化的 C++ 代码看起来非常像鸭子类型,但它是静态的、编译时的、结构化的。

template<typename T>
struct Test
{
    void op(T& t)
    {
        t.set(t.get() + t.alpha() - t.omega(t, t.inverse()));
    }
};

I'm not sure if it really answers your question, but...

Templated C++ code looks very much like duck-typing, yet is static, compile-time, structural.

template<typename T>
struct Test
{
    void op(T& t)
    {
        t.set(t.get() + t.alpha() - t.omega(t, t.inverse()));
    }
};
魂归处 2024-08-22 22:50:59

据我了解,结构类型被类型推断器等用来确定类型信息(想想 Haskell 或 OCaml),而鸭子类型本身并不关心“类型”,只是它可以处理特定的方法调用/属性访问等(想想 Ruby 中的 respond_to? 或 Javascript 中的功能检查)。

It's my understanding that structural typing is used by type inferencers and the like to determine type information (think Haskell or OCaml), while duck typing doesn't care about "types" per se, just that the thing can handle a specific method invocation/property access, etc. (think respond_to? in Ruby or capability checking in Javascript).

鸩远一方 2024-08-22 22:50:59

某些编程语言中总会有违反各种术语定义的示例。例如,ActionScript 支持对技术上非动态的实例进行鸭子类型编程。

var x:Object = new SomeClass();
if ("begin" in x) {
    x.begin();
}

在这种情况下,我们在调用“x”中的对象实例而不是使用接口之前测试它是否具有“begin”方法。这在 ActionScript 中有效,并且几乎是鸭子类型,即使类 SomeClass() 本身可能不是动态的。

There are always going to be examples from some programming languages that violate some definitions of various terms. For example, ActionScript supports doing duck-typing style programming on instances that are not technically dynamic.

var x:Object = new SomeClass();
if ("begin" in x) {
    x.begin();
}

In this case we tested if the object instance in "x" has a method "begin" before calling it instead of using an interface. This works in ActionScript and is pretty much duck-typing, even though the class SomeClass() may not itself be dynamic.

海未深 2024-08-22 22:50:59

在某些情况下,动态鸭子类型和类似的静态类型代码(即 C++ 中)的行为有所不同:

template <typename T>
void foo(T& obj) {
    if(obj.isAlive()) {
        obj.quak();
    }
}

在 C++ 中,对象必须同时具有 isAlivequak 方法用于编译代码;对于动态类型语言中的等效代码,如果 isAlive() 返回 true,则对象只需要具有 quak 方法。我将其解释为结构(结构类型)和行为(鸭子类型)之间的差异。

(然而,我通过从表面上理解维基百科的“鸭子类型必须是动态的”并试图使其有意义来达到这种解释。隐式结构类型是鸭子类型的另一种解释也是连贯的。)

There are situations in which dynamic duck typing and the similar static-typed code (in i.e. C++) behave differently:

template <typename T>
void foo(T& obj) {
    if(obj.isAlive()) {
        obj.quak();
    }
}

In C++, the object must have both the isAlive and quak methods for the code to compile; for the equivalent code in dynamically typed languages, the object only needs to have the quak method if isAlive() returns true. I interpret this as a difference between structure (structural typing) and behavior (duck typing).

(However, I reached this interpretation by taking Wikipedia's "duck-typing must be dynamic" at face value and trying to make it make sense. The alternate interpretation that implicit structural typing is duck typing is also coherent.)

尬尬 2024-08-22 22:50:59

我将“鸭子类型”更多地视为一种编程风格,而“结构类型”是一种类型系统功能。

结构类型是指类型系统表达包括具有某些结构属性的所有值的类型的能力。

鸭子类型是指编写代码,只使用所传递的值的特征,这些值是手头的工作实际需要的,而不施加任何其他约束。

因此,我可以通过将我的“鸭子类型”正式声明为结构类型,使用结构类型以鸭子类型风格进行编码。但我也可以使用结构类型,而无需“执行鸭子类型”。例如,如果我通过声明和命名公共结构类型然后在任何地方使用它来编写一堆相关函数/方法/过程/谓词/类/任何东西的接口,那么很可能某些代码单元不需要所有结构类型的特征,因此我不必要地限制其中一些拒绝理论上它们可以正确工作的值。

因此,虽然我可以看到如何存在共同点,但我不认为鸭子类型包含结构类型。在我看来,鸭子类型甚至不能包含结构类型,因为它们不是同一类东西。恕我直言,将动态语言中的鸭子类型视为“隐式的、未经检查的结构类型”是缺少某些东西的。鸭子类型是您选择使用或不使用的一种编码风格,而不仅仅是编程语言的技术特性。

例如,可以在 Python 中使用 isinstance 检查来伪造 OO 风格的“类或子类”类型约束。还可以检查特定的属性和方法,以伪造结构类型约束(您甚至可以将检查放在外部函数中,从而有效地获得命名的结构类型!)。我认为这些选项都不是鸭子类型的例证(除非结构类型非常细粒度并且与检查它们的代码保持密切同步)。

I see "duck typing" more as a programming style, whereas "structural typing" is a type system feature.

Structural typing refers to the ability of the type system to express types that include all values that have certain structural properties.

Duck typing refers to writing code that just uses the features of values that it is passed that are actually needed for the job at hand, without imposing any other constraints.

So I could use structural types to code in a duck typing style, by formally declaring my "duck types" as structural types. But I could also use structural types without "doing duck typing". For example, if I write interfaces to a bunch of related functions/methods/procedures/predicates/classes/whatever by declaring and naming a common structural type and then using that everywhere, it's very likely that some of the code units don't need all of the features of the structural type, and so I have unnecessarily constrained some of them to reject values on which they could theoretically work correctly.

So while I can see how there is common ground, I don't think duck typing subsumes structural typing. The way I think about them, duck typing isn't even a thing that might have been able to subsume structural typing, because they're not the same kind of thing. Thinking of duck typing in dynamic languages as just "implicit, unchecked structural types" is missing something, IMHO. Duck typing is a coding style you choose to use or not, not just a technical feature of a programming language.

For example, it's possible to use isinstance checks in Python to fake OO-style "class-or-subclass" type constraints. It's also possible to check for particular attributes and methods, to fake structural type constraints (you could even put the checks in an external function, thus effectively getting a named structural type!). I would claim that neither of these options is exemplifying duck typing (unless the structural types are quite fine grained and kept in close sync with the code checking for them).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文