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. 刘志梅201771010115.《面向对象程序设计(java)》第二周学习总结

    实验二 Java基本程序设计(1) 实验时间 2018-9-6 第一部分:理论知识学习 3.1一个简单的Java应用程序 关键字public称为访问修饰符,这些修饰符用于控制程序的其他部分对这段代码的 ...

  2. 谷歌浏览器内核Cef js代码整理(一)

    尊重作者原创,未经作者允许不得转载!作者:xtfnpgy,原文地址: https://www.cnblogs.com/xtfnpgy/p/9285359.html 一.js基础知识 <!--   ...

  3. Titanic缺失数值处理 & 存活率预测

    1.  kaggle泰坦尼克数据titanic完整下载,原作者良心分享 https://download.csdn.net/download/lansui7312/9936840 2. 缺失值处理 # ...

  4. Apache Struts2高危漏洞(S2-057CVE-2018-11776)

    花了两天时间,特此记录 一:背景: 2018年8月22日,Apache Strust2发布最新安全公告,Apache Struts2存在远程代码执行的高危漏洞. 二:漏洞产生原理: 1.需要知道对应跳 ...

  5. YAML基本语法

    正如YAML所表示的YAML Ain’t Markup Language,YAML /ˈjæməl/ 是一种简洁的非标记语言.YAML以数据为中心,使用空白,缩进,分行组织数据,从而使得表示更加简洁易 ...

  6. Node2.js

    Node.js简单爬虫的爬取,也是跟着慕课网上抄的,网站有一点点改动,粘上来好复习嘛 var http = require('http') var cheerio = require('cheerio ...

  7. 11. Container With Most Water (JAVA)

    Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). ...

  8. weld

    weld - 必应词典 美[weld]英[weld] v.焊接:熔接:锻接:使紧密结合 n.焊接点:焊接处 网络焊缝

  9. 算法练习LeetCode初级算法之树

    二叉树的前序遍历 我的解法:利用递归,自底向下逐步添加到list,返回最终的前序遍历list class Solution { public List<Integer> preorderT ...

  10. AltiumDesigner 查找相似对象

    同类器件的集体选中.集体选中的方法是:先选中一个标识符,右击在选项表中选择Find Similar Objects,然后就会出现一个对话框,在这个对话框中,有一些any项,根据自己的需要把一些any改 ...