依赖类型推断如何影响代码可维护性?

时间:2012-04-15 20:53:12

标签: java vb.net type-inference maintainability code-inspection

虽然此问题中的示例位于Visual Basic.NET和Java中,但该主题可能也适用于实现类型推断的其他语言。

到目前为止,我在VB.NET中使用LINQ时只使用了类型推断。但是,我知道类型推断可以用在语言的其他部分,如下所示:

Dim i = 1    'i is inferred to be an Integer
Dim s = "Hoi"    's is inferred to be a string

Dim Temperatures(10) as Double

For T In Temperatures      'T is inferred to be a Double
    'Do something
Next

我可以看到类型推断如何减少编写一段代码所需的输入量,并且还可以更快地更改基本变量的类型(例如上面的Temperatures(10))不需要更改访问它的所有其他变量的类型(例如T)。但是,我担心缺乏明确的类型声明可能会使代码更难以阅读,比如在代码检查期间,因为它可能不会立即明显变量的类型。例如,通过查看上面的For循环,您可能会认为T是某个浮点值,但是如果不回头看声明就无法判断它是单精度还是双精度Temperatures。根据代码的编写方式,Temperatures可以更早地声明,因此需要读者返回并找到声明然后继续阅读。不可否认,当使用一个好的IDE时,这不是一个问题,因为鼠标光标快速悬停在变量名称上会显示出类型。

另外,我想在某些情况下使用类型推断可能会在尝试更改代码时引入一些错误。假设类AB做完全不同的事情,请考虑以下(公认的做作)示例。

Class A
    Public Sub DoSomething()
    End Sub
End Class

Class B
    Public Sub DoSomething()
    End Sub
End Class

Dim ObjectList(10) As A

For item In ObjectList
    item.DoSomething()
End For

可以将ObjectList的类型从A更改为B,代码可以编译,但功能会有所不同,这可能表现为其他部分的错误代码。

通过一些类型推断的例子,我想大多数人会同意它的使用对可读性或可维护性没有负面影响。例如,在Java 7中,可以使用以下内容:

ArrayList<String> a = new ArrayList<>();    // The constructor type is inferred from the declaration.

而不是

ArrayList<String> a = new ArrayList<String>();

我很想知道人们对此事的想法是什么,以及是否有关于应该如何广泛使用类型推断的任何建议。

阿姆鲁

3 个答案:

答案 0 :(得分:3)

就个人而言,我倾向于仅在类型清晰且使代码更易于阅读的情况下使用隐式类型推理

var dict = new Dictionary<string, List<TreeNode<int>>>();

更容易阅读
Dictionary<string, List<TreeNode<int>>> dict =
    new Dictionary<string, List<TreeNode<int>>>();

但类型很清楚。


这里不清楚你得到了什么,我会明确指定类型:

var something = GetSomeThing();

这里使用var是没有意义的,因为它不会简化任何事情

int i = 0;
double x = 0.0;
string s = "hello";

答案 1 :(得分:1)

我认为部分原因在于编码风格。我亲自选择了更详细的代码。 (虽然当我转到Java 7项目时,我可能会利用新的语法,因为所有内容仍在一行中。)

我也认为明确可以避免某些微妙的错误。举个例子:

For T In Temperatures      'T is inferred to be a Double
    'Do something
Next

如果Do something是依赖TDouble的数值方法,则将Temperatures更改为单精度可能会导致算法无法收敛,或者收敛到一个不正确的值。

我想我可以用另一种方式论证 - 明确关于变量类型可以在某些情况下产生许多可以避免的微不足道的维护工作。同样,我认为这都是风格问题。

答案 2 :(得分:-2)

泛型的使用是为了确保在编译时进行类型安全检查,而不是在运行时处理它。如果您正确使用类型安全,它将使您免于运行时异常以及在数据检索时编写构建代码。

JAva在jdk 1.7之前不使用此sentax

ArrayList<String> a = new ArrayList<>(); 

它的

ArrayList<String> a = new ArrayList(); 

但是在java中使用

ArrayList<String> a = new ArrayList(); and
ArrayList<String> a = new ArrayList<String>();

两者都认为是相同的,因为引用变量保存了类型为safe的complile time信息,这是一个字符串,你不能在其中添加任何其他内容而不是字符串,即

a.add(new Integer(5));

它仍然是类型安全的,你会得到错误,你只能插入字符串。

所以你不能做你期望做的事。