内容简介:Suppose you see a bird walking around in a farm yard. This bird has no label that says 'duck'. But the bird certainly looks like a duck. Also, he goes to the pond and you notice that he swims like a duck. Then he opens his beak and quacks like a duck. Well
Suppose you see a bird walking around in a farm yard. This bird has no label that says 'duck'. But the bird certainly looks like a duck. Also, he goes to the pond and you notice that he swims like a duck. Then he opens his beak and quacks like a duck. Well, by this time you have probably reached the conclusion that the bird is a duck, whether he's wearing a label or not.
The previous quote was not the first invocation of the duck test but it is the most famous. The usage of this test may date back to the early 20th century as a way of arguing that “given the properties I can observe about some object, I’m going to classify it as what it appears to be.” It is sometimes deployed as a counterargument to claims that something is not what it seems.
The question before the house today is this: Is go duck-typed? Other languages claim to be so (see below), and the go team has mentioned in public presentations an affinity for this particular type strategy.
Duck Typing
In programming languages, duck typing can be roughly approximated as the application of the duck test to objects. To increase the precision slightly, a type is defined to be a collection of things that the type can do. Let’s try a go-ish example:
Thus, we will define some type to be an Animal
if it can return the number of legs it has. The previous is an example of an interface in go, so it implies that there are one or more implementations. An interface in go is a “test” in the sense of the duck test above; this type declaration is an animal test .
Given the animal test, let’s define a whole zoo!
Given the current Animal
interface definition, these are all duck-typed as Animal
:
Spider Dog Stool
Surely, one cannot have intended a three-legged stool to be an animal?!? Well, if one applies the—admittedly weak—animal test that we constructed with the interface Animal
above, the stool certainly passes. The critical idea of duck typing is “can I use the object in question in the way I want” and if so, the object passes the test. Clearly we can improve our definition of the animal test in this way:
With this better version of Animal
we can (correctly?) disallow a stool to be considered an animal because it has no Genus()
method. This example may seem contrived but by perusing the go standard library one will notice that a great many of the go standard interfaces have one or two methods. In fact,with a small program, one can compute the histogram of the number of methods that occur in interface declarations in the go standard library.
The histogram above indicates that number of interfaces with one or two methods is greater than three times all the others combined!
Duck Typing and Comparative Programming Languages
The notion of a “type” in a programming language goes back to the origin of programming languages. The arguing about what is a “type” in programming languages goes back to five minutes after the origin of programming languages. Many Ph.D. theses have been written about these arguments, entire conferences are dedicated to the subject, and books are written in an attempt to formally define a type (for example, A Theory of Objects or the Z notation ).
For the purpose of simplicity we will define an interface to be a type that specifies a contract about how an instance of the type will perform his duties. One could say that the first widely known programming language with the “object must meet the contract” paradigm was Eiffel in 1985, although this is arguable. Given our (simplistic) definition of an interface/contract how do programming languages differ? We’ll divide languages into two categories: those that require the specification of the interface and those that do not.
The most common reason for requiring that an interface be defined is performance, although there are others. The general reason that specifying interfaces provide additional performance is that a traditional compiler or a Just-In-Time (JIT) compiler can make assumptions about the underlying memory layout so long as the specification of the interface is enforced by the language. To use our improved example above with Animal
, a hypothetical compiler could assume that the method NumberOfLegs
is 0 bytes from the memory address of the instance implementing Animal
and the method Genus
is located 8 bytes from the memory address of the instance. So long as said compiler also enforces this requirement when compiling the implementation of Spider
and Dog
, the code that accepts an Animal
can 1) not need to know the true type of the instance passed as a parameter and 2) jump (branch) directly to the memory address of the implementation of NumberOfLegs
or Genus
for fast performance. Today, many compiled, object-oriented languages from Java (1991) to C# (2000) and from Rust (2010) to Swift (2014) operate with these explicit interfaces (this list is far from exhaustive!).
The other alternative is, well, to just wait. This is the case that is usually considered to be duck typing. In this formulation, you simply pass any type as a parameter to any function or method and wait to see if the parameter is used in a way that is acceptable. So, if type Spider
is passed to method Anatomy(a)
as the parameter a
, there is no check to see if Spider
will work in all code paths inside Anatomy
. We simply try to run the program and see if the method calls on a
( neé Spider
) work out. If they don’t, we generate an error and abort Anatomy
. You can easily imagine a dumb definition of Anatomy()
which only calls NumberOfLegs()
and since that is allowed on Spider
, the Spider
as a parameter is ok. Notably, the use of Stool
as parameter a would be ok too! In this model, the “contract”–if one can be said to exist–is implicit and varies with the exact code path that is taken through the function Anatomy
. Languages like Python (1990) and Ruby (1995) operate in this fashion; the Python community popularized the phrase “duck typing” for this behavior.
Duck Typing and Go
Go is an unusual hybrid of these two ideas. Let’s think about an example: Joe has defined and has exported this package somedwarf
:
Joe compiles this code and makes it available to his team. A week later, Mary writes this code:
If Mary runs her code from main()
she’ll see “dwarf is sad” and then on the next line “dwarf is happy.”
Given our poor man’s definition of duck typing earlier, when the language waits to see how the type is used, which case are we in here?
Does go have duck typing or not?
One can make the case that in the small we are in the first case explained above: the interface has to be explicitly defined. Within the code written by Mary, it seems fairly clear that the interface IsHappy
is defined so that it can be used to type check the uses of the parameter h
in PrintHappy
. As we explained previously, IsHappy
is being used to accelerate the call to h.Happy()
inside PrintHappy
.
In the largethough, one can easily argue that we are in the duck typing case above. Joe’s code didn’t know or care about Mary’s code, and since g
in Mary’s code worked because it had the proper method for Happy()
that is used in (Mary’s) PrintHappy()
that effectively we just waited to see if Grumpy could legitimately be used successfully in PrintHappy
.
What do we conclude from this? Sometimes, you have to embrace the ambiguity!
Happy go-ing!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
高性能JavaScript
Nicholas C.Zakas / 丁琛、赵泽欣 / 电子工业出版社 / 2010-11 / 49.00元
如果你使用JavaScript构建交互丰富的Web应用,那么JavaScript代码可能是造成你的Web应用速度变慢的主要原因。《高性能JavaScript》揭示的技术和策略能帮助你在开发过程中消除性能瓶颈。你将会了解如何提升各方面的性能,包括代码的加载、运行、DOM交互、页面生存周期等。雅虎的前端工程师Nicholas C. Zakas和其他五位JavaScript专家介绍了页面代码加载的最佳方......一起来看看 《高性能JavaScript》 这本书的介绍吧!