Tuesday, December 16, 2003

IDE Spelunking...

Ever wonder what the line break style is for each line in a text file? Well, there is a way to find out without opening the file in a hex-editor. If you have C#Builder, and will be in the upcoming Delphi 8 for Microsoft .NET, there is a hidden setting that will tell the editor to display special unique characters at the end of each line that will represent the style of line-break.

"HKCUSoftwareBorlandBDSx.xEditorSource OptionsxxxShow line breaks" = "True"

Where:

  • x.x = 1.0 for C#Builder and 2.0 for Delphi 8

  • xxx = Sub key for specific file types


  • !DANGER! WILL ROBINSON...

    In previous versions of Delphi, when a user built a package, the IDE provided significant assistance in making sure the package was being built correctly by limiting what units got implicitly linked into the package. In Delphi 8 for the Microsoft .NET Framework, much of this assistance isn't being done due to the overwhelming complexity of the problem now that we've moved into the managed space. Currently, when you build a package/assembly, this is ones using the "package" keyword, not using library, which I'll comment on later, the compiler will display warnings when any unit was implicitly linked into the package. Please treat these as ERRORS. In a future release of the D4Net compiler, these warnings will change to errors.

    What does this mean?

    You must make sure that your "requires" clause refers to the proper Delphi assemblies and your "contains" clause explicitly lists all the units to be included in the package/assembly. What has been happening, is that folks have been blithely ignoring those errors, then proceeding to wonder why their component behaves strangely when they load it into the IDE designer. If you see any "implicitly linked unit" warnings, you need to eliminate them. For instance, if you see a warning that states Borland.Vcl.Classes was implicitly linked into your package, you forgot to add Borland.VclRtl to the "requires" clause. The same if you see Borland.Vcl.Controls implicit link warning, only you forgot Borland.Vcl.

    Yes there are cases where this is legitimate, like you want to build your own specific run-time assembly with a mix of VCL units and your custom units. However, the rules regarding the use of an assembly/package such as this haven't changed... you can't build one that links into itself *any* Borland supplied .dcu/.dcuils. or to any non-Borland supplied package/assembly that does.

    What's the big deal, its the same code, right?

    Yes, the actual machine/IL instructions are the same, however that isn't the only thing in the assembly. There is all that metadata (this is also true for Delphi/win32) that describes certain types, such as classes, records, enums, etc... CLR is a little better at this because it will never mistake one type for another because it always internally deals with types as full assembly qualified names.
    Suppose you have two assemblies, A1.dll and A2.dll. You linked into both of these assemblies, the MyComp class. To the CLR, the MyComp class name in A1.dll is actually, "MyNamespace.MyComp, A1" which, to the CLR, is a totally different type than "MyNamespace.MyComp, A2." They are not interchangeable.

    But C# lets me do this.

    Oh sure it does.. you keep telling yourself that. Yes, C# does allow you to create two assemblies that contain the same class, however it also warns you and will select only one of the MyComp types to use in the calling assembly/.exe. Even Delphi has always allowed you to do this. The problem comes in when you want to load those assemblies/packages into the same process/AppDomain. Consider this scenario, you have assemblies B1.dll and B2.dll, each of which uses A1.dll and A2.dll respectively. B1 and B2 contain all unique types, so all is well... not! What if B1 has a class that descends from "MyNamespace.MyComp, A1" and B2 does the same with A2? Now you have a third assembly/.exe, C, that uses A1, B1 and B2 only. It knows nothing of A2. C constructs an instance of the MyComp descendent from B2. If you did an "as" cast or and "is" test, it will *not* report that it is a MyComp descendent.

    If you did the above scenario with Delphi, when it came time to link with A1, B1, and B2, you would also implicitly link with A2. When the compiler goes to link things together, it will discover that you have the same unit in A1 and A2 then fail to link. If the A1 and A2 assemblies were not Delphi written, then the compiler will still detect that it is importing two types that appear to be the same name and it will issue a warning and select one with which to link, just like C#.

    So the bottom line is that a type can exist in one and only one place within a process/AppDomain. In fact this has always been the rule for Delphi/Win32 as well. So, again, I find myself saying that the rules have not changed.

    Friday, November 21, 2003

    The rules have not changed...

    Let's hear it for Garbage Collection! Hip-Hip-Ho.... whoa there Nellie!! When it comes to VCL for .NET and Garbage Collection, the more things change, the more they stay the same..

    The level of source-code compatibility between the traditional VCL/Win32 and VCL/.NET is nothing short of amazing. If you witnessed the Product Address at this year's Borland Developer Conference, you would have seen a demo where the original FishFact database demo was opened in Octane (Delphi 8 for .NET), compiled and ran with 0 (zero), count them, 0(zero) code changes. Not even the uses lists needed to change (remember WinTypes, and WinProcs? ;-).

    OK, so they're compatible... What does this have to do with Garbage Collection? Well... there are some myths around GC that may get you in some serious trouble. Yes, it is true that in a GC environment, you generally don't have to worry about freeing memory. However there are a lot more types of resources than simply memory. Things like file handles, GDI handles, etc... It is easy to understand that these items are out of the reach of the GC, so you have to continue to guard your code with try..finally blocks to open/close, allocate/release, etc.. What is more subtle, though, are those "resources" that don't quite "fit" the definition of an "object."

    So what other kinds of "resources" out there have to be managed in a similar fashion to those more traditional notion of a resource? I use the term "resource" loosely here in order to simply highlight the correlation to what one normally thinks of as a "resource." Suppose you have a class of objects that have specific knowledge of the container in which they live. When you create an instance of one of these object classes, they are given the container and proceed to toss themselves into that container. You now have this "bag" of objects by referencing the container. You can pick each item from the bag perform some operation on them. One suich operation that is common is to "destroy" the item. Well, since this item knows about its container, it plays nice and removes itself from the container before it self-destructs.

    In the GC world, a common mistake is to simply think of "destroying" an object is simply freeing its memory. So I don't have to do that in the GC world because that will be handled for me, right? Sure it will.. eventually. But it will not automatically take care of one important resource, it's container's reference. That reference needs to be cleaned up. It is not a "resource" onto which the item itself holds, but is a resource nonetheless. When you look at the declaration of the object, you won't find a reference to this resource... oh wait yes you do... It is the reference to the container itself. It is through this reference that the "resource" lives.

    So if you don't "destroy" an object, how do you make it release its references? In .NET, there is a simple pattern that is followed. An object that needs to do immediate resource cleanup, should implement the IDisposable interface. It has one method called procedure Dispose; (or for you that prefer a more "curly" world void Dispose();). Now when you want to "destroy" an item in the container, you cast the item to IDisposable and call the Dispose method. In the Dispose method it just performs the nessesary steps to remove itself from the container.

    Sure, you could manually remove the item from the container yourself and forgo the IDisposable riggamarole, but what if you hand the item off to someone that has no specific knowledge of the particular container instance in which the object is currently living? This is why the IDisposable pattern is important.

    So let's bring all this around now to Delphi 8 for .NET and its view of the world. All this IDisposable stuff seems tedious and would require some massive changes to my code to play nicely in .NET. This is where Delphi has realized some of the benefit of arriving a little later to the party. Delphi introduces an interesting language construct called "class helpers." There could be a whole tome written about the subject of "class helpers", but suffice it to say, they have given the Delphi programmer a familiar world in which to work. All that code you have written in which you dutifully have implemented your destructors to properly clean up after yourself, release resources, and generally keep your house in order can now continue to live on..and serve a real purpose beyond simply releasing memory. Releasing memory is no longer the responsibility of the lowly Destroy destructor. It now is a cue to the Delphi compiler that you want it to implement the IDisposable pattern for you. Your object now implicitly implements IDisposable and the Dispose method maps to your Destroy destructor. It even takes care of guarding your destructor from being called more than once by implementing the pattern of setting a compiler generated instance variable to true the first time through the Destroy destructor and exits immediately on all subsequent calls. To the world outside Delphi, your objects simply appear to implement the IDisposable pattern. The really cool thing though, is that all objects that come in from outside Delphi (remember all objects in .NET descend from System.Object, which is not Delphi's System.TObject. In the CLR world, it is the other way around. Borland.Delphi.System.TObject = System.Object) "appear" to have a non-virtual method called Free (thank you class helpers). If you are a seasoned Delphi developer, you know that in order to maintain proper "exception safety" you never call the Destroy destructor directly. This is because the Free method would check to make sure Self (or this) is non-nil before calling Destroy. In .NET it continues to do this as well, but now it checks if Self implements IDisposable and then calls Dispose if it does. This is why you can call MyHashTable.Free. Through the magic of class helpers, the Free method appears to be a method of HashTable.

    So now all your nicely done try...finally code continues to serve a purpose, in fact is remains critical to the proper operation of VCL code. For instance, a TComponent derivitive takes an Owner parameter in its constructor. It then proceeds to add itself to the Owner's list of Owned Components. So, when you call Free on the component, the expectation is that that component is removed from the Owner's list immediately. These semantics are now preserved.

    Garbage collection certainly takes away certain programming chores, but it is not a panacea. The more you understand the environment in into which you are moving, the better you'll be able to migrate your existing code. So the upsot of all this is that you don't have to change nearly as much code as I'm sure you originally thought nor should you.

    Thursday, November 13, 2003

    Up periscope...

    Just a quick note here... For those two or three folks that seem to be gluttons for punishment and actually read this jumbled mess of random thoughts... I hope to be back in the blog saddle within the next few weeks. I need to make good on the promise that I'd present some of the material I had planned on preseting in my "IDE Spelunking" BorCon talk that was canceled.

    Monday, November 10, 2003

    Aftermath

    Now that the 2003 BorCon is behind us, we are now "kickin' it up a notch" for that final drive to release. This is mainly why the blogs have been coming less frequently... that whole "work" thing keeps cutting into my blog time ;-)... Also we're at that stage where the days are sort of blending together...

    It seems the rainy season here in Santa Cruz, County, CA has started in earnest. While it is sunny today, the past week was filled with dark overcast foggy skies. That certainly makes it easier to keep ones head down and concentrate on completing the release.

    Wednesday, November 5, 2003

    BorCon talk

    I just finished my one talk I was still giving at BorCon and am now back in the office... It was a small crowd, but it always is since Open ToolsAPI stuff isn't a huge draw. I got to present some interesting things, like we plan on publishing a Delphi/C#Builder integration package to registered users and partners to allow them to move thier existing Delphi and/or C#Builder IDE plug-ins over from Delphi 7.

    Stay tuned.

    Friday, October 31, 2003

    Avalon: Yes, the Picture's Changing

    Avalon: Yes, the Picture's Changing

    Here's a response that I posted to the above article:

    I can see everyone rolling their eyes at the loony that is about to make this statement.

    The movement of the declarative "InitializeComponents()" code to another more suitable "language" is nothing new, nor earth-shattering. Now comes the controversial part. Take a look at Borland Delphi... "Oh, I've heard of that" No, it is *not* just that "database" tool. It is a full featured, powerful object-oriented, component-based, compiled-to-native-code, development environment.

    The Visual Component Library (VCL) that is included with Delphi uses a predecessor to Avalon's XAML. By using a text or binary declarative "language", the form construction is taken out of the code. This "script" is attached to the executable as a resource. It can also be easily localized by providing an alternative script.

    Avalon is clearly an evolutionary step along this same path, but I would certainly *not* characterize it as "revolutionary."

    Yes, I work for Borland. Yes, I'm one of the original developers that designed and built Delphi. Delphi was launched on February 14, 1995 at the Software Development West conference in silicon valley.

    If you look closely, and resist the urge to revise history, you'll see that one of the primary architects behind .NET is Anders Hejlsberg... who was one of the original architects behind Delphi. Anders left Borland and helped produce J++ and WFC, then eventually C# and .NET. If you compare WinForms, WFC, nay Delphi's VCL, the similarities are... let's just say, striking.

    What I find interesting and, to be honest, somewhat frustrating, are the reactions when I state that "Delphi's been doing this since 1995." I can see them rolling their eyes, as if to say, "There's another of those Delphi crackpots who thinks they actually innovated something."

    In actual fact, we at Borland are extremely excited about the technologies that are coming out of Redmond.

    In fact, if you happen to *be* a Delphi programmer you need to keep your eye on the "Octane" project.. and if at all possible, attend the Borland Conference in San Jose, CA starting this weekend (Nov. 1, 2003).

    So I guess it *is* true that imitation is the highest form of flattery.

    Allen Bauer.
    Borland Software Corporation.
    RAD .NET IDE Architect.

    Wednesday, October 29, 2003

    Editor pair highlighting

    Since one of my BorCon talks has been canceled, I will begin to post some of the content that was planned here. To get things started, here's one item that applies to C#Builder (and the upcoming Delphi 8, codenamed "Octane").

    Modifying which character pairs the IDE highlights:

    Insert standard disclaimer concerning editing your registry, here

    Open RegEdit and go to the following key:

    HKCUSoftwareBorlandBDS1.0EditorSource OptionsBorland.EditOptions.XXXXPair Table

    Under the above key there are string entries formatted as comma separated values, for instance the "(* *)" pair in the "Borland.EditOptions.PascalPair Table" key is represented as:

    0,1,2,(*,*)

    The meanings of these values are, in order:

    Nestable = 0 - No, 1 - Yes, 2 - Maybe
    ImpliedDir = 0 - No, 1 - Yes
    CharCount = 1 or 2 only
    Starting string = 1 or 2 char string
    Ending string = 1 or 2 char string

    So to create non-nestable, implied direction pair for, say <% and %> it would look like this:

    0,1,2,<%,%>

    So if you don't want to highlight the quote characters since they have no implied direction and will often highlight strangely, delete the 0,0,1,',' and 0,0,1,"," entries and those pairs won't display as match characters. Note that this will also disable the Ctrl-Q+[ and Ctrl-Q+] functionality for those characters.

    Tuesday, October 28, 2003

    Talks canceled

    Due to product scheduling constraints, one of my BorCon talks has been cancelled. The "IDE Spelunking" talk will not take place on Tuesday, November 4 as planned. The Open Tools API talk is also in danger of being canceled as well. This stinks... I'll also not going to be able to be there very much either... Even though it is less than 30 minutes from Borland.

    Sunday, October 26, 2003

    Borland at this year's Microsoft PDC

    Marco Russo - Borland at PDC

    It seems that some folks are certainly noticing the conspicuous placement of Borland at this year's Microsoft PDC. And, since BorCon is after MS' PDC, there'll be a lot of continued buzz... You don't want to miss it.