<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TURBU Tech &#187; Generics</title>
	<atom:link href="http://tech.turbu-rpg.com/tag/generics/feed" rel="self" type="application/rss+xml" />
	<link>http://tech.turbu-rpg.com</link>
	<description>My thoughts on Delphi programming in general, and particularly on the technical aspects of developing the TURBU engine and editor.</description>
	<lastBuildDate>Fri, 27 Jan 2012 19:53:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Wish list: Generics collapsing</title>
		<link>http://tech.turbu-rpg.com/299/wish-list-generics-collapsing</link>
		<comments>http://tech.turbu-rpg.com/299/wish-list-generics-collapsing#comments</comments>
		<pubDate>Wed, 09 Feb 2011 22:13:55 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Generics]]></category>
		<category><![CDATA[Wish List]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=299</guid>
		<description><![CDATA[One annoying thing I&#8217;ve noticed in building my script compiler is the way the use of generic collections tends to bloat up the size of your EXE.  I use generics for a lot of things; a compiler uses lists, stacks and lookup tables (dictionaries) all over the place.  When I was building it with DeHL, [...]]]></description>
			<content:encoded><![CDATA[<p>One annoying thing I&#8217;ve noticed in building my script compiler is the way the use of generic collections tends to bloat up the size of your EXE.  I use generics for a lot of things; a compiler uses lists, stacks and lookup tables (dictionaries) all over the place.  When I was building it with DeHL, the compiler plus a very simple test frontend compiled into a 36 MB behemoth of a binary, and a quick look at the mapfile shows that the vast majority of that was DeHL collections.  Now that I&#8217;ve switched to the more simplified Collections library, it &#8220;only&#8221; takes 23 MB, a savings of about 33%.  But that&#8217;s still huge.  There has to be a better way.</p>
<p><span id="more-299"></span>Why does all this Generics code take up so much space?  Because generics aren&#8217;t actual code; they&#8217;re a template for creating actual code.  The compiler creates a new copy of the class for each instantiation of a generic class.  And this makes sense, to a certain extent.  You can&#8217;t reuse the same machine code implementation for, say, a TList&lt;TMyObject&gt; and a TList&lt;IMyInterface&gt;, because the interface version needs the compiler to generate the reference-counting code when working with the internal storage. Same for strings.  And records, integers and other value types need to be handled differently than objects and interfaces, which are reference types.  The compiler handles all that under the hood, and it makes our job a lot easier.</p>
<p>But&#8230; this has the side-effect of also making a bunch of silly, unnecessary copies.  For example, if you have a TList&lt;TMyObject1&gt; and a TList&lt;TMyObject2&gt;, the generated machine code for their routines will be identical, because there&#8217;s nothing in the difference between two classes that matters to TList&lt;T&gt;.  To illustrate, here&#8217;s a disassembly of the .Add methods of two different TList instantiations for two different class types.</p>
<p>Type 1:</p>
<pre>
<div class="codesnip-container" >
<div class="asm codesnip" style="font-family:monospace;">53 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> <span class="kw3">ebx</span>
56 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> <span class="kw3">esi</span>
51 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> <span class="kw3">ecx</span>
<span class="co2">8BF2</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">esi</span><span class="sy0">,</span><span class="kw3">edx</span>
<span class="co2">8BD8</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">ebx</span><span class="sy0">,</span><span class="kw3">eax</span>
<span class="co2">8B53</span>08 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">edx</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$08<span class="br0">&#93;</span>
42 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">inc</span> <span class="kw3">edx</span>
<span class="co2">8BC3</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="kw3">ebx</span>
<span class="co2">E856FDFF</span>FF &nbsp; &nbsp; &nbsp; <span class="kw1">call</span> Generics <span class="sy0">+</span> $43A074
<span class="co2">8B43</span>08 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">08</span><span class="br0">&#93;</span>
<span class="co2">8904</span>24 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="br0">&#91;</span><span class="kw3">esp</span><span class="br0">&#93;</span><span class="sy0">,</span><span class="kw3">eax</span>
<span class="co2">8B53</span>04 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">edx</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">04</span><span class="br0">&#93;</span>
<span class="co2">8934</span>82 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="br0">&#91;</span><span class="kw3">edx</span><span class="sy0">+</span><span class="kw3">eax</span><span class="sy0">*</span>4<span class="br0">&#93;</span><span class="sy0">,</span><span class="kw3">esi</span>
<span class="co2">FF43</span>08 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">inc</span> <span class="kw5">dword</span> <span class="kw4">ptr</span> <span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">08</span><span class="br0">&#93;</span>
<span class="co2">33C9</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">xor</span> <span class="kw3">ecx</span><span class="sy0">,</span><span class="kw3">ecx</span>
<span class="co2">8BD6</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">edx</span><span class="sy0">,</span><span class="kw3">esi</span>
<span class="co2">8BC3</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="kw3">ebx</span>
<span class="co2">8B18</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">ebx</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">eax</span><span class="br0">&#93;</span>
<span class="co2">FF53</span>04 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">call</span> <span class="kw5">dword</span> <span class="kw4">ptr</span> <span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">04</span><span class="br0">&#93;</span>
<span class="co2">8B04</span>24 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">esp</span><span class="br0">&#93;</span>
5A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> <span class="kw3">edx</span>
5E &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> <span class="kw3">esi</span>
5B &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> <span class="kw3">ebx</span>
C3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">ret</span></div>
</div>
</pre>
<p>Type 2:</p>
<pre>
<div class="codesnip-container" >
<div class="asm codesnip" style="font-family:monospace;">53 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> <span class="kw3">ebx</span>
56 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> <span class="kw3">esi</span>
51 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> <span class="kw3">ecx</span>
<span class="co2">8BF2</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">esi</span><span class="sy0">,</span><span class="kw3">edx</span>
<span class="co2">8BD8</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">ebx</span><span class="sy0">,</span><span class="kw3">eax</span>
<span class="co2">8B53</span>08 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">edx</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$08<span class="br0">&#93;</span>
42 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">inc</span> <span class="kw3">edx</span>
<span class="co2">8BC3</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="kw3">ebx</span>
<span class="co2">E856FDFF</span>FF &nbsp; &nbsp; &nbsp; <span class="kw1">call</span> Generics <span class="sy0">+</span> $43AC54
<span class="co2">8B43</span>08 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">08</span><span class="br0">&#93;</span>
<span class="co2">8904</span>24 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="br0">&#91;</span><span class="kw3">esp</span><span class="br0">&#93;</span><span class="sy0">,</span><span class="kw3">eax</span>
<span class="co2">8B53</span>04 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">edx</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">04</span><span class="br0">&#93;</span>
<span class="co2">8934</span>82 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="br0">&#91;</span><span class="kw3">edx</span><span class="sy0">+</span><span class="kw3">eax</span><span class="sy0">*</span>4<span class="br0">&#93;</span><span class="sy0">,</span><span class="kw3">esi</span>
<span class="co2">FF43</span>08 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">inc</span> <span class="kw5">dword</span> <span class="kw4">ptr</span> <span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">08</span><span class="br0">&#93;</span>
<span class="co2">33C9</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">xor</span> <span class="kw3">ecx</span><span class="sy0">,</span><span class="kw3">ecx</span>
<span class="co2">8BD6</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">edx</span><span class="sy0">,</span><span class="kw3">esi</span>
<span class="co2">8BC3</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="kw3">ebx</span>
<span class="co2">8B18</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">ebx</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">eax</span><span class="br0">&#93;</span>
<span class="co2">FF53</span>04 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">call</span> <span class="kw5">dword</span> <span class="kw4">ptr</span> <span class="br0">&#91;</span><span class="kw3">ebx</span><span class="sy0">+</span>$<span class="nu0">04</span><span class="br0">&#93;</span>
<span class="co2">8B04</span>24 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw3">eax</span><span class="sy0">,</span><span class="br0">&#91;</span><span class="kw3">esp</span><span class="br0">&#93;</span>
5A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> <span class="kw3">edx</span>
5E &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> <span class="kw3">esi</span>
5B &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> <span class="kw3">ebx</span>
C3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">ret</span></div>
</div>
</pre>
<p>You can eyeball this, or paste it into BeyondCompare if you&#8217;d like, but they&#8217;re identical.  The only difference is in the CALL line; the disassembly shows a different offset on the right, because the two collection classes are each calling their own versions of GrowCheck.  But the actual machine code on the left is identical, because the CALL instruction uses a relative jump and the routines are arranged the same way in relation to each other.</p>
<p>This being true, it would be really nice if the Delphi linker understood this (it would have to be done in the linker, because you could have different instantiations of the same basic generic class in different units) and kept track of all the instantiations of each generic class and compared them against each other, method by method. When it found routines that were identical like this, it should strip out the duplicates and adjust call references, VMT slots, etc accordingly.</p>
<p>This would probably slow the linker down by a certain amount, and if it&#8217;s too slow there should probably be a compiler switch to disable it so it doesn&#8217;t interfere with coding productivity, but it&#8217;s certainly something I&#8217;d like to be have available when I&#8217;m making a release build.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/299/wish-list-generics-collapsing/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>TThreadedQueue: interesting, but incomplete</title>
		<link>http://tech.turbu-rpg.com/250/tthreadedqueue-interesting-but-incomplete</link>
		<comments>http://tech.turbu-rpg.com/250/tthreadedqueue-interesting-but-incomplete#comments</comments>
		<pubDate>Sat, 20 Nov 2010 18:41:00 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Class Helpers]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Delphi XE]]></category>
		<category><![CDATA[Generics]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=250</guid>
		<description><![CDATA[I mentioned the new generic collection TThreadedQueue&#60;T&#62; in my First Look at Delphi XE. I decided to play around with it a little recently.  It&#8217;s useful for passing data between one thread that produces output and another that consumes it, keeping the two in step by blocking if the consumer tries to pop from the [...]]]></description>
			<content:encoded><![CDATA[<p>I mentioned the new generic collection TThreadedQueue&lt;T&gt; in my <a href="http://tech.turbu-rpg.com/181/first-look-at-delphi-xe">First Look at Delphi XE.</a> I decided to play around with it a little recently.  It&#8217;s useful for passing data between one thread that produces output and another that consumes it, keeping the two in step by blocking if the consumer tries to pop from the queue while it&#8217;s empty.</p>
<p>The first thread goes through and pushes data into the queue however it wants to.  The second has it easy; all it has to do is loop endlessly until the queue is shut down.  And we all know how to do that:</p>
<pre>
<div class="codesnip-container" >
<div class="delphi codesnip" style="font-family:monospace;"><span class="kw1">for</span> value <span class="kw1">in</span> queue <span class="kw1">do</span>
  process<span class="br0">&#40;</span>value<span class="br0">&#41;</span><span class="sy1">;</span></div>
</div>
</pre>
<p>Except that if you try to do that, the compiler will complain at you.  There&#8217;s no enumerator.  For some strange reason, out of all the collections in Generics.Collections, TThreadedQueue&lt;T&gt; alone does not descend from TEnumerable&lt;T&gt;.</p>
<p>Oh well.  It&#8217;s not all that hard to add an enumerator to a class that doesn&#8217;t have one.  Just use a class helper.</p>
<pre>
<div class="codesnip-container" >
<div class="delphi codesnip" style="font-family:monospace;">TThreadedQueueEnumerator&lt;T&gt; <span class="sy3">=</span> <span class="kw1">class</span>
&nbsp; <span class="kw1">private</span>
&nbsp; &nbsp; FQueue<span class="sy1">:</span> TThreadedQueue&lt;T&gt;<span class="sy1">;</span>
&nbsp; &nbsp; FCurrent<span class="sy1">:</span> T<span class="sy1">;</span>
&nbsp; &nbsp; <span class="kw1">function</span> GetCurrent<span class="sy1">:</span> T<span class="sy1">;</span>
&nbsp; <span class="kw1">public</span>
&nbsp; &nbsp; <span class="kw1">constructor</span> Create<span class="br0">&#40;</span>queue<span class="sy1">:</span> TThreadedQueue&lt;T&gt;<span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp; <span class="kw1">property</span> Current<span class="sy1">:</span> T <span class="kw3">read</span> GetCurrent<span class="sy1">;</span>
&nbsp; &nbsp; <span class="kw1">function</span> MoveNext<span class="sy1">:</span> <span class="kw4">Boolean</span><span class="sy1">;</span>
&nbsp; <span class="kw1">end</span><span class="sy1">;</span>

&nbsp; TThreadedQueueHelper&lt;T&gt; <span class="sy3">=</span> <span class="kw1">class</span> helper <span class="kw1">for</span> TThreadedQueue&lt;T&gt;
&nbsp; <span class="kw1">public</span>
&nbsp; &nbsp; <span class="kw1">function</span> GetEnumerator<span class="sy1">:</span> TThreadedQueueEnumerator&lt;T&gt;<span class="sy1">;</span>
&nbsp; <span class="kw1">end</span><span class="sy1">;</span>

<span class="kw1">implementation</span>

<span class="coMULTI">{ TThreadedQueueEnumerator&lt;T&gt; }</span>

<span class="kw1">constructor</span> TThreadedQueueEnumerator&lt;T&gt;<span class="sy1">.</span><span class="me1">Create</span><span class="br0">&#40;</span>queue<span class="sy1">:</span> TThreadedQueue&lt;T&gt;<span class="br0">&#41;</span><span class="sy1">;</span>
<span class="kw1">begin</span>
&nbsp; FQueue <span class="sy1">:</span><span class="sy3">=</span> queue<span class="sy1">;</span>
<span class="kw1">end</span><span class="sy1">;</span>

<span class="kw1">function</span> TThreadedQueueEnumerator&lt;T&gt;<span class="sy1">.</span><span class="me1">GetCurrent</span><span class="sy1">:</span> T<span class="sy1">;</span>
<span class="kw1">begin</span>
&nbsp; result<span class="sy1">:</span><span class="sy3">=</span> FCurrent<span class="sy1">;</span>
<span class="kw1">end</span><span class="sy1">;</span>

<span class="kw1">function</span> TThreadedQueueEnumerator&lt;T&gt;<span class="sy1">.</span><span class="me1">MoveNext</span><span class="sy1">:</span> <span class="kw4">Boolean</span><span class="sy1">;</span>
<span class="kw1">begin</span>
&nbsp; result <span class="sy1">:</span><span class="sy3">=</span> FQueue<span class="sy1">.</span><span class="me1">PopItem</span><span class="br0">&#40;</span>FCurrent<span class="br0">&#41;</span> <span class="sy3">=</span> wrSignaled<span class="sy1">;</span>
<span class="kw1">end</span><span class="sy1">;</span>

<span class="coMULTI">{ TThreadedQueueHelper&lt;T&gt; }</span>

<span class="kw1">function</span> TThreadedQueueHelper&lt;T&gt;<span class="sy1">.</span><span class="me1">GetEnumerator</span><span class="sy1">:</span> TThreadedQueueEnumerator&lt;T&gt;<span class="sy1">;</span>
<span class="kw1">begin</span>
&nbsp; result <span class="sy1">:</span><span class="sy3">=</span> TThreadedQueueEnumerator<span class="sy1">.</span><span class="me1">Create</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span><span class="sy1">;</span>
<span class="kw1">end</span><span class="sy1">;</span></div>
</div>
</pre>
<p>Well, that was easy.  That&#8217;s probably the simplest enumerator I&#8217;ve ever written, because of the way the queue&#8217;s design makes it easy to implement MoveNext.  Except&#8230; that doesn&#8217;t compile either.  Apparently you can&#8217;t put generic type parameters on a class helper, which means that as far as I can tell, you can&#8217;t apply a class helper to a generic class at all.</p>
<p>I suppose I could subclass it and add the enumerator that way, but TEnumerableThreadedQueue&lt;T&gt; is a bit of a bulky name, don&#8217;t you think?  I have to wonder why the enumerator was left off of this collection, though, especially since the standard enumerator pattern is basically the only reasonable way to use a class like this&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/250/tthreadedqueue-interesting-but-incomplete/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>First look at Delphi XE</title>
		<link>http://tech.turbu-rpg.com/181/first-look-at-delphi-xe</link>
		<comments>http://tech.turbu-rpg.com/181/first-look-at-delphi-xe#comments</comments>
		<pubDate>Wed, 01 Sep 2010 05:41:01 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Delphi XE]]></category>
		<category><![CDATA[Generics]]></category>
		<category><![CDATA[RTTI]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=181</guid>
		<description><![CDATA[This week&#8217;s just getting started, and it&#8217;s already had more than enough awesomeness to pack into a typical month.  The new version of Delphi came out yesterday.  Metroid: Other M and The Way of Kings, a new Brandon Sanderson book, were both released today.  (I have a feeling I&#8217;m going to be more distracted than [...]]]></description>
			<content:encoded><![CDATA[<p>This week&#8217;s just getting started, and it&#8217;s already had more than enough awesomeness to pack into a typical month.  The new version of Delphi came out yesterday.  <em>Metroid: Other M</em> and <em>The Way of Kings,</em> a new <a href="http://tvtropes.org/pmwiki/pmwiki.php/Main/BrandonSanderson">Brandon Sanderson</a> book, were both released today.  (I have a feeling I&#8217;m going to be more distracted than usual for a while&#8230;) But as awesome as Metroid games and anything by Sanderson tend to be, (if you&#8217;re into fantasy <em>at all</em>, check out <a href="http://www.amazon.com/Elantris-Brandon-Sanderson/dp/0765350378/">Elantris</a> and <a href="http://www.amazon.com/Mistborn-Trilogy-Boxed-Brandon-Sanderson/dp/076536543X">Mistborn</a> and prepare to be blown away,) this is a programming blog, and I&#8217;m supposed to be talking about Delphi.  So here&#8217;s the good, the bad, and the annoying about my first impressions with Delphi XE.</p>
<p><span id="more-181"></span>The first thing I knew about the release was when I received my SA email yesterday afternoon, as opposed to having to wait a few days or even weeks to get my upgrade as has happened in previous years.  Big improvement there, and I hope Embarcadero keeps it up for subsequent releases. <strong>Good.</strong></p>
<p>No OSX support, which we all thought was going to be in this release up until a few weeks ago. <strong>Bad.</strong> But it&#8217;s not there because the people at Embarcadero preferred to focus on quality and not release something that wasn&#8217;t ready. <strong>Good.</strong> No one wants to see (or pay for) another D8.</p>
<p>So I open it up and start browsing through some code.  My settings from D2010 didn&#8217;t get migrated forward. <strong>Annoying.</strong> There really should be some way to import them as part of the installation process.</p>
<p>ErrorInsight is the same old same old, with false positives all over the place because it can&#8217;t find basic standard library units. <strong>Annoying.</strong> But at least it doesn&#8217;t choke on methods of objects from a generic list anymore. <strong>Good.</strong></p>
<p>Speaking of Generics, huge improvement here.  I was able to go through my codebase and remove all the annoying workarounds for generics-related glitches, and it compiles and runs properly now! <strong>Good.</strong></p>
<p>When it&#8217;s time to debug, I immediately noticed a few improvements.  We finally, finally, after all these years, have debug DCPs available for the standard libraries.  (For those not familiar with them, DCPs are to Delphi packages as DCUs are to units.)  That means that people like me who build stuff with packages are able to trace into the RTL when debugging.  <strong>Good.</strong></p>
<p>Also, something that always drove me up the wall about the debugger has been fixed.  When you put the cursor in an expression and hit CTRL-F7, it pops up the Evaluate/Modify window and evaluates whatever you had the cursor on.  But if you moved the cursor and hit CTRL-F7 again without closing the Evaluate/Modify window, it would focus the Evaluate/Modify window, but it wouldn&#8217;t evaluate the new expression you had selected.  You&#8217;d have to close the window and hit CTRL-F7 again to get a new evaluation.  (Or copy/paste or type it in, of course.)  That always bugged me, but it&#8217;s been fixed in XE.  <strong>Good.</strong></p>
<p>And while we&#8217;re on the subject of Evaluate/Modify, you can now select more than whatever the limit used to be (80 characters?) and have your entire selection copied when you hit CTRL-F7. <strong>Good.</strong></p>
<p>But while poking around in there, I found a new way to crash the IDE.  Try to evaluate a call that will open a form, and it locks up Evaluate/Modify.  Then hit CTRL-F2 to kill the debugger, and it brings the whole program down. <strong>Bad.</strong> (Not sure if this was in earlier versions, though. I&#8217;ve never run across it before.)</p>
<p>Oh, there&#8217;s a new regular expression library in the RTL.  Some people will probably find this a good thing.  I personally see it as <strong>Annoying.</strong> Delphi code is supposed to be easy to read.  That&#8217;s an explicit design goal going all the way back to Wirth.  But PCREs are anything but, and having it right there in the standard library will just encourage people to use them in code that I might end up having to debug some day.</p>
<p>In addition to Generics bugs getting cleaned up, the Generics.Defaults and Generics.Collections units got a bit of polish.  There were some minor tweaks to speed up various low-level comparison functions in Generics.Defaults.  Over in Generics.Collections, all the collections have gained a ToArray method, TStack&lt;T&gt; and TQueue&lt;T&gt; gained a Capacity, and there&#8217;s a new TThreadedQueue&lt;T&gt; class that looks a lot like the <a href="http://17slon.com/blogs/gabr/2010/01/three-steps-to-blocking-collection-1.html">Blocking Collection</a> that Primoz Gabrijelcic set up for OmniThreadLibrary, only without all the Omni stuff.  These new features look <strong>Good.</strong></p>
<p>The Math unit has been given overloads for Single, Double and Extended precision versions of just about all its calculation routines, which is <strong>Good</strong> because there&#8217;s no more implicit conversions to introduce rounding errors.  However, I had this bite me when compiling some code at work.  Someone was passing an array of integers to Math.Sum, which worked before, but now the compiler gave an ambiguous overload error for that. <strong>Annoying,</strong> but not too hard to fix, since there&#8217;s a SumInt function right after Sum.  Not sure why the original author of this code didn&#8217;t use it in the first place.  Oh well&#8230;</p>
<p>In RTTI.pas, there&#8217;s a new class called TMethodImplementation.  You create it and give it data that describes the signature of a method, then pass it an anonymous method that takes an array of TValues and returns a TValue, and it creates a little thunk of machine code that builds a function with the correct signature that invokes your anonymous method.  Very cool, lots of potential&#8230; except that you can&#8217;t use it.  The constructor&#8217;s private, and there&#8217;s a public constructor that raises an exception, so you can&#8217;t get at it via TObject.Create.  It&#8217;s apparently for internal use only.  <strong>Annoying.</strong> I asked Allen Bauer about this, and he said that it&#8217;s because they weren&#8217;t sure they had the final form of the class worked out yet, and they didn&#8217;t want to make it publicly available yet in a form that they&#8217;d end up having to preserve and support forever afterwards.</p>
<p>There&#8217;s also a new class called TVirtualMethodInterceptor that <em>is </em>publicly available, and uses TMethodImplementation internally to allow you to replace virtual methods on a class.  I&#8217;m a bit curious as to what this is useful for, but apparently the team thought it was good for something, because a lot of work went into setting it up. <strong>Good?</strong></p>
<p>Oh, and apparently certain aspects of the compiler have slowed down.  Most things will compile about the same speed or even a little faster, but for really large projects (millions of lines) with complex interdependencies between units, you&#8217;ll notice some slowdown, and it&#8217;ll apparently get worse the larger your project is.  I timed it at work, on a project of about 3.5 million lines of code.  It builds in about 2 minutes on D2010, closer to 3 minutes on XE.  <strong>Bad,</strong> but still a heck of a lot better than the C family could do.  And apparently it has something to do with making Generics work right, so I can tolerate that.  Hopefully they&#8217;ll find some way to regain some of that lost speed in updates, though.</p>
<p>Oh, and there are little {$IFDEF POSIX} and {$IFDEF MACOS} tags scattered throughout the RTL and VCL, even more than there were in Delphi 2010.  This is <strong>Good</strong> if you&#8217;re looking forward to OSX or Linux cross-platform development in the next release(s).  I haven&#8217;t seen any 64-bit ifdefs, but that could be because it doesn&#8217;t require much change at the Pascal level, the way a completely different OS platform does. (UPDATE: According to PhiS, there&#8217;s a lot of {$IFDEF CPUX64} tags in System.pas.  I was poking around the libraries with BeyondCompare last night but I didn&#8217;t bother to look in there because I knew that, with all the cross-platform stuff and all the ASM they&#8217;ve got in System.pas, the diff view would be a big, confusing mess no matter what.)</p>
<p>Well, it&#8217;s getting late and I haven&#8217;t had time to dig through too much of the new stuff yet, (and with a new 1000-page novel and a new video game, it might be a while,) but overall this is looking like a pretty good release.  Not a huge leap forward like the last two were, but a lot of polish and incremental improvements.  I think this is going to be a pretty good release overall.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/181/first-look-at-delphi-xe/feed</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Generics and the Covariance Problem</title>
		<link>http://tech.turbu-rpg.com/149/generics-and-the-covariance-problem</link>
		<comments>http://tech.turbu-rpg.com/149/generics-and-the-covariance-problem#comments</comments>
		<pubDate>Tue, 22 Jun 2010 20:52:37 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Generics]]></category>
		<category><![CDATA[reference]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=149</guid>
		<description><![CDATA[Since some version of this question keeps showing up on StackOverflow, and the answer&#8217;s always basically the same, I figured I may as well write up a post on here that people can link to.  Here&#8217;s the question, in simplified form: &#8220;Why can&#8217;t I pass a TList&#60;TMyDerivedObject&#62; to a function that&#8217;s expecting a TList&#60;TMyBaseObject&#62;?  You [...]]]></description>
			<content:encoded><![CDATA[<p>Since some version of this question keeps showing up on StackOverflow, and the answer&#8217;s always basically the same, I figured I may as well write up a post on here that people can link to.  Here&#8217;s the question, in simplified form:</p>
<p>&#8220;Why can&#8217;t I pass a TList&lt;TMyDerivedObject&gt; to a function that&#8217;s expecting a TList&lt;TMyBaseObject&gt;?  You can pass a TMyDerivedObject to a parameter expecting TMyBaseObject, so why doesn&#8217;t it work for lists?&#8221;</p>
<p><span id="more-149"></span></p>
<p>It really looks like it ought to be that simple, but unfortunately it&#8217;s not.  Trying to do this gets into a tricky issue in type theory known as <em><a href="http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29">covariance and contravariance</a>,</em> which is a formal way of describing the relationship between different types when one inherits from another.</p>
<p>It&#8217;s important to remember that object types don&#8217;t really exist at the binary level.  They&#8217;re an abstraction that makes it easier for us to work with them, but when you get down to it, all that&#8217;s there is a sequence of bytes.  As a strongly-typed language, it&#8217;s up to the Delphi compiler to make sure that, when you have a TMyDerivedObject, it doesn&#8217;t get replaced with a TMyIncompatibleObject that will cause things to crash or corrupt your data when you try to use it.  This is why you&#8217;re not allowed to pass descendant classes to a <strong>var</strong> parameter, for example:  because in the function using the <strong>var</strong> parameter, you&#8217;re allowed to replace the object with something else, and if the compiler can&#8217;t guarantee that the replacement will be of a compatible type, it prevents you from passing it in order to preserve type safety.</p>
<p>This is basically the same problem you get when dealing with generic lists.  Let&#8217;s say you have a TList&lt;TMyDerivedObject&gt; and you pass it to a function that expects a TList&lt;TMyBaseObject&gt;.  As long as all it does is reads the items in the list, you&#8217;re just fine.  But if this function calls .Add on the list and adds a TMyIncompatibleObject, (which also descends from TMyBaseObject, and so is perfectly legal in this context,) then you&#8217;ve violated type safety.  You have a list that&#8217;s supposed to only contain one type of object, and now there&#8217;s something incompatible inside.  And since this is done by calling a method on the list object and not by directly assigning one variable to another, the compiler can&#8217;t check to make sure you&#8217;re not doing something dangerous like this, so it forbids the entire concept in order to preserve type safety.</p>
<p>There&#8217;s a solution to this problem.  You can extend the language syntax a little so that the compiler does have a way to check this.  You have to mark the methods on the list so that the compiler knows that it&#8217;s safe for them to receive an object that descends from, or is an ancestor of, the specified generic type.  For example, you could mark TList&lt;T&gt;.Add with a hint that it&#8217;s OK to add descendants of the T type, but not ancestors.  Then the compiler uses this to determine more relaxed type safety rules that allow you to pass around different generic types without the danger of mixing incompatible types together.</p>
<p>The latest version of Prism supports this, but the Delphi team hasn&#8217;t implemented it yet.  I haven&#8217;t heard anything to indicate that they&#8217;re working on it for Delphi 2011 either.  Hopefully it they&#8217;ll find some way to implement it for Delphi 2012.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/149/generics-and-the-covariance-problem/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>How to break the D2010 compiler</title>
		<link>http://tech.turbu-rpg.com/90/how-to-break-the-d2010-compiler</link>
		<comments>http://tech.turbu-rpg.com/90/how-to-break-the-d2010-compiler#comments</comments>
		<pubDate>Tue, 09 Mar 2010 19:41:34 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Dark Corners]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Generics]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=90</guid>
		<description><![CDATA[I really loved when Delphi 2009 came out, how it fixed so many ugly problems in the Delphi IDE.  The stability issues and memory leaks that plagued D2006 and D2007 were greatly reduced.  And it just got better in D2010. The tradeoff, though, seems to have been compiler stability.  Trying to do anything with Generics [...]]]></description>
			<content:encoded><![CDATA[<p>I really loved when Delphi 2009 came out, how it fixed so many ugly problems in the Delphi IDE.  The stability issues and memory leaks that plagued D2006 and D2007 were greatly reduced.  And it just got better in D2010.</p>
<p>The tradeoff, though, seems to have been <em>compiler</em> stability.  Trying to do anything with Generics in D2009 before Update 3 came out was a nightmare, and even after, (and even in D2010,) there were still plenty of dark corners where you can end up with an Internal Compiler Error or linker error on something that, syntactically speaking at least, is perfectly cromulent Object Pascal.</p>
<p><span id="more-90"></span>I think I ran into the darkest corner of all this morning, or at least the darkest one that&#8217;s been found yet.  I found something that not only won&#8217;t compile, but will either destabilize or completely crash the IDE if you try to compile it.</p>
<p>I was trying to build a specialized tree class.  Trees are pretty familiar to anyone who&#8217;s taken a Data Structures class:  Each TreeNode contains a Value and pointers to two or more other TreeNodes.  There&#8217;s an excellent implementation of the standard binary tree concept in <a href="http://code.google.com/p/delphilhlplib/">DeHL</a>, for example.  This works really well if you&#8217;re trying to build a standard binary tree, but when you want a hierarchical tree, (like the way the VCL&#8217;s TTreeView organizes information,) the standard binary tree concept doesn&#8217;t work so well.</p>
<p>I came across a situation while building the TURBU editor where I had a list of objects with an ID property and a Parent property, where both are integers, and I needed to come up with a list of all objects whose Parent value was equal to the ID value of a given object.  In other words, all immediate children of a certain node.</p>
<p>Obtaining all descendants of a binary tree node is trivial if you understand recursion.  But that&#8217;s not what I needed; I needed all immediate children, but not their children.  So a different kind of tree is needed, one composed of TLists of nodes instead of binary subtrees of nodes.  So that&#8217;s what I wrote.  Each node contains a value, a pointer to the list it&#8217;s in, and a pointer  to the list containing its children, and each list is a list of nodes, plus a pointer to its parent node.  It ended up looking like this:</p>
<pre>
<div class="codesnip-container" >
<div class="delphi codesnip" style="font-family:monospace;"><span class="kw1">unit</span> hierarchy_tree<span class="sy1">;</span>

<span class="kw1">interface</span>
<span class="kw1">uses</span>
&nbsp; &nbsp;SysUtils<span class="sy1">,</span> generics<span class="sy1">.</span><span class="me1">collections</span><span class="sy1">;</span>

<span class="kw1">type</span>
&nbsp; &nbsp;THierarchyTreeList&lt;T<span class="sy1">:</span> class&gt; <span class="sy3">=</span> <span class="kw1">class</span><span class="sy1">;</span>

&nbsp; &nbsp;THierarchyTreeNode&lt;T<span class="sy1">:</span> class&gt; <span class="sy3">=</span> <span class="kw1">class</span>
&nbsp; &nbsp;<span class="kw1">private</span> <span class="kw1">type</span>

&nbsp; &nbsp; &nbsp; TEnumerator <span class="sy3">=</span> <span class="kw1">class</span><span class="br0">&#40;</span>TEnumerator&lt;T&gt;<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">private</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FTopNode<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FIndex<span class="sy1">:</span> <span class="kw4">integer</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FNext<span class="sy1">:</span> TEnumerator<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FTopRead<span class="sy1">:</span> <span class="kw4">boolean</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">protected</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">function</span> DoGetCurrent<span class="sy1">:</span> T<span class="sy1">;</span> <span class="kw1">override</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">function</span> DoMoveNext<span class="sy1">:</span> <span class="kw4">Boolean</span><span class="sy1">;</span> <span class="kw1">override</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">public</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">constructor</span> Create<span class="br0">&#40;</span>value<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">function</span> GetCurrent<span class="sy1">:</span> T<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">function</span> MoveNext<span class="sy1">:</span> <span class="kw4">boolean</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">property</span> Current<span class="sy1">:</span> T <span class="kw3">read</span> GetCurrent<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">end</span><span class="sy1">;</span>

&nbsp; &nbsp; &nbsp; TNodeList <span class="sy3">=</span> THierarchyTreeList&lt;THierarchyTreeNode&lt;T&gt;&gt;<span class="sy1">;</span>

&nbsp; &nbsp;<span class="kw1">private</span>
&nbsp; &nbsp; &nbsp; FData<span class="sy1">:</span> T<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; FRight<span class="sy1">:</span> TNodeList<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; FList<span class="sy1">:</span> TNodeList<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">function</span> GetParent<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">function</span> GetLevel<span class="sy1">:</span> <span class="kw4">integer</span><span class="sy1">;</span>
&nbsp; &nbsp;<span class="kw1">public</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">constructor</span> Create<span class="br0">&#40;</span>value<span class="sy1">:</span> T<span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">destructor</span> Destroy<span class="sy1">;</span> <span class="kw1">override</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">procedure</span> Add<span class="br0">&#40;</span>node<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="br0">&#41;</span><span class="sy1">;</span> <span class="kw1">overload</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">procedure</span> Add<span class="br0">&#40;</span>value<span class="sy1">:</span> T<span class="br0">&#41;</span><span class="sy1">;</span> <span class="kw1">overload</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">function</span> GetEnumerator<span class="sy1">:</span> TEnumerator<span class="sy1">;</span>

&nbsp; &nbsp; &nbsp; <span class="kw1">property</span> List<span class="sy1">:</span> TNodeList <span class="kw3">read</span> FList<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">property</span> Right<span class="sy1">:</span> TNodeList <span class="kw3">read</span> FRight<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">property</span> Parent<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt; <span class="kw3">read</span> GetParent<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">property</span> Level<span class="sy1">:</span> <span class="kw4">integer</span> <span class="kw3">read</span> GetLevel<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">property</span> Data<span class="sy1">:</span> T <span class="kw3">read</span> FData <span class="kw3">write</span> FData<span class="sy1">;</span>
&nbsp; &nbsp;<span class="kw1">end</span><span class="sy1">;</span>

&nbsp; &nbsp;THierarchyTreeList&lt;T<span class="sy1">:</span> class&gt; <span class="sy3">=</span> <span class="kw1">class</span><span class="br0">&#40;</span>TObjectList&lt;THierarchyTreeNode&lt;T&gt;&gt;<span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="kw1">private</span>
&nbsp; &nbsp; &nbsp; FParent<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; FLevel<span class="sy1">:</span> <span class="kw4">integer</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">procedure</span> SetParent<span class="br0">&#40;</span>Value<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp;<span class="kw1">public</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">constructor</span> Create<span class="br0">&#40;</span>parent<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">function</span> Add<span class="br0">&#40;</span>value<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt;<span class="br0">&#41;</span><span class="sy1">:</span> <span class="kw4">integer</span><span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">property</span> Parent<span class="sy1">:</span> THierarchyTreeNode&lt;T&gt; <span class="kw3">read</span> FParent <span class="kw3">write</span> SetParent<span class="sy1">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">property</span> Level<span class="sy1">:</span> <span class="kw4">integer</span> <span class="kw3">read</span> FLevel<span class="sy1">;</span>
&nbsp; &nbsp;<span class="kw1">end</span><span class="sy1">;</span>

<span class="kw1">implementation</span>

<span class="coMULTI">{ No implementation provided. &nbsp;Compiler will break before reaching this
point anyway. }</span>

<span class="kw1">end</span><span class="sy1">.</span></div>
</div>
</pre>
<p>You can try to compile this if you want, but make sure to save any work before you try.  Turns out this will break the compiler.  The compiler will try to process this, get stuck for about 30 seconds, all the while sucking up memory like there&#8217;s no tomorrow, until it hits 1.5 GB according to Task Manager, and then break.  It may crash, or it may simply become unstable.  If you&#8217;re really lucky, you&#8217;ll get an Out Of Memory error so at least you have some idea what&#8217;s going on.</p>
<p>After sharing this problem with a few other coders, I&#8217;ve got some idea what&#8217;s going on.  The node uses the list in its definition, and the uses the node as its generic parameter.  Apparently the compiler is trying to resolve one of these generics immediately, instead of waiting for instantiaion when a value of T can be provided, and getting stuck in an infinite loop, even though the definition is not infinitely recursive.</p>
<p>I&#8217;ve submitted <a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=82838">a bug report about this to QC </a>. Thanks to <a href="http://stackoverflow.com/users/80565/moritz-beutel">Moritz Beutel</a> and <a href="http://delphiaddict.blogspot.com/">Stephen Kamradt</a> for the insights as to what was going on!</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/90/how-to-break-the-d2010-compiler/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>

