The current state of generics in Delphi

 

To avoid duplication of generated code, the compiler builders of Embarcadero have done a nice job. They introduced new instrinsics like IsManagedType, GetTypeKind and IsConstantType (see this Stackoverflow answer), so they could make a function like the following generate a call to the exact function for the parametric type directly. This means that the code below "runs" completely inside the compiler, even the code in the called InternalAddMRef and similar dispatching routines.

function TList.Add(const Value: T): Integer;
begin
if
IsManagedType(T) then
begin
if
(SizeOf(T) = SizeOf(Pointer)) and (GetTypeKind(T) <> tkRecord) then
Result := FListHelper.InternalAddMRef(Value, GetTypeKind(T))
else if GetTypeKind(T) = TTypeKind.tkVariant then
Result := FListHelper.InternalAddVariant(Value)
else
Result := FListHelper.InternalAddManaged(Value);
end else
case
SizeOf(T) of
1: Result := FListHelper.InternalAdd1(Value);
2: Result := FListHelper.InternalAdd2(Value);
4: Result := FListHelper.InternalAdd4(Value);
8: Result := FListHelper.InternalAdd8(Value);
else
Result := FListHelper.InternalAddN(Value);
end;
end;

That, in its turn, means that if you code something like:

var
List: TList<string>;
begin
List := TList<string>>.Create;
List.Add('Hello');

then

List.Add('Hello');

is in fact directly compiled as

List.FListHelper.DoAddString('Hello');

i.e. TList.Add does not have any runtime code at all, the result of "calling" it (see above) is the generation of a direct call to the DoAddString function. That is a simple method, not generic, not virtual or dynamic, like all the other methods of TListHelper, so the unused functions can be eliminated by the linker. This also means there is hardly any duplication of generated code anymore, i.e. if another part of the same executable also uses TList<string>.Add it will use the same function.

No code duplication?

Well, this means that if the class is coded like above, there is no unnecessary duplication of generated code anymore. That is cool and can probably reduce the expected bloat caused by using generics.

But it also means that it greatly reduces one of the advantages associated with generics: no unnecessary duplication of source code. You write a routine once, and only the type it works on is parametrized. The compiler takes care of generating code for each used routine and parametric type.

But then you still get the dreaded bloat. So you either duplicate a lot of source code (take a look at the code of TListHelper in System.Generics.Collections to see what I mean; for example, the functions DoAddWideString, DoAddDynArray, DoAddInterface and DoAddString contain exactly the same code, except for the lines where FItems^ is cast each to a different pointer type), which is almost as much work as writing a separate TList for each type, or you use the naïve approach, writing code only once, as generics should actually be used. But then you could get bloat again, i.e. it is well possible that the same routine gets generated multiple times, in different units of the same executable.

What to do?

There is not much we can do, except to emphatically ask Embarcadero to put the kind of logic that was implemented in TList<T> and other generic classes to avoid duplication of generated code, in the compiler and linker, so we don't have to write huge helper classes nor get the bloat.

In the meantime, you can do what Embarcadero did: if your class is used a lot for many different types, do a lot of "copy and paste generics". Otherwise, if you only have to deal with a few types and in a few places, simply use the naïve approach. Or you use a hybrid approach, using the intrinsics mentioned above and implementing the most used helper functions for the types you need most.

Let's hope they get a lot of requests and implement these things in the compiler and linker, like other languages with generics, e.g. C# or C++, do.

Rudy Velthuis

The current state of generics in Delphi( 转载)的更多相关文章

  1. “Operation is not valid due to the current state of the object.”

    将Repeater单页显示的2000条数据一次性提交的时候出现这个错误: Operation is not valid due to the current state of the object. ...

  2. 关于 error: Operation is not valid due to the current state of the object。

    今天碰到一个特别的异常. Operation is not valid due to the current state of the object. at System.Web.HttpValueC ...

  3. Error occurred in deployment step 'Add Solution': Operation is not valid due to the current state of the object.

    Sharepoint 部署的时候出现一个错误 Error occurred in deployment step 'Add Solution': Operation is not valid due ...

  4. Operation is not valid due to the current state of the object.

    今天遇到一个asp.net的草郁闷的问题,看下截图 狂晕啊,在google上狂搜了一下,好在已经有大侠也遇到过这个问题了,先看下别人的解决办法吧 Operation is not valid due ...

  5. Unable to boot device in current state: Creating

    安装完xcode6.1后,将其改名为Xcode6.1.app,再移动个位置,启动模拟器,问题来了: Unable to boot device in current state: Creating 解 ...

  6. Cannot attach medium 'D:\program\VirtualBox\VBoxGuestAdditions.iso' {}: medium is already associated with the current state of machine uuid {}返回 代码: VBOX_E_OBJECT_IN_USE (0x80BB000C)

    详细的错误信息如下: Cannot attach medium 'D:\program\VirtualBox\VBoxGuestAdditions.iso' {83b35b10-8fa2-4b81-8 ...

  7. vs问题解决:an operation is not legal in the current state

    debug时弹出提示框:内容有:an operation is not legal in the current state 解决方案: Go to Tools > Options > D ...

  8. GridView Postback后出错Operation is not valid due to the current state of the object.

    一.问题起因 最近项目中有一页面第一次search后正常,但是再次点击其它任何按钮都会报错,亦即postback后页面有问题,经检查是由于页面有一GridView且数据量极大,记录大概有上千条,这儿解 ...

  9. 前端 vue单页面应用刷新网页后vuex的state数据丢失的解决方案(转载)

    最近接手了一个项目,前端后端都要做,之前一直在做服务端的语言.框架和环境,前端啥都不会啊. 突然需要前端编程,两天速成了JS和VUE框架,可惜还是个半吊子.然后遇到了一个困扰了一整天的问题.一直调试都 ...

随机推荐

  1. keil5 MDK 链接报错 Error: L6410W 解决

    keil5 MDK 报错 Build target 'Project' linking... .\Output\Project.axf: Warning: L6310W: Unable to find ...

  2. Django项目的创建

    一. Django介绍 Python的WEB框架有Django.Tornado.Flask 等多种, Django相较与其他WEB框架其优势为: 大而全, 框架本身集成了ORM.模型绑定,.模板引擎, ...

  3. 使用 JavaScript 将 XML 转成 JSON

    function xmlToJson(xml) { // Create the return object var obj = {}; if (xml.nodeType == 1) { // elem ...

  4. rpm软件包、yum软件仓库、systemd初始化进程

    rpm软件包.yum软件仓库.systemd初始化进程 作者:Eric 微信:loveoracle11g 红帽软件包管理器rpm (Redhat Package Manager) RPM会建立统一的数 ...

  5. Navicat工具怎么连接oracle数据库

    当我们安装完oracle数据库之后,我们会想着用可视化工具连接,navicat是我们常用的可视化连接数据库的工具 当我们安装完oracle数据库的时候,我们需要先启动他 先把相应的服务启动 保证这两个 ...

  6. Python的随机数模块

    random模块中几个随机函数用法. 引入random模块: import random 1.random.random() 此函数用于生成一个0到1的随机浮点数:0 <= n < 1.0 ...

  7. ORACLE重装之后恢复数据库,相当于sqlserver的附加数据库

    在开发机器上经常会遇到重装系统的问题,重装之前如果ORACLE没有及时备份的话重装之后就纠结了,数据还原很头疼. 各种娘中只能找到一些ORACLE安装与重装系统前目录相同的解决办法,目录不同就没招了. ...

  8. 分布式计算课程补充笔记 part 3

    ▶ OpenMP 的任务并行 (task parallelism):显式定义一系列可执行的任务及其相互依赖关系,通过任务调度的方式多线程动态执行,支持任务的延迟执行 (deferred executi ...

  9. 分布式计算课程补充笔记 part 2

    ▶ 并行计算八字原则:负载均衡,通信极小 ▶ 并行计算基本形式:主从并行.流水线并行.工作池并行.功能分解.区域分解.递归分治 ▶ MPI 主要理念:进程 (process):无共享存储:显式消息传递 ...

  10. jQuery入门基础(动画效果)

    一.隐藏显示 1.show()--显示隐藏的被选择元素 例:$(selector).show(speed,callback); 2.hide()--隐藏被选元素的内容 例:$(selector).hi ...