1

我的问题几乎就是标题所说的:是否有可能拥有一种不允许显式类型转换的编程语言?

为了澄清我的意思,假设我们正在使用一些类似 C# 的语言,有一个父Base类和一个子Derived类。显然,这样的代码是安全的:

Base a = new Derived();

由于向上继承层次结构是安全的,但是

Dervied b = (Base)a;

不能保证安全,因为下去是不安全的。

但是,不管安全性如何,这种向下转换在许多语言(如 Java 或 C#)中都是有效的 - 代码将编译,如果类型不正确,它将在运行时失败。所以从技术上讲,代码仍然是安全的,但是通过运行时检查而不是编译时检查(顺便说一句,我不喜欢运行时检查)。

我个人会发现完整的编译时类型安全非常重要,至少从理论角度来看,最多从可靠代码的角度来看。编译时类型安全的一个结果是不再需要强制转换(我认为这很好,因为无论如何它们都很丑)。任何类似强制转换的行为都可以通过隐式转换运算符或构造函数来实现。

所以我想知道,目前是否有任何 OO 语言在编译时提供如此严格的类型安全,以至于强制转换已过时?即,他们不允许任何不安全的转换操作?或者有什么原因这不起作用?

感谢您的任何意见。

编辑

如果我可以举例说明,这就是我如此讨厌沮丧的主要原因。

假设我有以下内容(大致基于 C# 的集合):

public interface IEnumerable<T>
{
     IEnumerator<T> GetEnumerator();
     
     IEnumerable<T> Filter( Func<T, bool> );
}

public class List<T> : IEnumerable<T>
{
    // All of list's implementation here
}

现在假设有人决定编写如下代码:

List<int> list = new List<int>( new int[]{1, 2, 3, 4, 5, 6} );
// Let's filter out the odd numbers
List<int> result = (List<int>)list.Filter( x => x % 2 != 0 );

请注意最后一行的演员表是如何必要的。但它有效吗?一般不会。List<T>.Filter当然,实现将返回另一个是有道理的List<T>,但这不是保证(它可以是 的任何子类型IEnumerable<T>)。即使它在某个时间点运行,以后的版本也可能会改变这一点,暴露出代码的脆弱性。

几乎所有我认为需要向下转换的情况都可以归结为像这个例子这样的东西——一个方法具有某个类或接口的返回类型,但是由于我们知道一些实现细节,我们有信心向下转换结果。但这是反 OOP 的,因为 OOP 实际上鼓励从实现细节中抽象出来。那么我们为什么要这样做,即使是纯粹的 OOP 语言呢?

4

3 回答 3

2

通过提高类型系统的能力,可以逐渐消除向下转换。

您给出的示例的一种建议解决方案是添加将方法的返回类型声明为“与此相同”的功能。这允许子类返回子类而不需要强制转换。因此你会得到这样的东西:

public interface IEnumerable<T>
{
 IEnumerator<T> GetEnumerator();

 This<T> Filter( Func<T, bool> );
}

public class List<T> : IEnumerable<T>
{
    // All of list's implementation here
}

现在演员表是不必要的:

List<int> list = new List<int>( new int[]{1, 2, 3, 4, 5, 6} );
// Compiler "knows" that Filter returns the same type as its receiver
List<int> result = list.Filter( x => x % 2 != 0 );

其他向下转型的案例也提出了通过改进类型系统的解决方案,但这些改进尚未针对 C#、Java 或 C++ 进行。

于 2012-11-07T01:18:42.783 回答
1

好吧,当然有可能拥有根本没有子类型的编程语言,然后自然就不需要向下转换了。大多数非面向对象的语言都属于这一类。

即使在像 Java 这样的基于类的 OO 语言中,大多数向下转换也可以通过简单地让基类有一个方法来正式替换

Foo meAsFoo() {
   return null;
}

然后子类将覆盖它以返回自身。然而,这仍然只是表达运行时测试的另一种方式,但使用起来更加复杂。并且很难在不失去基于继承的子类型的所有其他优点的情况下禁止该模式。

当然,这只有在您能够修改父类时才有可能。我怀疑您可能会认为这是一个加号,但考虑到一个人可以修改父类的频率并因此使用解决方法,我不确定在鼓励“好”设计方面有多少价值(或多或少“好”的任意值)。

如果该语言提供大小写匹配结构而不是向下转换表达式,则可以证明它会更多地鼓励安全编程:

Shape x = .... ;
switch( x ) {
  case Rectangle r:
    return 5*r.diagonal();
  case Circle c:
    return c.radius();
  case Point:
    return 0 ;
  default:
    throw new RuntimeException("This can't happen, and I, "+
            "the programmer, take full responsibility");
}

然而,在实践中可能会出现一个问题,如果没有封闭世界的假设(现代编程语言似乎不愿意做出),许多开关将需要default:程序员知道永远不会发生的情况,这可能会使程序员失去敏感性到最终的投掷。

于 2011-08-20T23:34:47.980 回答
0

有许多具有鸭子类型和/或隐式类型转换的语言。Perl 肯定会浮现在脑海中。标量类型的子类型如何在内部转换的复杂性经常受到批评,但也受到称赞,因为当它们按您预期的方式工作时,它们有助于语言的 DWIM 感觉。

传统的 Lisp 是另一个很好的例子——你所拥有的只是原子和列表,nil它们同时是两者。否则,这对双胞胎永远不会见面......

(不过,您似乎来自一个编程语言必然是面向对象、强类型和编译的世界。)

于 2011-09-10T16:36:53.927 回答