鸭子打字与静态打字有什么好处?

时间:2023-01-23 22:38:38

I'm researching and experimenting more with Groovy and I'm trying to wrap my mind around the pros and cons of implementing things in Groovy that I can't/don't do in Java. Dynamic programming is still just a concept to me since I've been deeply steeped static and strongly typed languages.

我正在使用Groovy进行更多的研究和实验,并且我试图围绕在Groovy中实现事物的优点和缺点,我不能/不能用Java做。动态编程对我来说仍然只是一个概念,因为我已经深深地沉浸在静态和强类型语言中。

Groovy gives me the ability to duck-type, but I can't really see the value. How is duck-typing more productive than static typing? What kind of things can I do in my code practice to help me grasp the benefits of it?

Groovy给了我鸭子型的能力,但我无法真正看到它的价值。鸭子打字比静态打字更有效率?在我的代码练习中我可以做些什么来帮助我掌握它的好处?

I ask this question with Groovy in mind but I understand it isn't necessarily a Groovy question so I welcome answers from every code camp.

我用Groovy问这个问题,但我知道它不一定是一个Groovy问题所以我欢迎来自每个代码阵营的答案。

12 个解决方案

#1


5  

Next, which is better: EMACS or vi? This is one of the running religious wars.

接下来,哪个更好:EMACS还是vi?这是正在进行的宗教战争之一。

Think of it this way: any program that is correct, will be correct if the language is statically typed. What static typing does is let the compiler have enough information to detect type mismatches at compile time instead of run time. This can be an annoyance if your doing incremental sorts of programming, although (I maintain) if you're thinking clearly about your program it doesn't much matter; on the other hand, if you're building a really big program, like an operating system or a telephone switch, with dozens or hundreds or thousands of people working on it, or with really high reliability requirements, then having he compiler be able to detect a large class of problems for you without needing a test case to exercise just the right code path.

可以这样想:如果语言是静态类型的,任何正确的程序都是正确的。静态类型的作用是让编译器有足够的信息在编译时检测类型不匹配而不是运行时。如果您正在进行增量编程,这可能会让您感到烦恼,尽管(我坚持认为)如果您正在清楚地考虑您的计划并不重要;另一方面,如果你正在构建一个非常大的程序,比如操作系统或电话交换机,有数十或数百或数千人在上面工作,或者具有非常高的可靠性要求,那么让编译器能够为您检测一大类问题,而无需测试用例来运行正确的代码路径。

It's not as if dynamic typing is a new and different thing: C, for example, is effectively dynamically typed, since I can always cast a foo* to a bar*. It just means it's then my responsibility as a C programmer never to use code that is appropriate on a bar* when the address is really pointing to a foo*. But as a result of the issues with large programs, C grew tools like lint(1), strengthened its type system with typedef and eventually developed a strongly typed variant in C++. (And, of course, C++ in turn developed ways around the strong typing, with all the varieties of casts and generics/templates and with RTTI.

这并不是说动态类型是一个新的和不同的东西:例如,C是有效动态类型的,因为我总是可以将foo *转换为条形*。这只是意味着我作为C程序员的责任,当地址真正指向foo *时,永远不要使用适合于条形码*的代码。但是由于大型程序的问题,C开发了像lint(1)这样的工具,用typedef强化了它的类型系统,最终在C ++中开发了一个强类型变体。 (当然,C ++反过来开发了强类型的方法,包括所有类型的演员表和泛型/模板以及RTTI。

One other thing, though --- don't confuse "agile programming" with "dynamic languages". Agile programming is about the way people work together in a project: can the project adapt to changing requirements to meet the customers' needs while maintaining a humane environment for the programmers? It can be done with dynamically typed languages, and often is, because they can be more productive (eg, Ruby, Smalltalk), but it can be done, has been done successfully, in C and even assembler. In fact, Rally Development even uses agile methods (SCRUM in particular) to do marketing and documentation.

但另一件事是 - 不要将“敏捷编程”与“动态语言”混为一谈。敏捷编程是关于人们在项目中协同工作的方式:项目能否适应不断变化的需求以满足客户的需求,同时为程序员保持人性化的环境?它可以使用动态类型语言来完成,并且通常是因为它们可以更高效(例如,Ruby,Smalltalk),但它可以在C甚至汇编程序中成功完成。实际上,Rally Development甚至使用敏捷方法(特别是SCRUM)来进行营销和文档编制。

#2


16  

A lot of the comments for duck typing don't really substantiate the claims. Not "having to worry" about a type is not sustainable for maintenance or making an application extendable. I've really had a good opportunity to see Grails in action over my last contract and its quite funny to watch really. Everyone is happy about the gains in being able to "create-app" and get going - sadly it all catches up to you on the back end.

很多关于鸭子打字的评论并没有真正证实这些说法。对于某种类型而言,“不必担心”是不可持续的维护或使应用程序可扩展。我真的有机会看到Grails在我的最后一份合同中采取行动,真的非常有趣。每个人都对能够“创造应用程序”并开始行动的成果感到高兴 - 遗憾的是,它们都会在后端赶上你。

Groovy seems the same way to me. Sure you can write very succinct code and definitely there is some nice sugar in how we get to work with properties, collections, etc... But the cost of not knowing what the heck is being passed back and forth just gets worse and worse. At some point your scratching your head wondering why the project has become 80% testing and 20% work. The lesson here is that "smaller" does not make for "more readable" code. Sorry folks, its simple logic - the more you have to know intuitively then the more complex the process of understanding that code becomes. It's why GUI's have backed off becoming overly iconic over the years - sure looks pretty but WTH is going on is not always obvious.

Groovy对我来说似乎是一样的。当然你可以编写非常简洁的代码,并且肯定有一些很好的糖,我们如何使用属性,集合等...但不知道什么是来回传递的成本变得越来越糟。在某些时候,你不知道为什么该项目已经成为80%的测试和20%的工作。这里的教训是“较小”不会产生“更易读”的代码。对不起,人们简单的逻辑 - 你必须越直观地知道,然后理解代码的过程就越复杂。这就是为什么GUI多年来已经成为过度标志性的原因 - 肯定看起来很漂亮,但WTH正在发生并不总是显而易见的。

People on that project seemed to have troubles "nailing down" the lessons learned, but when you have methods returning either a single element of type T, an array of T, an ErrorResult or a null ... it becomes rather apparent.

那个项目的人似乎有麻烦“扼杀”所学到的经验教训,但是当你有方法返回T类型的单个元素,T,ErrorResult或null的数组时,它变得相当明显。

One thing working with Groovy has done for me however - awesome billable hours woot!

然而,使用Groovy的一件事已经为我做了 - 令人敬畏的可计费小时数!

#3


10  

There is nothing wrong with static typing if you are using Haskell, which has an incredible static type system. However, if you are using languages like Java and C++ that have terribly crippling type systems, duck typing is definitely an improvement.

如果你使用的Haskell有一个令人难以置信的静态类型系统,静态类型没有任何问题。但是,如果您使用的Java和C ++等语言具有非常严重的类型系统,那么鸭子打字肯定是一种改进。

Imagine trying to use something so simple as "map" in Java (and no, I don't mean the data structure). Even generics are rather poorly supported.

想象一下,尝试在Java中使用像“map”这样简单的东西(不,我不是指数据结构)。即使是泛型也很难得到支持。

#4


9  

Duck typing cripples most modern IDE's static checking, which can point out errors as you type. Some consider this an advantage. I want the IDE/Compiler to tell me I've made a stupid programmer trick as soon as possible.

鸭子打字瘫痪了大多数现代IDE的静态检查,它可以在您键入时指出错误。有些人认为这是一个优势。我希望IDE /编译器告诉我,我已经尽快制作了一个愚蠢的程序员技巧。

My most recent favorite argument against duck typing comes from a Grails project DTO:

我最近最喜欢反对鸭子打字的论点来自Grails项目DTO:

class SimpleResults {
    def results
    def total
    def categories
}

where results turns out to be something like Map<String, List<ComplexType>>, which can be discovered only by following a trail of method calls in different classes until you find where it was created. For the terminally curious, total is the sum of the sizes of the List<ComplexType>s and categories is the size of the Map

结果结果类似于Map >,只能通过跟踪不同类中的方法调用的跟踪,直到找到它的创建位置。对于最终的好奇,total是List 的大小的总和,而类别是Map的大小 ,list>

It may have been clear to the original developer, but the poor maintenance guy (ME) lost a lot of hair tracking this one down.

原来的开发人员可能已经清楚了,但是那个糟糕的维护人员(ME)失去了很多头发跟踪这个。

#5


6  

It's a little bit difficult to see the value of duck typing until you've used it for a little while. Once you get used to it, you'll realize how much of a load off your mind it is to not have to deal with interfaces or having to worry about exactly what type something is.

在您使用它一段时间之前,看到鸭子打字的价值有点困难。一旦你习惯了它,你就会意识到你不必处理接口或者不必担心什么类型的东西是多少负担。

#6


3  

IMHO, the advantage of duck typing becomes magnified when you adhere to some conventions, such as naming you variables and methods in a consistent way. Taking the example from Ken G, I think it would read best:

恕我直言,当你遵守一些约定时,鸭子打字的优势就会被放大,例如以一致的方式命名变量和方法。以Ken G为例,我认为最好:

class SimpleResults {
    def mapOfListResults
    def total
    def categories
}

Let's say you define a contract on some operation named 'calculateRating(A,B)' where A and B adhere to another contract. In pseudocode, it would read:

假设你在一些名为'calculateRating(A,B)'的操作上定义了一个契约,其中A和B遵守另一个契约。在伪代码中,它将显示为:

Long calculateRating(A someObj, B, otherObj) {

   //some fake algorithm here:
   if(someObj.doStuff('foo') > otherObj.doStuff('bar')) return someObj.calcRating());
   else return otherObj.calcRating();

}

If you want to implement this in Java, both A and B must implement some kind of interface that reads something like this:

如果要在Java中实现它,A和B都必须实现某种类似于以下内容的接口:

public interface MyService {
    public int doStuff(String input);
}

Besides, if you want to generalize you contract for calculating ratings (let's say you have another algorithm for rating calculations), you also have to create an interface:

此外,如果你想概括计算评级的合约(假设你有另一种评级计算算法),你还需要创建一个界面:

public long calculateRating(MyService A, MyServiceB);

With duck typing, you can ditch your interfaces and just rely that on runtime, both A and B will respond correctly to your doStuff() calls. There is no need for a specific contract definition. This can work for you but it can also work against you.

使用duck typing,您可以放弃接口,只需依赖运行时,A和B都会正确响应doStuff()调用。不需要特定的合同定义。这可以为你工作,但它也可以对你不利。

The downside is that you have to be extra careful in order to guarantee that your code does not break when some other persons changes it (ie, the other person must be aware of the implicit contract on the method name and arguments).

缺点是你必须格外小心,以保证你的代码在其他人改变时不会中断(即,另一个人必须知道方法名和参数的隐式契约)。

Note that this aggravates specially in Java, where the syntax is not as terse as it could be (compared to Scala for example). A counter-example of this is the Lift framework, where they say that the SLOC count of the framework is similar to Rails, but the test code has less lines because they don't need to implement type checks within the tests.

请注意,这在Java中特别恶化,其语法并不像它可能的那样简洁(例如与Scala相比)。一个反例就是Lift框架,他们说框架的SLOC计数类似于Rails,但测试代码的行数较少,因为它们不需要在测试中实现类型检查。

#7


3  

Here's one scenario where duck typing saves work.

这是鸭子打字节省工作的一个场景。

Here's a very trivial class

这是一个非常微不足道的课程

class BookFinder {
    def searchEngine

    def findBookByTitle(String title) {
         return searchEngine.find( [ "Title" : title ] ) 
    }
}

Now for the unit test:

现在进行单元测试:

void bookFinderTest() {
    // with Expando we can 'fake' any object at runtime.
    // alternatively you could write a MockSearchEngine class.
    def mockSearchEngine = new Expando()
    mockSearchEngine.find = {
        return new Book("Heart of Darkness","Joseph Conrad")
    }

    def bf = new BookFinder()
    bf.searchEngine = mockSearchEngine
    def book = bf.findBookByTitle("Heart of Darkness")
    assert(book.author == "Joseph Conrad"
}

We were able to substitute an Expando for the SearchEngine, because of the absence of static type checking. With static type checking we would have had to ensure that SearchEngine was an interface, or at least an abstract class, and create a full mock implementation of it. That's labour intensive, or you can use a sophisticated single-purpose mocking framework. But duck typing is general-purpose, and has helped us.

由于缺少静态类型检查,我们能够将Expando替换为SearchEngine。使用静态类型检查,我们必须确保SearchEngine是一个接口,或者至少是一个抽象类,并创建一个完整的模拟实现。这是劳动密集型的,或者您可以使用复杂的单一用途模拟框架。但鸭子打字是通用的,并帮助了我们。

Because of duck typing, our unit test can provide any old object in place of the dependency, just as long as it implements the methods that get called.

由于duck typing,我们的单元测试可以提供任何旧对象来代替依赖,只要它实现了被调用的方法。

To emphasise - you can do this in a statically typed language, with careful use of interfaces and class hierarchies. But with duck typing you can do it with less thinking and fewer keystrokes.

要强调 - 您可以使用静态类型语言执行此操作,并仔细使用接口和类层次结构。但是通过鸭子打字你可以用更少的思维和更少的击键来做到这一点。

That's an advantage of duck typing. It doesn't mean that dynamic typing is the right paradigm to use in all situations. In my Groovy projects, I like to switch back to Java in circumstances where I feel that compiler warnings about types are going to help me.

这是鸭子打字的一个优点。这并不意味着动态类型是在所有情况下使用的正确范例。在我的Groovy项目中,我喜欢在我认为有关类型的编译器警告将帮助我的情况下切换回Java。

#8


2  

With, TDD + 100% Code Coverage + IDE tools to constantly run my tests, I do not feel a need of static typing any more. With no strong types, my unit testing has become so easy (Simply use Maps for creating mock objects). Specially , when you are using Generics, you can see the difference:

有了TDD + 100%代码覆盖率+ IDE工具来不断运行我的测试,我不再需要静态类型了。由于没有强大的类型,我的单元测试变得如此简单(只需使用Maps创建模拟对象)。特别是,当您使用泛型时,您可以看到差异:

//Static typing 
Map<String,List<Class1<Class2>>> someMap = [:] as HashMap<String,List<Class1<Class2>>>

vs

//Dynamic typing
def someMap = [:]   

#9


1  

It's not that duck typing is more productive than static typing as much as it is simply different. With static typing you always have to worry that your data is the correct type and in Java it shows up through casting to the right type. With duck typing the type doesn't matter as long as it has the right method, so it really just eliminates a lot of the hassle of casting and conversions between types.

并不是说鸭子打字比静态打字更有效率,因为它只是简单的不同。使用静态类型,您总是要担心您的数据是正确的类型,并且在Java中它通过强制转换显示为正确的类型。使用duck键入类型并不重要,只要它具有正确的方法,因此它实际上消除了很多类型之间的转换和转换的麻烦。

#10


1  

@Chris Bunch

It's not that static typing is more productive than duck typing as much as it is simply different. With duck typing you always have to worry that your data has the right method and in Javascript or Ruby it shows up through a lot of method testing. With static typing it doesn't matter as long as it is the correct interface, so it really just eliminates a lot of the hassle of testing and conversions between types.

并不是说静态打字比鸭子打字更有效率,因为它只是简单的不同。使用duck typing你总是要担心你的数据有正确的方法,并且在Javascript或Ruby中它通过大量的方法测试显示出来。使用静态类型,只要它是正确的接口就没关系,所以它确实消除了很多类型之间的测试和转换的麻烦。

Sorry but I had to do it...

对不起,但我不得不这样做......

#11


1  

My opinion:

Dynamically typed or duck typed languages are toys. You can't get Intellisense and you lose compile time (or edit time - when using a REAL IDE like VS, not that garbage other people think are IDEs) code validation.

动态打字或鸭子打字的语言是玩具。您无法获得智能感知,并且您将失去编译时间(或编辑时间 - 使用像VS这样的真实IDE,而不是其他人认为是垃圾的IDE)代码验证。

Stay clear of every language that is not statically typed, everything else is just plain masochism.

要清除所有非静态输入的语言,其他一切都只是纯粹的受虐狂。

#12


0  

To me, they aren't horribly different if you see dynamically typed languages as simply a form of static typing where everything inherits from a sufficiently abstract base class.

对我而言,如果您将动态类型语言视为静态类型的一种形式,其中所有内容都从一个足够抽象的基类继承,那么它们并没有太大的不同。

Problems arise when, as many have pointed out, you start getting strange with this. Someone pointed out a function that returns a single object, a collection, or a null. Have the function return a specific type, not multiple. Use multiple functions for single vs collection.

正如许多人所指出的那样,当你开始对此感到陌生时,会出现问题。有人指出了一个返回单个对象,集合或null的函数。让函数返回特定类型,而不是多个。对单个vs集合使用多个函数。

What it boils down to is that anyone can write bad code. Static typing is a great safety device, but sometimes the helmet gets in the way when you want to feel the wind in your hair.

它归结为是任何人都可以编写错误的代码。静态打字是一种很好的安全装置,但有时当你想要感受到头发的风时,头盔就会受阻。

#1


5  

Next, which is better: EMACS or vi? This is one of the running religious wars.

接下来,哪个更好:EMACS还是vi?这是正在进行的宗教战争之一。

Think of it this way: any program that is correct, will be correct if the language is statically typed. What static typing does is let the compiler have enough information to detect type mismatches at compile time instead of run time. This can be an annoyance if your doing incremental sorts of programming, although (I maintain) if you're thinking clearly about your program it doesn't much matter; on the other hand, if you're building a really big program, like an operating system or a telephone switch, with dozens or hundreds or thousands of people working on it, or with really high reliability requirements, then having he compiler be able to detect a large class of problems for you without needing a test case to exercise just the right code path.

可以这样想:如果语言是静态类型的,任何正确的程序都是正确的。静态类型的作用是让编译器有足够的信息在编译时检测类型不匹配而不是运行时。如果您正在进行增量编程,这可能会让您感到烦恼,尽管(我坚持认为)如果您正在清楚地考虑您的计划并不重要;另一方面,如果你正在构建一个非常大的程序,比如操作系统或电话交换机,有数十或数百或数千人在上面工作,或者具有非常高的可靠性要求,那么让编译器能够为您检测一大类问题,而无需测试用例来运行正确的代码路径。

It's not as if dynamic typing is a new and different thing: C, for example, is effectively dynamically typed, since I can always cast a foo* to a bar*. It just means it's then my responsibility as a C programmer never to use code that is appropriate on a bar* when the address is really pointing to a foo*. But as a result of the issues with large programs, C grew tools like lint(1), strengthened its type system with typedef and eventually developed a strongly typed variant in C++. (And, of course, C++ in turn developed ways around the strong typing, with all the varieties of casts and generics/templates and with RTTI.

这并不是说动态类型是一个新的和不同的东西:例如,C是有效动态类型的,因为我总是可以将foo *转换为条形*。这只是意味着我作为C程序员的责任,当地址真正指向foo *时,永远不要使用适合于条形码*的代码。但是由于大型程序的问题,C开发了像lint(1)这样的工具,用typedef强化了它的类型系统,最终在C ++中开发了一个强类型变体。 (当然,C ++反过来开发了强类型的方法,包括所有类型的演员表和泛型/模板以及RTTI。

One other thing, though --- don't confuse "agile programming" with "dynamic languages". Agile programming is about the way people work together in a project: can the project adapt to changing requirements to meet the customers' needs while maintaining a humane environment for the programmers? It can be done with dynamically typed languages, and often is, because they can be more productive (eg, Ruby, Smalltalk), but it can be done, has been done successfully, in C and even assembler. In fact, Rally Development even uses agile methods (SCRUM in particular) to do marketing and documentation.

但另一件事是 - 不要将“敏捷编程”与“动态语言”混为一谈。敏捷编程是关于人们在项目中协同工作的方式:项目能否适应不断变化的需求以满足客户的需求,同时为程序员保持人性化的环境?它可以使用动态类型语言来完成,并且通常是因为它们可以更高效(例如,Ruby,Smalltalk),但它可以在C甚至汇编程序中成功完成。实际上,Rally Development甚至使用敏捷方法(特别是SCRUM)来进行营销和文档编制。

#2


16  

A lot of the comments for duck typing don't really substantiate the claims. Not "having to worry" about a type is not sustainable for maintenance or making an application extendable. I've really had a good opportunity to see Grails in action over my last contract and its quite funny to watch really. Everyone is happy about the gains in being able to "create-app" and get going - sadly it all catches up to you on the back end.

很多关于鸭子打字的评论并没有真正证实这些说法。对于某种类型而言,“不必担心”是不可持续的维护或使应用程序可扩展。我真的有机会看到Grails在我的最后一份合同中采取行动,真的非常有趣。每个人都对能够“创造应用程序”并开始行动的成果感到高兴 - 遗憾的是,它们都会在后端赶上你。

Groovy seems the same way to me. Sure you can write very succinct code and definitely there is some nice sugar in how we get to work with properties, collections, etc... But the cost of not knowing what the heck is being passed back and forth just gets worse and worse. At some point your scratching your head wondering why the project has become 80% testing and 20% work. The lesson here is that "smaller" does not make for "more readable" code. Sorry folks, its simple logic - the more you have to know intuitively then the more complex the process of understanding that code becomes. It's why GUI's have backed off becoming overly iconic over the years - sure looks pretty but WTH is going on is not always obvious.

Groovy对我来说似乎是一样的。当然你可以编写非常简洁的代码,并且肯定有一些很好的糖,我们如何使用属性,集合等...但不知道什么是来回传递的成本变得越来越糟。在某些时候,你不知道为什么该项目已经成为80%的测试和20%的工作。这里的教训是“较小”不会产生“更易读”的代码。对不起,人们简单的逻辑 - 你必须越直观地知道,然后理解代码的过程就越复杂。这就是为什么GUI多年来已经成为过度标志性的原因 - 肯定看起来很漂亮,但WTH正在发生并不总是显而易见的。

People on that project seemed to have troubles "nailing down" the lessons learned, but when you have methods returning either a single element of type T, an array of T, an ErrorResult or a null ... it becomes rather apparent.

那个项目的人似乎有麻烦“扼杀”所学到的经验教训,但是当你有方法返回T类型的单个元素,T,ErrorResult或null的数组时,它变得相当明显。

One thing working with Groovy has done for me however - awesome billable hours woot!

然而,使用Groovy的一件事已经为我做了 - 令人敬畏的可计费小时数!

#3


10  

There is nothing wrong with static typing if you are using Haskell, which has an incredible static type system. However, if you are using languages like Java and C++ that have terribly crippling type systems, duck typing is definitely an improvement.

如果你使用的Haskell有一个令人难以置信的静态类型系统,静态类型没有任何问题。但是,如果您使用的Java和C ++等语言具有非常严重的类型系统,那么鸭子打字肯定是一种改进。

Imagine trying to use something so simple as "map" in Java (and no, I don't mean the data structure). Even generics are rather poorly supported.

想象一下,尝试在Java中使用像“map”这样简单的东西(不,我不是指数据结构)。即使是泛型也很难得到支持。

#4


9  

Duck typing cripples most modern IDE's static checking, which can point out errors as you type. Some consider this an advantage. I want the IDE/Compiler to tell me I've made a stupid programmer trick as soon as possible.

鸭子打字瘫痪了大多数现代IDE的静态检查,它可以在您键入时指出错误。有些人认为这是一个优势。我希望IDE /编译器告诉我,我已经尽快制作了一个愚蠢的程序员技巧。

My most recent favorite argument against duck typing comes from a Grails project DTO:

我最近最喜欢反对鸭子打字的论点来自Grails项目DTO:

class SimpleResults {
    def results
    def total
    def categories
}

where results turns out to be something like Map<String, List<ComplexType>>, which can be discovered only by following a trail of method calls in different classes until you find where it was created. For the terminally curious, total is the sum of the sizes of the List<ComplexType>s and categories is the size of the Map

结果结果类似于Map >,只能通过跟踪不同类中的方法调用的跟踪,直到找到它的创建位置。对于最终的好奇,total是List 的大小的总和,而类别是Map的大小 ,list>

It may have been clear to the original developer, but the poor maintenance guy (ME) lost a lot of hair tracking this one down.

原来的开发人员可能已经清楚了,但是那个糟糕的维护人员(ME)失去了很多头发跟踪这个。

#5


6  

It's a little bit difficult to see the value of duck typing until you've used it for a little while. Once you get used to it, you'll realize how much of a load off your mind it is to not have to deal with interfaces or having to worry about exactly what type something is.

在您使用它一段时间之前,看到鸭子打字的价值有点困难。一旦你习惯了它,你就会意识到你不必处理接口或者不必担心什么类型的东西是多少负担。

#6


3  

IMHO, the advantage of duck typing becomes magnified when you adhere to some conventions, such as naming you variables and methods in a consistent way. Taking the example from Ken G, I think it would read best:

恕我直言,当你遵守一些约定时,鸭子打字的优势就会被放大,例如以一致的方式命名变量和方法。以Ken G为例,我认为最好:

class SimpleResults {
    def mapOfListResults
    def total
    def categories
}

Let's say you define a contract on some operation named 'calculateRating(A,B)' where A and B adhere to another contract. In pseudocode, it would read:

假设你在一些名为'calculateRating(A,B)'的操作上定义了一个契约,其中A和B遵守另一个契约。在伪代码中,它将显示为:

Long calculateRating(A someObj, B, otherObj) {

   //some fake algorithm here:
   if(someObj.doStuff('foo') > otherObj.doStuff('bar')) return someObj.calcRating());
   else return otherObj.calcRating();

}

If you want to implement this in Java, both A and B must implement some kind of interface that reads something like this:

如果要在Java中实现它,A和B都必须实现某种类似于以下内容的接口:

public interface MyService {
    public int doStuff(String input);
}

Besides, if you want to generalize you contract for calculating ratings (let's say you have another algorithm for rating calculations), you also have to create an interface:

此外,如果你想概括计算评级的合约(假设你有另一种评级计算算法),你还需要创建一个界面:

public long calculateRating(MyService A, MyServiceB);

With duck typing, you can ditch your interfaces and just rely that on runtime, both A and B will respond correctly to your doStuff() calls. There is no need for a specific contract definition. This can work for you but it can also work against you.

使用duck typing,您可以放弃接口,只需依赖运行时,A和B都会正确响应doStuff()调用。不需要特定的合同定义。这可以为你工作,但它也可以对你不利。

The downside is that you have to be extra careful in order to guarantee that your code does not break when some other persons changes it (ie, the other person must be aware of the implicit contract on the method name and arguments).

缺点是你必须格外小心,以保证你的代码在其他人改变时不会中断(即,另一个人必须知道方法名和参数的隐式契约)。

Note that this aggravates specially in Java, where the syntax is not as terse as it could be (compared to Scala for example). A counter-example of this is the Lift framework, where they say that the SLOC count of the framework is similar to Rails, but the test code has less lines because they don't need to implement type checks within the tests.

请注意,这在Java中特别恶化,其语法并不像它可能的那样简洁(例如与Scala相比)。一个反例就是Lift框架,他们说框架的SLOC计数类似于Rails,但测试代码的行数较少,因为它们不需要在测试中实现类型检查。

#7


3  

Here's one scenario where duck typing saves work.

这是鸭子打字节省工作的一个场景。

Here's a very trivial class

这是一个非常微不足道的课程

class BookFinder {
    def searchEngine

    def findBookByTitle(String title) {
         return searchEngine.find( [ "Title" : title ] ) 
    }
}

Now for the unit test:

现在进行单元测试:

void bookFinderTest() {
    // with Expando we can 'fake' any object at runtime.
    // alternatively you could write a MockSearchEngine class.
    def mockSearchEngine = new Expando()
    mockSearchEngine.find = {
        return new Book("Heart of Darkness","Joseph Conrad")
    }

    def bf = new BookFinder()
    bf.searchEngine = mockSearchEngine
    def book = bf.findBookByTitle("Heart of Darkness")
    assert(book.author == "Joseph Conrad"
}

We were able to substitute an Expando for the SearchEngine, because of the absence of static type checking. With static type checking we would have had to ensure that SearchEngine was an interface, or at least an abstract class, and create a full mock implementation of it. That's labour intensive, or you can use a sophisticated single-purpose mocking framework. But duck typing is general-purpose, and has helped us.

由于缺少静态类型检查,我们能够将Expando替换为SearchEngine。使用静态类型检查,我们必须确保SearchEngine是一个接口,或者至少是一个抽象类,并创建一个完整的模拟实现。这是劳动密集型的,或者您可以使用复杂的单一用途模拟框架。但鸭子打字是通用的,并帮助了我们。

Because of duck typing, our unit test can provide any old object in place of the dependency, just as long as it implements the methods that get called.

由于duck typing,我们的单元测试可以提供任何旧对象来代替依赖,只要它实现了被调用的方法。

To emphasise - you can do this in a statically typed language, with careful use of interfaces and class hierarchies. But with duck typing you can do it with less thinking and fewer keystrokes.

要强调 - 您可以使用静态类型语言执行此操作,并仔细使用接口和类层次结构。但是通过鸭子打字你可以用更少的思维和更少的击键来做到这一点。

That's an advantage of duck typing. It doesn't mean that dynamic typing is the right paradigm to use in all situations. In my Groovy projects, I like to switch back to Java in circumstances where I feel that compiler warnings about types are going to help me.

这是鸭子打字的一个优点。这并不意味着动态类型是在所有情况下使用的正确范例。在我的Groovy项目中,我喜欢在我认为有关类型的编译器警告将帮助我的情况下切换回Java。

#8


2  

With, TDD + 100% Code Coverage + IDE tools to constantly run my tests, I do not feel a need of static typing any more. With no strong types, my unit testing has become so easy (Simply use Maps for creating mock objects). Specially , when you are using Generics, you can see the difference:

有了TDD + 100%代码覆盖率+ IDE工具来不断运行我的测试,我不再需要静态类型了。由于没有强大的类型,我的单元测试变得如此简单(只需使用Maps创建模拟对象)。特别是,当您使用泛型时,您可以看到差异:

//Static typing 
Map<String,List<Class1<Class2>>> someMap = [:] as HashMap<String,List<Class1<Class2>>>

vs

//Dynamic typing
def someMap = [:]   

#9


1  

It's not that duck typing is more productive than static typing as much as it is simply different. With static typing you always have to worry that your data is the correct type and in Java it shows up through casting to the right type. With duck typing the type doesn't matter as long as it has the right method, so it really just eliminates a lot of the hassle of casting and conversions between types.

并不是说鸭子打字比静态打字更有效率,因为它只是简单的不同。使用静态类型,您总是要担心您的数据是正确的类型,并且在Java中它通过强制转换显示为正确的类型。使用duck键入类型并不重要,只要它具有正确的方法,因此它实际上消除了很多类型之间的转换和转换的麻烦。

#10


1  

@Chris Bunch

It's not that static typing is more productive than duck typing as much as it is simply different. With duck typing you always have to worry that your data has the right method and in Javascript or Ruby it shows up through a lot of method testing. With static typing it doesn't matter as long as it is the correct interface, so it really just eliminates a lot of the hassle of testing and conversions between types.

并不是说静态打字比鸭子打字更有效率,因为它只是简单的不同。使用duck typing你总是要担心你的数据有正确的方法,并且在Javascript或Ruby中它通过大量的方法测试显示出来。使用静态类型,只要它是正确的接口就没关系,所以它确实消除了很多类型之间的测试和转换的麻烦。

Sorry but I had to do it...

对不起,但我不得不这样做......

#11


1  

My opinion:

Dynamically typed or duck typed languages are toys. You can't get Intellisense and you lose compile time (or edit time - when using a REAL IDE like VS, not that garbage other people think are IDEs) code validation.

动态打字或鸭子打字的语言是玩具。您无法获得智能感知,并且您将失去编译时间(或编辑时间 - 使用像VS这样的真实IDE,而不是其他人认为是垃圾的IDE)代码验证。

Stay clear of every language that is not statically typed, everything else is just plain masochism.

要清除所有非静态输入的语言,其他一切都只是纯粹的受虐狂。

#12


0  

To me, they aren't horribly different if you see dynamically typed languages as simply a form of static typing where everything inherits from a sufficiently abstract base class.

对我而言,如果您将动态类型语言视为静态类型的一种形式,其中所有内容都从一个足够抽象的基类继承,那么它们并没有太大的不同。

Problems arise when, as many have pointed out, you start getting strange with this. Someone pointed out a function that returns a single object, a collection, or a null. Have the function return a specific type, not multiple. Use multiple functions for single vs collection.

正如许多人所指出的那样,当你开始对此感到陌生时,会出现问题。有人指出了一个返回单个对象,集合或null的函数。让函数返回特定类型,而不是多个。对单个vs集合使用多个函数。

What it boils down to is that anyone can write bad code. Static typing is a great safety device, but sometimes the helmet gets in the way when you want to feel the wind in your hair.

它归结为是任何人都可以编写错误的代码。静态打字是一种很好的安全装置,但有时当你想要感受到头发的风时,头盔就会受阻。