似乎永远不敢剪切和粘贴代码的人在指定一遍又一遍的东西类型方面没有问题。为什么不强调类型信息应该只被声明一次,以便在整个源代码中产生尽可能小的连锁反应,如果某种类型的东西被修改?例如,使用从C#和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.
}
如果更改MyClass的名称,或更改MyGenericArg的类型,或者决定更改foo的类型,似乎第二个不那么脆弱。
答案 0 :(得分:2)
我认为你不会对你的论点发现很多不同意见,即后一个例子对于程序员来说“更好”。有很多语言设计功能,因为它们对编译器实现者来说更好!
请参阅Scala,了解您的想法。
其他语言(例如ML系列)进一步采用类型推断,并创建整个编程风格,其中类型非常重要,远比C语言更为重要。 (请参阅The Little MLer以获得温和的介绍。)
答案 1 :(得分:1)
重复可能会导致更易读的代码,有时在一般情况下可能需要。我一直认为DRY的重点更多是重复逻辑而不是重复文字。从技术上讲,您也可以从底部代码中消除'var'和'void'。更不用说你用缩进表示范围了,为什么要用括号重复自己?
重复也可以带来实际好处:例如,通过保持'void'可以更容易地通过程序进行解析。
(但是,我仍然非常同意你更喜欢“var name = new Type()”而不是“Type name = new Type()”。)
答案 2 :(得分:1)
这根本不算坏。事实上,C#维护者已经开始采用var
关键字来减少疲惫的样板了,其中
MyContainer<MyType> cont = new MyContainer<MyType>();
完全等同于
var cont = new MyContainer<MyType>();
虽然您会看到很多人会反对反对 var
使用,但这种情况表明很多人不熟悉带类型推断的强类型语言;类型推断被误认为是动态/软打字。
答案 3 :(得分:0)
阿尔伯特爱因斯坦说:“一切都应尽可能简单,但不能简单一点。”
对于动态类型语言,您的投诉毫无意义,因此您必须打算使用静态类型语言。在这种情况下,您的替换示例隐式使用泛型(也称为模板类),这意味着在使用fun
或gun
的任何时间,基于参数类型的新定义。无论程序员的意图如何,这都可能导致数十种额外的方法。特别是,对于运行时错误,您将丢弃编译器检查的类型安全性的好处。
如果您的目标是简单地通过参数而不检查其类型,那么正确的类型将是Object
而不是T
。
类型声明旨在通过在编译时捕获错误而不是在运行时失败来使程序员的生活更简单。如果您的类型定义过于复杂,那么您可能无法理解您的数据。在您的示例中,我建议将fun
和gun
添加到MyClass
,而不是单独定义它们。如果fun
和gun
不适用于所有可能的模板类型,那么它们应该在显式子类中定义,而不是作为带有模板化类参数的单独函数。
泛型作为一种将行为包裹在更具体的对象周围的方式而存在。列表,队列,堆栈,这些是泛型的很好的理由,但是在一天结束时,你应该用裸Generic做的唯一事情是创建它的实例,并在其上调用方法。如果您真的觉得需要使用Generic进行更多操作,那么您可能需要将Generic类作为实例对象嵌入到包装类中,该类定义了您需要的行为。这样做的原因与将基元嵌入类中的原因相同:因为数字和字符串本身并不传达有关其内容的语义信息。
示例:
List传达了哪些语义信息?只是你正在使用多个三元组的整数。另一方面,List,其中一个颜色有3个整数(红色,蓝色,绿色)和有界值(0-255)传达了你正在使用多个颜色的意图,但没有提供关于List是否是有序,允许重复或有关颜色的任何其他信息。最后,Palette可以为您添加这些语义:Palette有一个名称,包含多个Colors,但没有重复,并且顺序并不重要。
这与原始问题相比有点远,但对我来说意味着DRY(不要重复自己)意味着指定一次信息,但该规范应该尽可能精确。
答案 4 :(得分:0)
这是一件坏事。 Google's Go language Techtalk中提到了这个话题。