<?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; Delphi</title>
	<atom:link href="http://tech.turbu-rpg.com/tag/delphi/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>Wed, 01 Sep 2010 21:11:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<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>18</slash:comments>
		</item>
		<item>
		<title>The insanities of roadmap publishing</title>
		<link>http://tech.turbu-rpg.com/176/the-insanities-of-roadmap-publishing</link>
		<comments>http://tech.turbu-rpg.com/176/the-insanities-of-roadmap-publishing#comments</comments>
		<pubDate>Wed, 25 Aug 2010 20:55:30 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[DelphiLive!]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=176</guid>
		<description><![CDATA[Last night at DelphiLive they had a &#8220;Meet the team&#8221; event in one of the halls, where most of the RAD Studio development team was present and the attendees could hang out and chat with them.  While I was there, I talked with Mike Rozlog a bit.  He&#8217;d seen some of the critical things I [...]]]></description>
			<content:encoded><![CDATA[<p>Last night at DelphiLive they had a &#8220;Meet the team&#8221; event in one of the halls, where most of the RAD Studio development team was present and the attendees could hang out and chat with them.  While I was there, I talked with Mike Rozlog a bit.  He&#8217;d seen some of the critical things I wrote on here and on the forums about the roadmap, and he explained to me a bit about how the process of making a roadmap works.  One thing to keep in mind is that he told me it&#8217;s like this everywhere  he&#8217;s worked.  What I&#8217;m about to describe is apparently not a symptom of  dysfunctional corporate culture at Embarcadero; more like dysfunctional corporate culture in general.<span id="more-176"></span>Apparently, due to really complicated business-related reasons that I didn&#8217;t understand well enough to explain here, producing an official roadmap for a commercial product almost invariably has to be signed off on by anyone and everyone with any degree of decision-making authority.  This might be a bit inaccurate, but the impression I got is that it&#8217;s kinda like getting Congress to pass a law, except that each individual Congressman has not only a vote, but veto power as well!</p>
<p>They&#8217;d have something almost ready, and then person A says &#8220;No, we can&#8217;t do this, we shouldn&#8217;t have X on there, it needs to be Y instead,&#8221; so they take X off and replace it with Y.  Then person B looks at it and says, &#8220;hey, what happened to X? That was <em>critical</em>!&#8221;  So Mike has to explain that it was removed because of person A, and get those two in a room together where they can discuss it and work out a compromise, and then they update the roadmap so it says XY.  And then of course, person C comes by and says, &#8220;hey, what&#8217;s with all this X stuff in there? I thought we took it out, because we won&#8217;t be able to get it implemented on this schedule!&#8221; And it&#8217;s back to square one.</p>
<p>Repeat a few dozen times, over a period of a few months, until finally they reach the Ultimate Compromise that everyone can bring themselves to agree upon, and then they finally publish the new version.  That&#8217;s the easy part.  Once everyone&#8217;s signed off on it, it takes about five minutes to get it posted to embarcadero.com.  He said that he&#8217;d have liked to publish the updated roadmap before the XE sneak previews started, but that just wouldn&#8217;t have worked on the timetable they had.  It was a real eye-opener, talking with him about the process.  It makes the roadmaps being the way they are a bit more understandable.</p>
<p>Mike also mentioned that a lot of people, including himself, don&#8217;t like the &#8220;PowerPoint slide&#8221; format that the last few roadmaps have been done in, and the next one will probably be done a different way.  Of course, working out what the new format will look like will be another long round of negotiations and compromises&#8230;</p>
<p>Again, apparently this is all completely normal for trying to publish a roadmap for a commercial product.  What do you guys think?  Has anyone out there been in a similar situation?  Are roadmaps always that messy, or has Mike just had a run of bad luck?</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/176/the-insanities-of-roadmap-publishing/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>New tools for Delphi XE</title>
		<link>http://tech.turbu-rpg.com/167/new-tools-for-delphi-xe</link>
		<comments>http://tech.turbu-rpg.com/167/new-tools-for-delphi-xe#comments</comments>
		<pubDate>Tue, 17 Aug 2010 18:39:33 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=167</guid>
		<description><![CDATA[The second sneak preview is out now.  It&#8217;s quite a bit more interesting than the first one.  FinalBuilder being added to the package will make it a lot easier for me to get builds set up for the TURBU project.  Right now I have to do it all by hand.  So far I haven&#8217;t missed [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.embarcadero.com/rad-studio-xe-preview">second sneak preview</a> is out now.  It&#8217;s quite a bit more interesting than the first one.  FinalBuilder being added to the package will make it a lot easier for me to get builds set up for the TURBU project.  Right now I have to do it all by hand.  So far I haven&#8217;t missed a step and ended up releasing it, but if there&#8217;s a way to reduce the chance of that happening in the future I&#8217;d definitely appreciate it.  I just wonder if it&#8217;ll be in all editions or just the higher-level SKUs.</p>
<p>Then they mentioned AQTime, which looked interesting but IMO brings up more questions than it answers.  For example, &#8220;Since this is the standard edition, not all of the profilers are enabled.&#8221; (9:13)  But I don&#8217;t see any of the profilers on that list grayed out.  And again, will this be in all editions, or just the high-level ones?</p>
<p>Also, will it come with an extension to the Open Tools API to allow other profilers to be integrated?  AQTime has some great features, but its core feature, performance profiling, uses instrumenting that slows your app down horribly, which makes it unsuitable for a lot of uses.  I prefer Sampling Profiler, which gives a good picture of what you&#8217;re spending your time doing without instrumenting your program.  It doesn&#8217;t provide the perfect counting accuracy that instrumenting does, but most of the time you don&#8217;t actually need that anyway in order to track down performance problems.  If there was a way to integrate Sampling Profiler into Delphi, it would make a good compliment to AQTime&#8217;s other profilers.</p>
<p>As for CodeSite, I don&#8217;t have too much to say about that, because I don&#8217;t know enough about how it works to discuss it very well.  Logging&#8217;s definitely useful, but usually in different ways than what they were demonstrating on the video.  For example, if CodeSite can only output to that popup window, it&#8217;s worthless IMO.  But if it can write to a file, or better yet if it allows you to create and register custom outputs of some kind, that would be a big help.</p>
<p>The one thing I&#8217;m a bit worried about is price.  Delphi&#8217;s got three general problems, which need to be resolved independently.</p>
<ol>
<li>Missing features.  No 64-bit, no cross-platform, no data binding, no LINQ, etc.</li>
<li>Bugs and quality issues.  Glitchy generics, *Insight, the helpfiles, etc.</li>
<li>Price.  No explanation needed</li>
</ol>
<p>Delphi 2011&#8242;s main point was supposed to be addressing a missing feature.  That ended up not happening, as the team members have been explaining, because they don&#8217;t have enough time to get it working at a good quality level.  That&#8217;s definitely a praiseworthy attitude, but I&#8217;m a bit worried at seeing all these expensive third-party tools being suddenly announced as part of the product.  They don&#8217;t actually do anything to solve the three main problems facing Delphi, and I&#8217;m a bit worried that they&#8217;ll end up taking the price even higher.</p>
<p>They&#8217;ve mentioned their commitment to quality several times, and specifically that they&#8217;ve done a lot of work to fix the generics issues.  That&#8217;s great, and if they&#8217;ve allocated some resources to getting a Error Insight and Code Completion working properly that&#8217;ll be even better.  But even so, not having the main missing feature we were expecting would be delivered is going to do a lot to reduce the perceived quality of the release, even if the objective quality has gone up quite a bit since D2010.  Quality improvements are generally expected to be part of an update, not a new release.  (The &#8220;I paid good money for this with the expectation that the promised features would actually work&#8221; argument.)</p>
<p>I really hope I&#8217;m interpreting this wrong, but what it looks like to me is that in order to avoid the new version being perceived as &#8220;just a bugfix release&#8221; that isn&#8217;t worth the price, Embarcadero decided to bundle a bunch of expensive tools to make it appear to be more worth the cost.  If that&#8217;s what they&#8217;re doing, there are two ways to do it, and both will hurt them.  Either the price stays about the same as it was for D2010, but they&#8217;re paying a share of it to the owners of AQTime, FinalBuilder, etc, so they lose a lot of revenue, or they pass that cost along to us, the price goes up, (without delivering the anticipated new feature,) and a lot of people end up not wanting to buy it at that price, so they lose a lot of revenue.</p>
<p>What I would prefer, and what I would do if it was my product, is to negotiate some sort of deal with the creators of these other products where people who buy Delphi XE can pick them up at a discount, and then sell the actual Delphi license to us at a reduced price.  That would help improve sales, or at the very least help stem the loss of sales resulting from not having cross-platform available, and no one ends up paying for add-on products they don&#8217;t need.  (And not everyone will need them.  Where I work we&#8217;ve got a bunch of developers and one build machine.  If we all got a copy of FinalBuilder&#8230; what would we do with it?)</p>
<p>I really hope I&#8217;m wrong about this, but this is what it looks like Embarcadero is doing.  I just wish they wouldn&#8217;t, since I don&#8217;t think it will actually be good for Delphi users, or for Delphi itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/167/new-tools-for-delphi-xe/feed</wfw:commentRss>
		<slash:comments>9</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>Inheritance baggage</title>
		<link>http://tech.turbu-rpg.com/147/inheritance-baggage</link>
		<comments>http://tech.turbu-rpg.com/147/inheritance-baggage#comments</comments>
		<pubDate>Mon, 21 Jun 2010 15:03:25 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Dark Corners]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Optimization]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=147</guid>
		<description><![CDATA[A couple posts ago, I mentioned that I&#8217;ve been working with code generation lately.  This is for a part of the TURBU project.  An RPG relies pretty heavily on scripting, and RPG Maker, the system I created TURBU to replace, has a fairly extensive, if limited, scripting system.  The limitations were one of the things [...]]]></description>
			<content:encoded><![CDATA[<p>A couple posts ago, I mentioned that I&#8217;ve been working with code generation lately.  This is for a part of the TURBU project.  An RPG relies pretty heavily on scripting, and RPG Maker, the system I created TURBU to replace, has a fairly extensive, if limited, scripting system.  The limitations were one of the things that made me say &#8220;I could do better than this,&#8221; in fact:  No functions, no local variables, callable procedures exist but parameters don&#8217;t, so any &#8220;passing&#8221; has to be done in global variables, only two data types: integer and boolean, no event handlers, minimal looping support, etc.</p>
<p><span id="more-147"></span></p>
<p>The upside of all this, though, is a very simple scripting system that doesn&#8217;t look much like a programming language, with a simple interface that almost anyone can pick up.  I wanted to keep that simplicity as much as possible, while adding the full flexibility and power of a real scripting language.  So I dreamed up EventBuilder, a set of objects which represent a high-level scripting interface and can also express themselves as <a href="http://www.remobjects.com/ps.aspx">PascalScript</a> code.</p>
<p>I needed some way to create EventBuilder objects that could form a hierarchical tree that can represent blocks of code.  They needed to be easily serializable to some human-readable format so people can copy and paste blocks of EventBuilder script in order to share scripts, ask for help with debugging, etc.  And it needed to be ready quickly, since I want to be able to present as much of this as possible at Delphi Live! in August.</p>
<p>So is there any pre-existing system that supports hierarchical trees of objects and easy serialization to a simple text-based format?  The answer should be obvious to any experienced Delphi user:  descend from TComponent and use its built-in serialization to &#8220;DFM format.&#8221;  I tried that and, once I&#8217;d figured out how to handle a few quirks related to object ownership, it worked great!  All the infrastructure was there for me, tested and tried and proven over the last 15 years, and I could focus on the actual Event Builder logic.  It&#8217;s taken me about a month to get the system to a workable state, and now it&#8217;s more or less all ready.</p>
<p>Then I tried running a very, very large RPG Maker project through my project importer, and it took a long time on converting the global script block.  That&#8217;s sort of to be expected, since there are almost 2000 event scripts in there, but even so it felt like it was taking far too long for the amount of work involved.  I looked at my code and couldn&#8217;t find any obvious issues, so I ran it through <a href="http://delphitools.info/samplingprofiler/">Sampling Profiler</a>.</p>
<p>It&#8217;s a good thing I did, too.  It found a very clear bottleneck in a place I&#8217;d have never thought to look.  Apparently I was spending 77% of my time in TComponent.Notification.  And why would I have never thought to look there?  Because I&#8217;ve never heard of it!  But apparently every time I added a component, it would recursively call this on the entire subtree, turning what ought to have been a O(n) conversion into O(n^2).</p>
<p>With a bit of research, it turns out that TComponent.Notification is for dealing with linked components.  For example, when you link a TDataset to a TDatasource, it needs a notification mechanism so it can clean up references if you free one of them.  Since EventBuilder doesn&#8217;t use linked components, I didn&#8217;t really need this functionality.  Good thing TComponent.Notification is virtual!  I overrode it with a blank method, and suddenly the conversion time dropped from about 12 seconds to about 3 seconds, and everything&#8217;s running smoothly again.</p>
<p>Moral of the story?  Be careful that you understand what you&#8217;re inheriting from, otherwise you might end up with <a href="http://www.snopes.com/humor/nonsense/kangaroo.asp">killer kangaroos</a> or other unwanted features.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/147/inheritance-baggage/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>AnyDAC: First impressions</title>
		<link>http://tech.turbu-rpg.com/144/anydac-first-impressions</link>
		<comments>http://tech.turbu-rpg.com/144/anydac-first-impressions#comments</comments>
		<pubDate>Fri, 04 Jun 2010 21:55:40 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[AnyDAC]]></category>
		<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=144</guid>
		<description><![CDATA[Over the last few days, when I&#8217;ve had some free time available, I&#8217;ve been working with AnyDAC&#8217;s TADMemTable, which Dimitry Arafiev, the author, pitched to me as a replacement for and an improvement upon TClientDataset. I&#8217;d like to report on how smoothly everything went and how well it works, and spend some time on my [...]]]></description>
			<content:encoded><![CDATA[<p>Over the last few days, when I&#8217;ve had some free time available, I&#8217;ve been working with AnyDAC&#8217;s TADMemTable, which Dimitry Arafiev, the author, pitched to me as a replacement for and an improvement upon TClientDataset.  I&#8217;d like to report on how smoothly everything went and how well it works, and spend some time on my experience with the dataset and the new features it brings to the table.</p>
<p>Unfortunately, I don&#8217;t always get what I&#8217;d like.  I can&#8217;t really talk about stuff like that because I haven&#8217;t reached that point yet, due to various bugs and other implementation hurdles.</p>
<p><span id="more-144"></span>The installation and setup phase went quite well, actually.  The package was a 19 MB installer including full source code, DPKs and other requisite files for building the AnyDAC packages under anything from Delphi 5/C++ Builder 5 to RAD Studio 2010 (or FPC 2.2.x), a nice big helpfile and a fairly comprehensive Samples folder.  The download was nice and fast, and the only real annoyance was the installer getting a few paths wrong.  The helpfile is quite well-written in good, understandible English, which is good to see; that&#8217;s not always the case when working with libraries written by people from non-English-speaking countries.</p>
<p>I loaded up the TURBU project, backed up everything to source control, and went into dm_database.pas, where I keep my client datasets.  Time for the trial by fire:  Open the form designer, switch to text view, Select All, SyncEdit, replace all &#8220;TClientDataset&#8221; with &#8220;TADMemTable&#8221;, switch back to form view.  IMO, if something is presented as a replacement for something else, you ought to be able to swap it out and have it &#8220;just work.&#8221;  In practice, it&#8217;s rarely that simple.</p>
<p>TADMemDataset has the same support for filtering as TClientDatset, and it has a CloneCursor function, which is good because I use it pretty extensively.  What it doesn&#8217;t have, though, is the same public interface as TClientDataset.  For example, TClientDataset has a property called LogChanges, where if you turn it on it will save all edits to an intermediary datastore instead of the main one until you call MergeChangeLog or CancelUpdates.  Among other things, this makes implementing an editor dialog with Apply and Cancel buttons very simple.  TADMemDataset supports the same functionality, but the property that controls it is called CachedUpdates, not LogChanges, and to merge the change log you call CommitUpdates.</p>
<p>I got a bit of a rude surprise when I tried to convert one of my ClientDatasets to a TADMemTable: it didn&#8217;t like one of the fields.  The field was a TSingleField, and the internal storage table doesn&#8217;t know what a Single is, so it converts it to a Double, which causes errors when trying to open the dataset.  When I reported this to Dimitry, he replied that &#8220;ftSingle is not supported for a while.&#8221;</p>
<p>Also, using custom filtering with the OnFilterRecord event handler seems to break CloneCursor.  It looks like an order-of-operations issue inside TADDataset.InternalOpen: X needs to happen before Y, which needs to happen before Z, which is the way it&#8217;s currently set up, except that Z and Y both need to happen before X if you&#8217;re cloning a dataset with an OnFilterRecord event handler.  Apparently this is because X is doing too many different things, and needs to be reworked a bit.</p>
<p>I&#8217;ve reported all these issues to Dimitry and he says he&#8217;ll get a fixed version to me as soon as possible.  What I&#8217;ve seen so far of the dataset&#8217;s API looks interesting, but it&#8217;s kind of difficult to test for the moment, until the rough edges are polished.   I&#8217;ll post another update once I&#8217;m able to.</p>
<p>One other strange thing: In order to use the dataset, it requires  access to some interface that has to be initialized by dropping a certain component onto your project that seems to have no other  purpose except to make this interface available.  (Sorta like the XP  Manifest component that does nothing except link a resource into your  EXE.)  I&#8217;m not quite sure why TADMemTable can&#8217;t manage its own  dependencies, but that&#8217;s kind of disappointing.  Hopefully that will get fixed in an update.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/144/anydac-first-impressions/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I think I just got sponsored</title>
		<link>http://tech.turbu-rpg.com/134/i-think-i-just-got-sponsored</link>
		<comments>http://tech.turbu-rpg.com/134/i-think-i-just-got-sponsored#comments</comments>
		<pubDate>Mon, 24 May 2010 15:18:33 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[AnyDAC]]></category>
		<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=134</guid>
		<description><![CDATA[A couple days ago, I got an email from a member of the AnyDAC dev team.  They make a set of professional data-access components for Delphi, and they&#8217;re looking for feedback and publicity.  They were willing to give me a free license, worth about $400, if I&#8217;d take the time to evaluate their components, provide [...]]]></description>
			<content:encoded><![CDATA[<p>A couple days ago, I got an email from a member of the <a href="http://www.anydac.net/">AnyDAC</a> dev team.  They make a set of professional data-access components for Delphi, and they&#8217;re looking for feedback and publicity.  They were willing to give me a free license, worth about $400, if I&#8217;d take the time to evaluate their components, provide some feedback and suggestions, and write up a few reviews on here.  Apparently they&#8217;re particularly interested in getting some focus on their in-memory dataset, DatS, which isn&#8217;t documented particularly well and doesn&#8217;t get used much. <span id="more-134"></span></p>
<p>So over the next few weeks, I&#8217;m going to be trying AnyDAC out and writing up what I find out.  In the interests of disclosure, I&#8217;m not under any sort of contract to do or say anything specific with it, just an informal agreement over email.  I received a free license for AnyDAC, but no money or other compensation.  I&#8217;ll take a look at their components, and especially DatS, and post on here about my experience with it.  I hope the AnyDAC people don&#8217;t think they&#8217;re getting paid advertising,  because I plan to be honest and objective about the whole thing.  What I like, what I don&#8217;t like, what&#8217;s good and what needs improvement.  And if it turns out that I enjoy my experience, and something in my reviews causes some of my readers to buy some licenses, then maybe it&#8217;ll be worth it for them.  I guess we&#8217;ll see.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/134/i-think-i-just-got-sponsored/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Going to DelphiLive! again.</title>
		<link>http://tech.turbu-rpg.com/131/going-to-delphilive-again</link>
		<comments>http://tech.turbu-rpg.com/131/going-to-delphilive-again#comments</comments>
		<pubDate>Mon, 10 May 2010 13:29:14 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[DelphiLive!]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=131</guid>
		<description><![CDATA[This time last year, I was getting ready to take a plane down to California to attend the DelphiLive! conference, where I&#8217;d been invited to speak about developing games in Delphi.  This year, it&#8217;s been pushed back a few months, to be held in late August instead of mid-May, and I just now got the [...]]]></description>
			<content:encoded><![CDATA[<p>This time last year, I was getting ready to take a plane down to California to attend the <a href="http://www.delphilive.com">DelphiLive!</a> conference, where I&#8217;d been invited to speak about developing games in Delphi.  This year, it&#8217;s been pushed back a few months, to be held in late August instead of mid-May, and I just now got the acceptance email from the organizers.  Looks like I&#8217;ll be presenting two sessions this year: &#8220;Using extended RTTI to make your life easier,&#8221; and &#8220;Game engine  development in Delphi.&#8221;</p>
<p><span id="more-131"></span>Last year&#8217;s conference was a lot of fun, and I really enjoyed having four days to relax, learn some new stuff, and hang out with a bunch of really talented coders.  (And about an hour and a half of completely stressing out and hoping nothing would go wrong as I presented my session!)  They haven&#8217;t posted the schedule yet, and I haven&#8217;t heard much from the other participants, but this is being put on by the same people who did last year&#8217;s DelphiLive!, and they did a really good job of it, so I&#8217;m looking forward to this one.  If any of you can come, you&#8217;ll have a good time.  Hope to see you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/131/going-to-delphilive-again/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Adding non-data fields to a client dataset</title>
		<link>http://tech.turbu-rpg.com/122/adding-non-data-fields-to-a-client-dataset</link>
		<comments>http://tech.turbu-rpg.com/122/adding-non-data-fields-to-a-client-dataset#comments</comments>
		<pubDate>Wed, 21 Apr 2010 18:56:08 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Dark Corners]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[RTTI]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=122</guid>
		<description><![CDATA[A lot of the UI design for the TURBU editor is based on data-aware controls bound to client datasets.  I was trying to build a new form this morning that required me to filter one of the datasets.  Problem is, that would break other things that expected it not to be filtered.  Well, that&#8217;s not [...]]]></description>
			<content:encoded><![CDATA[<p>A lot of the UI design for the TURBU editor is based on data-aware controls bound to client datasets.  I was trying to build a new form this morning that required me to filter one of the datasets.  Problem is, that would break other things that expected it not to be filtered.  Well, that&#8217;s not such a big problem, because TClientDataset has an awesome method called <a href="http://edn.embarcadero.com/article/29416">CloneCursor</a> that lets you set up a second client dataset that shares the first one&#8217;s data store, but with independent view settings.  So I used a cloned dataset, and immediately got an exception when I tried to run.  The control I was using couldn&#8217;t find the field.</p>
<p><span id="more-122"></span>After a bit of digging, I found out that when CloneCursor builds the field structure for the cloned dataset, it copies the FieldDefs from the original.  And FieldDefs only define data fields.  The field I was trying to display was a Calculated field, so I ended up without it.  Well, OK, that&#8217;s not such a big problem.  Just add a new calculated field, right?</p>
<pre>
<div class="codesnip-container" >
<div class="delphi codesnip" style="font-family:monospace;"><span class="kw1">begin</span>
&nbsp; &nbsp;calc <span class="sy1">:</span><span class="sy3">=</span> TWideStringField<span class="sy1">.</span><span class="me1">Create</span><span class="br0">&#40;</span><span class="kw2">nil</span><span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp;calc<span class="sy1">.</span><span class="me1">FieldName</span> <span class="sy1">:</span><span class="sy3">=</span> <span class="st0">'DisplayName'</span><span class="sy1">;</span>
&nbsp; &nbsp;calc<span class="sy1">.</span><span class="me1">Size</span> <span class="sy1">:</span><span class="sy3">=</span> <span class="nu0">255</span><span class="sy1">;</span>
&nbsp; &nbsp;calc<span class="sy1">.</span><span class="me1">FieldKind</span> <span class="sy1">:</span><span class="sy3">=</span> fkCalculated<span class="sy1">;</span>
&nbsp; &nbsp;calc<span class="sy1">.</span><span class="me1">Dataset</span> <span class="sy1">:</span><span class="sy3">=</span> DataSet<span class="sy1">;</span></div>
</div>
</pre>
<p>That ought to work, but it raises an exception.  &#8220;Cannot perform this operation on an open dataset.&#8221;   OK, I can understand that, almost.  It makes sense for data fields, because the underlying data store has to be set up in a certain way.  But for lookup and calculated fields that aren&#8217;t bound to the data store, it doesn&#8217;t make any sense.  Unfortunately, TField.SetDataset doesn&#8217;t care what kind of field you&#8217;re adding.  It checks to see if the dataset is inactive, and if not, boom!  It blows up in your face.</p>
<p>So I can&#8217;t add a calculated field to the dataset after CloneCursor has run, because CloneCursor calls Open and after that it&#8217;s too late.  So maybe I can add it <em>before</em> CloneCursor has run?  That almost works.  You end up with that calculated field in your cloned dataset&#8230; and nothing else.  Why?  Because about 2/3 of the way through TClientDataset.InternalOpen, it says &#8220;if DefaultFields then CreateFields;&#8221;  And DefaultFields is set by the method that calls InternalOpen, which starts like this:</p>
<pre>
<div class="codesnip-container" >
<div class="delphi codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> TDataSet<span class="sy1">.</span><span class="me1">DoInternalOpen</span><span class="sy1">;</span>
<span class="kw1">begin</span>
&nbsp; FDefaultFields <span class="sy1">:</span><span class="sy3">=</span> FieldCount <span class="sy3">=</span> <span class="nu0">0</span><span class="sy1">;</span>
&nbsp; InternalOpen<span class="sy1">;</span></div>
</div>
</pre>
<p>Oops!  Again, not making any distinction between data fields and auxiliary fields.  FDefaultFields is a private field, and DefaultFields is a read-only property, so that makes it very difficult to change.</p>
<p>I could have created an entirely new TClientDataset on my DFM that duplicates the entire field structure of the dataset I&#8217;m trying to clone, including the calculated field, and that would have solved the immediate problem.  But then I&#8217;d have to make another copy of another dataset every time I find myself in a situation like this.  I&#8217;d really prefer to make it recognize that there are some predefined fields that it can integrate into the field structure.</p>
<p>Fortunately, InternalOpen is virtual.  All I need to do is create a subclass of TClientDataset that overrides InternalOpen and resets FDefaultFields to the correct value before calling <strong>inherited</strong>.  Except&#8230; how do you do that?  It&#8217;s a private field of TDataset, accessible only through a read-only property.</p>
<p>Prior to Delphi 2010, I wouldn&#8217;t have been able to do this.  But now, <a href="http://tech.turbu-rpg.com/79/abusing-extended-rtti-for-fun-and-profit">there&#8217;s a way to fix this sort of problem with extended RTTI.</a> The solution looks like this.  (This solution works specifically for TClientDataset, but you can apply it to any TDataset descendant easily enough.)</p>
<pre>
<div class="codesnip-container" >
<div class="delphi codesnip" style="font-family:monospace;"><span class="kw1">unit</span> extensible_cds<span class="sy1">;</span>

<span class="kw1">interface</span>
<span class="kw1">uses</span>
&nbsp; &nbsp;DBClient<span class="sy1">;</span>

<span class="kw1">type</span>
&nbsp; &nbsp;TExtensibleClientDataset <span class="sy3">=</span> <span class="kw1">class</span><span class="br0">&#40;</span>TClientDataset<span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="kw1">protected</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">procedure</span> InternalOpen<span class="sy1">;</span> <span class="kw1">override</span><span class="sy1">;</span>
&nbsp; &nbsp;<span class="kw1">end</span><span class="sy1">;</span>

<span class="kw1">implementation</span>
<span class="kw1">uses</span>
&nbsp; &nbsp;db<span class="sy1">,</span> RTTI<span class="sy1">;</span>

<span class="coMULTI">{ TExtensibleClientDataset }</span>

<span class="kw1">procedure</span> TExtensibleClientDataset<span class="sy1">.</span><span class="me1">InternalOpen</span><span class="sy1">;</span>
<span class="kw1">var</span>
&nbsp; &nbsp;context<span class="sy1">:</span> TRttiContext<span class="sy1">;</span>
&nbsp; &nbsp;field<span class="sy1">:</span> TField<span class="sy1">;</span>
&nbsp; &nbsp;value<span class="sy1">:</span> <span class="kw4">boolean</span><span class="sy1">;</span>
<span class="kw1">begin</span>
&nbsp; &nbsp;value <span class="sy1">:</span><span class="sy3">=</span> <span class="kw2">true</span><span class="sy1">;</span>
&nbsp; &nbsp;<span class="kw1">for</span> field <span class="kw1">in</span> <span class="kw2">self</span><span class="sy1">.</span><span class="me1">Fields</span> <span class="kw1">do</span>
&nbsp; &nbsp; &nbsp; value <span class="sy1">:</span><span class="sy3">=</span> value <span class="kw1">and</span> <span class="br0">&#40;</span>field<span class="sy1">.</span><span class="me1">FieldKind</span> &lt;&gt; fkData<span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp;context<span class="sy1">.</span><span class="me1">GetType</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="sy1">.</span><span class="me1">ClassInfo</span><span class="br0">&#41;</span><span class="sy1">.</span><span class="me1">GetField</span><span class="br0">&#40;</span><span class="st0">'FDefaultFields'</span><span class="br0">&#41;</span><span class="sy1">.</span><span class="me1">SetValue</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="sy1">,</span> TValue<span class="sy1">.</span><span class="me1">From</span><span class="br0">&#40;</span>value<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy1">;</span>
&nbsp; &nbsp;<span class="kw1">inherited</span> InternalOpen<span class="sy1">;</span>
<span class="kw1">end</span><span class="sy1">;</span>

<span class="kw1">end</span><span class="sy1">.</span></div>
</div>
</pre>
<p>If this sounds overly complicated, that&#8217;s probably because it is.  TField.SetDataset should only care about the dataset being open if you&#8217;re trying to add a data field.  That would have solved everything.  I submitted <a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=77055">a report to QC about this</a> a few months ago.  Hopefully it&#8217;ll be one of the things they fix for Delphi 2011.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/122/adding-non-data-fields-to-a-client-dataset/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Personal property and computing</title>
		<link>http://tech.turbu-rpg.com/116/personal-property-and-computing</link>
		<comments>http://tech.turbu-rpg.com/116/personal-property-and-computing#comments</comments>
		<pubDate>Fri, 09 Apr 2010 21:50:02 +0000</pubDate>
		<dc:creator>Mason Wheeler</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programming Ethics]]></category>
		<category><![CDATA[politics]]></category>

		<guid isPermaLink="false">http://tech.turbu-rpg.com/?p=116</guid>
		<description><![CDATA[I&#8217;ve always been a big fan of Apple&#8217;s.  My first computer was an Apple IIe, and finding a copy of BASIC on there was what first got me into programming.  A good percentage of the modern user interface concepts we take for granted today were invented by Apple back in the 1980s.  (Yes, I know, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve always been a big fan of Apple&#8217;s.  My first computer was an Apple IIe, and finding a copy of BASIC on there was what first got me into programming.  A good percentage of the modern user interface concepts we take for granted today were invented by Apple back in the 1980s.  (Yes, I know, they got the basic concepts from Xeroc PARC, but a lot of their work was <em>their work</em>, not Xerox&#8217;s.)  They&#8217;ve always been one of the major drivers of innovation in the computer industry, and they&#8217;ve done a lot to hold the line against Microsoft&#8217;s campaign for complete domination of the computer industry.  They&#8217;re one of a <em>very</em> few companies that have actually had any real success in that area, and we all owe them a debt of gratitude for that, if nothing else.</p>
<p>Apple released the latest iPhone development license yesterday, and I suddenly find myself a lot less grateful.</p>
<p><span id="more-116"></span>In case you haven&#8217;t already seen, it contains the following provision:</p>
<blockquote><p>Applications must be originally written in Objective-C, C, C++, or  JavaScript as executed by the iPhone OS WebKit engine, and only code  written in C, C++, and Objective-C may compile and directly link against  the Documented APIs (e.g., Applications that link to Documented APIs  through an intermediary translation or compatibility layer or tool are  prohibited).</p></blockquote>
<p>Among other things, that means no Object Pascal for the iPhone.  At Delphi Live last year, the Embarcadero folks talked about &#8220;Native Delphi everywhere.&#8221;  Everywhere but the iPhone and the iPad, apparently.  Oh, and not on any phone that runs on Windows Phone 7 either; <a href="http://www.networkworld.com/news/2010/031510-windows-phone-apps.html">only .NET apps that use Silverlight or XNA are allowed there</a>.  Google&#8217;s Android is only slightly better.  You&#8217;re &#8220;officially discouraged&#8221; from using anything but Java, but not outright prohibited.  (Language choice is alive and well on Palm&#8217;s WebOS, but phones that run on it aren&#8217;t doing so well in the market.)</p>
<p>This also slams the door hard right in the face of all the folks at the Lazarus project and the fascinating work they&#8217;ve done on <a href="http://wiki.freepascal.org/FPC_PasCocoa#Enabling_Objective-C.2FObjective-Pascal">Objective-Pascal</a>, and it calls the future of the Delphi team&#8217;s cross-platform work into question.  With all of the blog posts about Delphi for the Mac in the upcoming &#8220;Fulcrum&#8221; project, it&#8217;s clear that Embarcadero is putting a lot of effort into making Delphi work on the Mac, and does anyone doubt that they had the iPhone/iPad in their sights as part of the long-term plan?</p>
<p>I spent a lot of time thinking about what makes this new policy so offensive to me.  Apple has every right to build the iPhone however they want to.  The design of the phone is their own intellectual property.  And they have the right to build an App Store as a centralized place to buy and sell iPhone content.  And if they own the App Store, it logically follows that they have every right to decide what apps people can offer on it.  The store&#8217;s their property, after all.  I&#8217;ve seen plenty of brick-and-mortar stores with signs that say &#8220;we reserve the right to refuse service to anyone for any reason,&#8221; and this is just the electronic version of that.</p>
<p>But here&#8217;s where we come to a problem.  The design of the iPhone is Apple&#8217;s property.  The App Store is Apple&#8217;s property.  But <em>the individual phones and iPads are not</em>.  If Apple sells an iPhone to me, it is transferring ownership of the device from Apple to me in exchange for an agreed-upon sum of money, and once this transfer has taken place, they no longer own it.  It becomes my property, to do with as I please.  That&#8217;s a very simple, intuitive concept that anyone can grasp, and it&#8217;s been a fundamental principle of capitalism since before Adam Smith wrote the how-to guide:  as long as I do not use a personal possession in such a way as to cause actual harm to others, I can do whatever I want to with it.</p>
<p>This principle&#8217;s under attack now.  The only way to get a new app on your iPhone is through the App Store, or by uploading it directly from your Mac if you have a Mac and the iPhone SDK.  On my PC, I can go to some random website, download a new program and install it, but you can&#8217;t do that on an iPhone, even though it has a built-in Internet connection.  In effect, Apple has decreed you only theoretically own the iPhone; you don&#8217;t own the part of it that receives new applications.  That still belongs to Apple 100%.</p>
<p>Well, to be frank, that&#8217;s a bunch of crap.  Apple has no right to tell me that I can&#8217;t download an iPhone app from some random website and install it on an iPhone if I want to, and Microsoft has no right to say that I can&#8217;t write non-.NET apps for the Windows Phone 7 OS if I can figure out the bindings.  <a href="http://en.wikipedia.org/wiki/Digital_Millennium_Copyright_Act">Any law that says they do have such a right</a> is evil and needs to be repealed.</p>
<p>This isn&#8217;t just about the iPhone, or even phones in general.  This is about the future of personal computing itself.  What Apple&#8217;s managed to pull off with the iPhone looks a whole lot like Microsoft&#8217;s vision of the future, in which every computer contains a <a href="http://en.wikipedia.org/wiki/Trusted_Platform_Module">TPM chip</a> that will place the ultimate control of the system&#8217;s functionality under the control of the owners of the software that runs on it, not the owner of the computer.  This isn&#8217;t some hypothetical bad future bogeyman that Richard Stallman is cooking up to scare people into using Free Software, folks.  This is what is really happening, right in front of us, today.</p>
<p>In any other context, taking control of the functionality of a computer away from the computer&#8217;s owner and using it against his will and against his interests is known as hacking that computer.  It&#8217;s universally regarded as a form of computer crime, and rightfully so.  But when DRM technology is involved, it&#8217;s not a crime; instead it&#8217;s a legally-protected &#8220;access control.&#8221;  That&#8217;s what the DMCA and similar laws in other countries are all about: they explicitly give copyright owners the right to hack your computer, at any time and for any reason, if your computer runs their copyrighted material.  And until this notion is reversed, and the use of DRM technology is legally recognized as the crime it is, we can expect to see the future of computing looking more and more like the iPhone.</p>
<p>It would seem that Apple has come full circle.  <a href="http://www.youtube.com/watch?v=OYecfV3ubP8">Thanks to Apple Macintosh, 1984 was not like &#8220;1984&#8243;.</a> But thanks to Apple iPhone, 2010 might be.</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.turbu-rpg.com/116/personal-property-and-computing/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>
