我有兴趣学习一种语言,它在内部处理对象作为哈希表(如JavaScript),但可以用强类型包装它们,以便在设计时提供代码完成/智能感知的好处。以下是我希望这种梦想语言能够发挥作用的方式:
public class Lion
{
public void Roar() { Console.WriteLine("Aaarrgghh");}
}
public static Main(string[] args)
{
object myCat = new object(); // just plain object, no type!
// adding a Roar() method to the myCat instance
myCat.Roar += delegate() {Console.WriteLine("Miauew");}
// At this point myCat should qualify to be a Lion.
// So we should be able to successfully duck-type-cast
// her to a lion
Lion myLion = myCat as Lion;
// now the myLion reference is strongly typed,
// so I expect the Intellisense window pop up
// and offer me the Roar() method when I hit the dot after "myLion"
myLion.Roar();
}
我希望这个程序能够无错误地编译,无异常运行并打印 控制台上的“Miauew”。有没有可以做到这一点的语言?也许C#4.0?
答案 0 :(得分:3)
也许是C#4.0中的新动态类型。 看看这个:http://blogs.msdn.com/cburrows/archive/2008/10/27/c-dynamic.aspx
答案 1 :(得分:2)
这取决于您希望Lion类型实现非虚拟方法的目的。
扩展类型(给定类型的对象集合是那些具有类型属性的对象,它接近于鸭子类型的静态等价物)要求对象的结构暗示其类型,但你的狮子类型没有结构 - 它只是说任何狮子都有特定的咆哮方法。所以对于你的例子,我看不出你有什么方法可以把你的猫变成狮子,因为它没有狮子会所说的唯一结构属性。
另一方面,如果您打算说任何你说的狮子可能有自己的咆哮方法或将使用Lion中的方法,那么它并没有说任何关于狮子的物体类型,而AFAIK你可以通过对象的扩展方法获得相同的行为(虽然我不知道C#是否知道自我方法是否覆盖C#中的扩展方法)。
在动态IDE中,在IDE可以确定myCat具有Roar属性之前,您没有理由需要强制转换为Lion - 该信息是静态可推导的。
IDE支持在具有动态构造类型(如JavaScript)的语言中很难实现,您可以这样做:
let myCat = {}
if ( locale.name == 'en' )
myCat.roar = function () { alert ( "Miauew" ); }
else
mCat[ resources.getString( 'roar' ) ] =
function () { alert ( resources.getString ( 'Miauew' ) ); }
// the structure of the type of myCat depends what locale the code
// is running in, so you can't deduce the Intellisense
myCat.
这种情况当然意味着你无法预测代码是否会起作用,没有更深入的分析(例如,检查你的法国猫总是被要求用法语咆哮)。
如果Intellisense无法推断出结构具有静态可推导性的对象的结构,那么这就是Intellisense的弱点,而不是动态类型。
您认为您的示例中强类型的好处是什么?
答案 2 :(得分:2)
每当我尝试计划任何此类事情时,问题就在于演员。当然你可以用程序员的话来说明,但这结合了两种打字系统的最差功能。也许演员可以在运行时检查一个对象是否实现了Lion接口,但这基本上是不可能的。在这种情况下,它看起来似乎有道理,因为你需要的只是void (*)()
函数的存在。但总的来说,如果Lion有一个getHabitat
方法返回一个应该是另一个接口的对象呢?一个强类型语言需要能够肯定地说它确实存在,但是如果没有实际调用该方法,你通常无法判断无类型代码是否返回一个Habitat,因此在强类型术语中你无法工作看看它是不是狮子。
所以我从来没有遇到这样的问题:在混合弱类型和强类型的代码段时,你最终会得到强类型的代码,在任何时候它都可以调用一个方法然后找回一个没有实现它应该的接口。这不是强类型,它是动态类型,具有误导性的代码注释。
答案 3 :(得分:1)
这是一个有趣的想法,也是之前探索过的想法。在我给你拍摄之后,我将链接到一些研究和现有的工作。我将讨论脚本语言和静态命令式语言,因为我认为这就是你所说的。
基本问题是类型在静态和动态类型系统中并不意味着相同。在动态系统中,类型是值的属性,并且当值传递时,类型也是如此。在静态系统中,您可以限制变量(等)可能保存的值的类型。到目前为止一切都很好。
当您查看如何在脚本语言中使用对象时会出现问题 - 它们都是鸭子类型。这意味着类型(nominal-typing)的名称无用。所有现代命令式语言(Java,C#,C ++,C)都使用名义类型系统。所以在C ++中你可能会说你期望Duck
,但在Python中你真的想要quack()
。
因此,请考虑为duck-typed语言添加静态类型。由于函数会将参数表达为quack()
,但它不能说它期望Duck
,因此将两者结合起来很困难。您可以定义一个名为quacks
的接口,它可以quack()
,并将其用作类型。但这确实有点冗长,这会破坏动态打字的好处。也许,沿着这些方面可能有某些东西(某种structural type system)可以做到这一点。
另一种方法是只要求程序员指定Duck
,并且无论如何该死的业务 - 没有人真的使用它吗?但是,你只是在Python中编写Java,并且作为尝试过一次的人,让我告诉你它非常适得其反。
让我们以另一种方式看待它。 C#将如何从dynamic
关键字中受益?简单的答案是它不会。老实说,我没有看到你在C#dynamic
中从Python中获得的任何美丽和自由。现在,我唯一知道的就是来自Jon Skeet的演讲,但我得到的压倒性印象是它的冗长和不雅。而且我认为这不是来自C#民谣的实现错误。我认为这是因为动态类型在Python中解决的问题已经在C#中得到了解决(尽管很冗长),dynamic
只是给聚会带来了什么。
查找Jeremy Siek's gradual typing内容,了解最先进的静态/动态研究。虽然它有点难读,但我自己只是粗略地看了一眼,所以我无法总结它。然而,单独浏览他的相关工作很有意思,STOP conference可能会有很好的东西。
答案 4 :(得分:0)
与您的示例没有密切关系,但Scala的implicit conversion是一个经过深思熟虑(尽管有时难以理解)的机制,以完全受控的,静态检查的方式扩展类的功能。
此外,有structural typing有时可以用作类型安全方式的鸭子输入的替代品。