twm's homepage logo
From someone who traveled abroad to learn appreciating his own country ...
Class and Variable declaration pitfall in Delphi
Deutsch English
Google
Search dummzeuch.de
Search WWW

Introduction

There has recently been quite a lot of hubbub in the Delphi blogosphere about a blog posting by a guy called Branden Tanga, who was venting his frustration with Rad Studio 2007. In his latest post called Now I am pissed at CodeGear RAD and the follow up called More about me being pissed at CodeGear he describes a problem about the visiblity of a class "TestClass" and how he thought he solved it, just to find that his solution doesn't work, which he then again blames on RAD-Studio. I think I know what the issue is and tried to leave a comment on his block but Blogger won't let me, so here is my reply.

The first problem

In a unit called "global" he declares a class called "TestClass":

                      
unit global;

interface

type
  TestClass = class
  end;
                    

In another unit he then tries to declare a variable of that class and it fails to compile:

                    
unit SomeOther;

interface

uses
  global;

implementation

/// ....

procedure someproc;
var
  Test: TestClass;
begin
end;
                  

The above should definitely compile but for him it didn't, so there must be more to it.

Solution to the first problem

Since his "solution" was to change the declaration like this:

                  
var
  Test: global.TestClass;
                

My guess is that there was another unit in the uses clause, that declared a variable called "TestClass" thus causing a name collision:

                
unit Intruder;

implementation

uses
  global;

var
  TestClass: global.TestClass;
              
              
unit SomeOther;

interface

uses
  global,
  intruder;

implementation

/// ....

procedure someproc;
var
  Test: TestClass;
begin
end;
            

(It might have been called something like "testClass" rather than "TestClass" (lower case "t"), which is common practice in the Java/C# world, I have been told, since these languages are case sensitive. Delph isn't, so this is the same identifier!) This will produce a compiler error because "Test" is declared with a type identifier that isn't a type but a variable name. Adding the "global" prefix solves this issue but only until you try to actually instantiate "Test":

The second problem

            
procedure someproc;
var
  Test: global.TestClass;
begin
  Test := TestClass.Create;
end;
          

While this looks fine it is actually an error: It will not call "global.TestClass.Create" but rather "intruder.TestClass.Create" and this will fail - probably with an access violation - because "TestClass" (the variable) has not been initialized.

Solution to the second problem

To solve that issue again, prefixing "global" would work:

          
procedure someproc;
var
  Test: global.TestClass;
begin
  Test := global.TestClass.Create;
end;
        

But of course, this will easily fall over again somewhere else, so the only real solution would be to resolve the name conflict by renaming at least one of the two. I'd suggest to rename the class adhering to the Delphi naming convention of prefixing classes with an upper case T:

        
unit global;

interface

type
  TTestClass = class
  end;
      

Conclusion

The above is pure guesswork - I seem to have misslaid my crystal ball - but I think this is the issue he is facing. It is caused by having an implicit global namespace that contains every identifier from every unit in the uses clause. Identifiers are introduced in the order of the units in the uses clause, so the last one overrides all previous ones. This can be convenient if you want to locally override a type declaration, but it can also cause hard to find errors, which is even aggravated if you are using the "with" statement.

Invoice ;-)

Hi Branden,

For now, I won't charge any consultancy fees ;-), but if it turns to be correct, please link to this article. In the future I suggest using the Delphi newsgroups when facing a problem like this rather than blogging about it.

twm



This document was generated using AFT v5.096

last updated: 2012-10-14 twm
Post to del.icio.us Best Viewed With Open EyesValid XHTML 1.0!