泛型编程在Delphi中的实现(200分)

  • 主题发起人 左轻侯
  • 开始时间
D

dream_soft

Unregistered / Unconfirmed
GUEST, unregistred user!
To yysun:
说实话,我不太了解你的意思。能给出具体一点的方案吗?因为我从你的话中设想了几
种可能性,却似忽都不能同时达到"类型通用并且类型安全"这两个条件。
谢谢。
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
To flier: 我是这样理解,不知道对不对:

您谈到的泛型的好处,本质上是“抽象”的好处。泛型做到了“抽象”,所以有这些好处。
但是,反过来,“抽象”不是泛型专有的。那些好处不能证明泛型的高明。同样实现了
“抽象”的还有其他方法,例如 OO 的方法,也能得到那些好处。

泛型的思想体系是什么?“抽象”+ 效率/类型安全。
泛型没有理论性,其理论依据是“抽象”。剥去“抽象”这层含义,泛型就剩下 C++ 中用
template + 编译器预处理文本,来得到效率/类型安全。不用template的泛型就不能算泛型。
只能回到如何实现“抽象”上了。

在 Delphi 支持 template 以前就没有泛型可言,只有“抽象”。
不存在“泛型编程在delphi中实现”的概念,只有“在Delphi中如何抽象”。

硬是用 Delphi 模拟泛型,其结果就是很差的 OO 设计。我谈到接口的意思是说用接口
替代泛型实现“抽象”,而不是用接口实现泛型。[:)]

说说您的接口构架是如何失败的吧。
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
to dream_soft:
定义一个接口
IxListFriendly = interface
end;
TxList 只接收实现了 IxListFriendly 接口的对象。
TxList = class
procedure AddElement(element: IxListFriendly);
end;
您的类如果想放进 TxList 则必须实现 IxListFriendly 接口。
TMyClass = class(TObject, IxListFriendly)
end;
您看看能不能达到您的要求?
 
D

dream_soft

Unregistered / Unconfirmed
GUEST, unregistred user!
To yysun:
对不起,可能是我对interface了解的不够。IxListFriendly中到底包含着什么样的秘密,
可以让继承它的类成为类型安全?
解释一下我对你方法的理解。
第一种猜想,是在IxListFriendly中包含了能自动转换类型到对象真实类型信息的代码。
第二种猜想,是将所有你要调用的所有方法都包括在IxListFriendly接口中。
但这两种方法都不能满足我所说的条件,所以想请教孙老师你的实现方法。
 
F

flier

Unregistered / Unconfirmed
GUEST, unregistred user!
To yysun:

不用那么客气,“您”字听起来怪别扭的 :)
我记得我曾经说过这样一句话,“范型编程思想是以与OO不同的角度看待问题域”。
的确,OO或者范型,只不过是一直抽象的方法而已,两者都是方法论,并不存在好坏之分,
只是对于不同的情况有着自己的优势和劣势而已。从最初的结构化,到后来的Object-Based,
到OO,到接口,到GP,到以后的Agent,其实都是在尝试着以更高的层次来抽象这个世界,
他们都有自己的思想体系,有自己的方法论,是独立的世界观。这些思想体系只是
基于不同的观察角度来诠释这个世界而已,并没有谁取代谁的必要性和可能性。
我前面的文章也只是阐述范型编程相对于现有其他思想体系的一些优势,并没有说OO
会被其取代啊。范型的优点也不是具有完全普遍性的,只是对于目前很多情况适用而已。
如果我的文中没有说明这个观点,造成了你的误解,请原谅。
实际上以我的理解,范型思想是可以很好地与OO想结合的。在OO思想看来,世界就是
由无数的对象组成的,这些对象通过抽象可以构造成一棵包含万事万物的类树 :)
这可以说是OO的世界观(可能不全面,但我想也差不多:)。而在范型思想看来,世界分为
静态的和动态的两个部分(我的理解,不一定对)。静态的是那些具有普遍意义的行为,
或者说算法;动态的则是算法操作的对象,这些对象被容器组织起来。行为或者算法本身,
并不对某种特定类型的对象进行操作(这大概是你理解的类型无关抽象),而是通过Concept
(观念?概念?我不知道该怎么翻译)进行操作,这里的Concept本身就可以看作是一组
行为的集合,比如Input Iterator Concept包含*i, ++i, i++等等这些行为,
而容器本身也是一直Concept,比如Container Concept包含begin(), end(),
size()等等,算法只针对Concept进行设计,根本不去管具体的类型,因此称之为
Generic。因此,范型编程的抽象和OO中的抽象是有区别的,他们对世界分类的标准是
不同的。而且,范型思想的抽象层次可以说比OO又高了一层,因为从OO到接口,说到底
还是有类型的,到了GP,根本就连类型都没了,呵呵,只剩Concept了。因此,我认为
接口的思想是OO思想的进化表现,因为他抽象出了行为集;范型编程又是另一次进化,
他将接口中行为集与原来思想的唯一联系——类型也给割断了,就好像具有普遍意义的
接口一样。如果用过COM中的IEnumXXX一套接口,就可以体会出其中奥妙。
但是,范型思想也不是凭空存在的,因为他抽象的层次较高,必须挂接在其他
抽象方法上,比如OO。毕竟算法得有实现,而且要有操作对象,这些对象是OO最好的
用武之地。因此,我以为GP对OO不是取代而是改进,以GP的思想将OO中静止的那部分
抽出来,最大限度结合GP和OO才是正途。前者可以改善后者,特别是可以降低OO中
对象组织、互操作的复杂性;而后者是前者的基础,可以说没有OO、范型也没的玩,
起码实现起来复杂N倍。而且两者并没有什么直接的冲突。
至于template,我想我前面的文章已经说得很清楚了。你和前面朋友总是
认为范型就是template,template就是范型,这其实是错误的。那只是因为范型
思想现在在C++中实现得非常出色,而且基本上范型思想的发展就是随着C++一路
发展下来的,好像范型就是template。其实不然,范型的真正意义在于其通过
Concept这个渠道进行设计,他在设计时根本就不去考虑什么类型,什么存储,
所有需要考虑的就是提供的不同Concepts,比如设计一个find,我需要两个
Input Iterator Concept的Model定义一个查找范围,然后一个需要查找的值
这个值本身就是一类Concept,其行为是可进行比较等等(operator ==())。
然后我就可以设计出这个find,从头到尾就和类型不搭边。真正需要和操作对象打交道时,
委托给那些Concept的Model去干,比如Input Iterator Concept有++i, i++
行为,可以遍历一个Container Concept,如果需要随机访问就得有一个
modal of Random Access Iterator Concept等等
映射到实现中就是一组算法,一组Iterator,一组Container,诸如此类的东东
注意,这里只是一个映射而已。也就是说,我在C++里可以把这些Concept映射成以
Template实现的class,我在delphi/java里一样可以映射成对单根的ADT进行操作的class,
只要实现了这些Concept,算法本身就是静态的,就可以说他是遵循GP思想的。
至于Template实现GP的优势,我也非常喜欢。但这并不意味着GP只能以Template实现
例如在Delphi/java这一点的单根类结构中,也可以实现这些行为。
好了,手也敲累了,先说到这里吧,明天有精神再说 :)
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
能得到有两位高手的指教,荣幸之至。[:)]

to dream_soft: 我是这样解释的:
1、如果不实现 IxListFriendly 接口的类是放不进 TxList 的(编译器会报错)。

2、TxList 需要的操作,比如 int hashValue()
string getClassName()
定义在 IxListFriendly
接口里,不可能调不到 hashValue() 或者 getClassName(), 有可以判别类的类型。
这两点保证安全性。

3、任何想用 TxList 作为容器的类,都需要实现 IxListFriendly 接口。
这点保证通用性。因为接口不影响基类。 您可以这样
TMyClass = class(TMySuperClass, IxListFriendly)

这种接口是 Java 的 interface,类似于 C++ 中的纯虚类。Delphi 6 中有了这种接口。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=596317

可能是我对您所说的“类型安全” 不很了解。您能否详细一些要达到什么目标。


to flier:我觉得如果您把泛型看作“类型无关的抽象”和 Concept 层次上的东西的话。
可以说归纳研究 Concept 不是 Delphi,也不是 C++/Java 的范畴,而是脱离具体语言的抽象
化过程。(目前我看到的关于泛型的文章真的多是列表、堆栈、排序、矩阵之类东西的原理研究。
可以知道泛型基本上是局限于局部算法的精化,它不在于改善系统构架以及对象的交互。
当然,这也很重要)。

这种 Concept 最好是用伪语言写出来。因为它们是纯粹的算法,是思想。
有了 Concept,在具体语言中如何应用 Concept?

C++ 正好有 template 机制,可以把具体的类替换进去,得以使得多种类都可以应用
这些 Concept。

Delphi 没有 template 和编译前替换机制,对那些 Concept 的应用,有两种方法:
1、这些 Concept 必须直接翻译并写到特定的类中。
2、必须更多地依赖 OO 的结构、定义基类、定义接口等等,使得这些 Concept 被重用。

当然是后者好些。可是这样的话,考虑的是全体对象的排列、交互和调用,以便把符合
那些 Concept 算法的程序片断 在更多的类里、更方便的应用起来。
这就成了设计模式的东西了。
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
to flier:
我想了想,我们之间因为对 GP 的定义不同,因而看起来已经不是讨论同一桩事请了。

您定义的 GP = Concept
我定义的 GP = Concept + template

且不说,哪种定义比较准确。实际上,依据不同的定义,所得到的结论都是正确的。

您说的:“使用遵循这种思想的程序,就取得得到范型编程的优势。”
意思就是遵循那种精炼的 concept,就有优势。-- 正确!

我说的:“在 Delphi 支持 template 以前就没有泛型可言,只有“抽象””。
意思就是没有可能模拟 template 的替换方式,把 Concept 用到 Delphi 中,
应该选用,“抽象”的方法。 -- 也是正确的吧。

您谈的是标准化的 Iterator, Container 等的重要意思,并认为除了用 template
还有其他办法。-- 正确!

我谈的是 Delphi 中替代 template 的是可以用 interface 在 Iterator,Container 等
和普通对象之间建立沟通的桥梁。-- 也是正确的吧。

您说的抽象是:算法的抽象。
我说的抽象是:对象的抽象。

我看您还是否具体些,指出您的准备用到 delphi 的 Concept 到底是哪几个概念。
我看看接口是否真的做不了。
 
F

flier

Unregistered / Unconfirmed
GUEST, unregistred user!
To yysun:
注意,我们讨论的题目是“泛型编程在Delphi中的实现”:)
之所以我们花了那么多时间讨论GP本身和OO的关系
是因为前面你和一些朋友认为GP在Delphi中无法实现
或者不值得实现,因此我才发文反驳,因为GP在Delphi
中的实现,在我看来可行性和必要性都是无可非议的
之后讨论又集中在GP到底是否必须以Template实现
我们各执一词,你可能更多地从对C++的理解,认为
GP = Concepts + Template,而我认为Template是手段
不是目的,所以有此争论

我以为这些争论应该还是有价值的,因为没有一个对GP
的明确认识,去理解他,实现他,应用他都是困难的
至于GP在Delphi中的实现,或者说GP思想在以Delphi为
代表的单根类结构语言中的映射,DeCal已经做了第一步
的尝试,我相信以后这种尝试会更多,大家都在努力中 :)

en, 给我感觉也是我们对GP本身的理解就有很大分歧,
这些争论下去本身就是无谓的,不过通过争论我还是
学到了很多东西,起码逼着我去看了不少文档,呵呵
这个要很感谢你的说 :)

btw:接口做是可以做,但是很多情况下并不能很好体现GP
思想,这就是为什么我淘汰了纯接口实现的原因,
当然,目前我的几种尝试中,都或多或少地用到了接口
 
T

touip

Unregistered / Unconfirmed
GUEST, unregistred user!
这么多大虾,举世关注
 
M

mikedeakins

Unregistered / Unconfirmed
GUEST, unregistred user!
单根类中如何实现类特性的派生?多重继承的优势在于一个类可以转换为多个实现目的不同
的类来使用。不错,vcl 确实是单根的,但是 vcl 做的工作大多只是提供单一用途的对象,
并不涉及到通用算法,并且是类型相关的。
flier 的泛型观点我搞不懂。
 
G

gwbasic

Unregistered / Unconfirmed
GUEST, unregistred user!
高手过招,精彩呀!!
 

流浪者

Unregistered / Unconfirmed
GUEST, unregistred user!
听天书,不过还要继续听的,听君一席话,胜读十年(百年???)书啊!!

惭愧啊,牛年马月俺才达到以上各位老师的水平哦???
 
T

Tense

Unregistered / Unconfirmed
GUEST, unregistred user!
精彩。
关注。期待更好的结论。
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
to flier: 关键还是我们的定义有所不同。讨论的题目是“泛型编程在Delphi中的实现”:)

在您看来就是 “Concept 在Delphi中的实现”,这当然是“可行性和必要性都是无可非议
的”。我同意。

在我和其他一些人看来就是:“Concept + template 的组合在Delphi中的实现”,于是
我的结论是:“用 Delphi 的 RTTI 或者 Java 的 Reflection 来模拟 C++ 的模板”没
有意义,而是应该用“需要认认真真的类设计。通过设计模式提高对象的可重用性。”

各人立场不同,定义对换一下:
“Concept + template 的组合在Delphi中的实现”,当然“可行性和必要性都是无可非议
的”的观点。在我和其他一些朋友不同意。您也只认为“Template是手段不是目的”

“Concept 在Delphi中的实现”是“没有意义”的这个观点,你自然也不同意,我也不同意。

这就是产生争论的根源。所以我发现“我们已经不是讨论同一桩事请了”[:(]
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
我关于 GP 论述的第一句话就是:

Generic programming 广义上讲是:对通用概念和相关实例进行抽象。
而狭义上讲就是 C++ 用利用模板(template)机制实现代码重用。

然后,我就说明 GP 在 C++ 很成功,是因为它同时体现了 抽象 + 效率。
结论,就是这样的(利用模板的)GP 在 Delphi 中靠模拟是出不来的。
只有靠对象设计。或者等到编译器直接支持(如jdk1.5)。

这是我的主题思想和逻辑。请大家指正。
 
D

dream_soft

Unregistered / Unconfirmed
GUEST, unregistred user!
To yysun:
我想我们对类型安全的理解是不一致的。在使用Template实现的List模版类中,不但
在List本身中的操作中是类型安全的,而且如果在List中加入某型类,则自List中读出的
就直接是该类型本身,而不会是它的父类或实现的IxListFriendly接口。因为在返回父类
和接口的情况下,如果TxList类将用于多个类(这多个类都定义了IxListFriendly接口),
程序员仍然必须手动转换类型至真实类型才能安全调用。这实际上是将维护类型的责任放到
了程序员的身上。因为程序员必须保证放入Txlist的对象一定是正确的,编译器并不能
检查出问题:因为都实现了IxListFriendly接口。
据philip wadler(Java GP专家委员会成员)所说,这是在Java中引入GP的重要原因。

To flier:
我个人认为,STL并不代表GP。GP的关键概念,正如中文译名,是泛型,[red]是类型安全的
类型无关性[/red],是将数据类型当成数据进行处理的一种理念。Delphi最具此理念的,我感
觉是类引用这个概念。至于STL中Concepts概念,其实质就是类型无关的回调接口。只是因着
Templat的实现,并不一定用虚函数而已。而你所说的算法与数据的分离,除了因着类型
无关而来的新特性外,总让我想起过程程序设计,这并不能代表GP所能涵盖的范围。
将类型无关的思想与OO结合,我想,是可以对现有的OO中心的设计模式产生影响的。使
用Delphi中最具GP思想的类引用,不就可以对创建型模式进行革新?例如在一定程度上取
代Factory Method的作用,增强Abstract Factory的功能?虽然因着类引用本身的限制,
我还不未能想出解决Create函数带有不同参数的问题。但这该可视为一种可行的尝试。
再者,你一再指出的"用单根的ADT进行操作的class"可以实现GP,我想这仍是没得到证
明的。Template不是实现GP的唯一方法,但在现阶段来说,我认为它是最好的方法。
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
flier 兄反对我的上述观点,他以“范型编程的意义并不是只在于效率”......“可维护性更重
要。”开场。然后举出一个例子,作为“范型编程优势的体现”。

可是,我觉得那个程序有“为泛型而泛型”的嫌疑,因为它把程序越弄越复杂了。在我给出
明明本来就很简单的程序的同时,我提出关键要证明在 Delphi 这样泛型优越在什么地方,
以至于非用不可(因为既然会有很多优势的话)。可是,我得到的回答是“用什么技术是你的
自由”以及“用不用范型编程思想,是具体问题具体分析,实事求是”。

于是,我进一步论述我的定义:“泛型的思想体系是什么?“抽象”+ 效率/类型安全”。
认为:
1、“剥去“抽象”这层含义,泛型就剩下 C++ 中用 template,
2、不用template的泛型就不能算泛型。只能回到如何实现“抽象”上了。

这时,flier 兄才说明,他一直在谈的是“类型无关抽象”- Concept。
我这才明白过来,他的 GP = Concept。

Concept 很重要,这我当然也同意的。因为我一直是在说“concept + template”不可行,
需要“concept + OO”。正是因为 Concept 重要、必要,才必须选择好得手段来实现到
Delphi,不能模拟 template,而是需要设计模式。

这是,到目前的讨论结果,我看没有本质上的分歧。
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
所以,现在我要出个题目给大家: GP = Concept 还是 GP = Concept + tempalte?
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
原来 dream_soft 也在线上啊。
dream_soft, 我想也是我们对类型安全的理解是不一致的。

我认为的类型安全是:大家都有可比性,共同的IxListFriendly接口。同样返回 Hash 值
以便排序,或者比较。 Java 的 Collection Framework 就基于这样的概念。

您可能要求的是得到绝对相同的类,既然 philip wadler 那么说,就是证明目前 Java
做不到,必须引入 template,而 Delphi 到了 D6 才有了象 Java 那样的接口,刚刚得以
实现我说的可比性。哪天有了 template 才能达到您的要求。

您那么问我简直是给我下了个套去钻啊 [:D]
 
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
dream_soft, 这样吧,请您来说说:没有 template ,算不算 GP?
 
顶部