English 中文(简体)
Why isn t DRY considered a good thing for type declarations?
原标题:

It seems like people who would never dare cut and paste code have no problem specifying the type of something over and over and over. Why isn t it emphasized as a good practice that type information should be declared once and only once so as to cause as little ripple effect as possible throughout the source code if the type of something is modified? For example, using pseudocode that borrows from C# and D:

MyClass<MyGenericArg> foo = new MyClass<MyGenericArg>(ctorArg);

void fun(MyClass<MyGenericArg> arg) {
    gun(arg);
}

void gun(MyClass<MyGenericArg> arg) {
    // do stuff.
}

Vs.

var foo = new MyClass<MyGenericArg>(ctorArg);

void fun(T)(T arg) {
    gun(arg);
}

void gun(T)(T arg) {
    // do stuff.
}

It seems like the second one is a lot less brittle if you change the name of MyClass, or change the type of MyGenericArg, or otherwise decide to change the type of foo.

最佳回答

It isn t considered a bad thing at all. In fact, C# maintainers are already moving a bit towards reducing the tiring boilerplate with the var keyword, where

MyContainer<MyType> cont = new MyContainer<MyType>();

is exactly equivalent to

var cont = new MyContainer<MyType>();

Although you will see many people who will argue against var usage, which kind of shows that many people is not familiar with strong typed languages with type inference; type inference is mistaken for dynamic/soft typing.

问题回答

I don t think you re going to find a lot of disagreement with your argument that the latter example is "better" for the programmer. A lot of language design features are there because they re better for the compiler implementer!

See Scala for one reification of your idea.

Other languages (such as the ML family) take type inference much further, and create a whole style of programming where the type is enormously important, much more so than in the C-like languages. (See The Little MLer for a gentle introduction.)

Repetition may lead to more readable code, and sometimes may be required in the general case. I ve always seen the focus of DRY being more about duplicating logic than repeating literal text. Technically, you can eliminate var and void from your bottom code as well. Not to mention you indicate scope with indentation, why repeat yourself with braces?

Repetition can also have practical benefits: parsing by a program is easier by keeping the void , for example.

(However, I still strongly agree with you on prefering "var name = new Type()" over "Type name = new Type()".)

It s a bad thing. This very topic was mentioned in Google s Go language Techtalk.

Albert Einstein said, "Everything should be made as simple as possible, but not one bit simpler."

Your complaint makes no sense in the case of a dynamically typed language, so you must intend this to refer to statically typed languages. In that case, your replacement example implicitly uses Generics (aka Template Classes), which means that any time that fun or gun is used, a new definition based upon the type of the argument. That could result in dozens of extra methods, regardless of the intent of the programmer. In particular, you re throwing away the benefit of compiler-checked type-safety for a runtime error.

If your goal was to simply pass through the argument without checking its type, then the correct type would be Object not T.

Type declarations are intended to make the programmer s life simpler, by catching errors at compile-time, instead of failing at runtime. If you have an overly complex type definition, then you probably don t understand your data. In your example, I would have suggested adding fun and gun to MyClass, instead of defining them separately. If fun and gun don t apply to all possible template types, then they should be defined in an explicit subclass, not as separate functions that take a templated class argument.

Generics exist as a way to wrap behavior around more specific objects. List, Queue, Stack, these are fine reasons for Generics, but at the end of the day, the only thing you should be doing with a bare Generic is creating an instance of it, and calling methods on it. If you really feel the need to do more than that with a Generic, then you probably need to embed your Generic class as an instance object in a wrapper class, one that defines the behaviors you need. You do this for the same reason that you embed primitives into a class: because by themselves, numbers and strings do not convey semantic information about their contents.

Example:

What semantic information does List convey? Just that you re working with multiple triples of integers. On the other hand, List, where a color has 3 integers (red, blue, green) with bounded values (0-255) conveys the intent that you re working with multiple Colors, but provides no hint as to whether the List is ordered, allows duplicates, or any other information about the Colors. Finally a Palette can add those semantics for you: a Palette has a name, contains multiple Colors, but no duplicates, and order isn t important.

This has gotten a bit far afield from the original question, but what it means to me is that DRY (Don t Repeat Yourself) means specifying information once, but that specification should be as precise as is necessary.





相关问题
Allow user to change the default web part styles

I have a web part which uses many SharePoint controls like menu, SPGrid, tool bar etc. I want the user to be able to change the style by specifying an external CSS file. Can somebody tell me how I ...

using jqgrid style for usual Table in asp.net mvc

I d prefer using Table and td instead of JqGrid but i like JqGrid styles. has anyone used jqgrid style for usual Grid of asp.net MVC(i mean Table and td) before?

热门标签