Wednesday, August 11, 2004

Why the with-statement should not be extended

N. Ismail commented on my last post about the with-statement:

"I recommend the with statement be extended to allow it to also be written as such:

with a: Form1 do 
begin
a.foo := 123;
a.bar := 'xyz';
a.Caption := 'Test';
Caption := 'Foo Bar'; //The forms caption
end;"

IMO, the with statement should not be extended.


Here are my reasons:


#1. This will help nothing for existing code. Existing code uses with the old way, so the compiler would have to support that syntax for foreseeable future.


#2. Enhancing the with-statement will encourage increased use of it, which is a bad thing, IMO. My suggested warning should encourage decreased use.


#3. What you want can easiliy be obtained today and work in all versions of Delphi. Just define the identifier as a local var and get rid of the with, like this:

var 
a: TForm1;
begin
a := Form1;
a.foo := 123;
a.bar := 'xyz';
a.Caption := 'Test';
Caption := 'Foo Bar'; //The forms caption
end;

"Obviously one could have declared a variable named 'a' of same type as Form1,"
Exactly ;)
"but I think the above syntax is cleaner"

I don't. And it doesn't give you anything functionally that a local variable cannot give you. Its pure syntactic sugar (with a sour taste, IMO).

Tuesday, August 10, 2004

The with-statement considered harmful

As have been mentioned by several people in several places (newsgroups, blogs, QC etc.) Delphi's with-statements can be harmful to the readability, maintainability and robustness of your code. Not to mention it makes debugging harder ;).

Much like the problem with potential duplicate identifiers from used unit scopes, the with-statement problem could be mitigated by enhancing the compiler to produce Warnings for ambiguous with-statements.

Consider the following code:

Unit Foo; 
type
TGadget = class
bar: integer;
end;
//----
Unit Bar;
var
a: TGadget;
foo: integer
begin
with a do
foo := 123;
end;

This is version 1. Code compiles without warnings and works correctly. Now Mr. Component on the other side of the globe makes an update to the TGadget class:

Unit Foo; 
type
TGadget = class
foo: integer; // New feature!
bar: integer;
end;

Then John Doe recompiles his code with this new version:

Unit Bar; 
var
a: TGadget;
foo: integer
begin
with a do
foo := 123;
end;

Currently, with D7, there is no warning. Code compiles, but it fails mysteriously at run-time. In a future version of the compiler he could get warning such as: Warning: Potential name conflict: foo declared in unit Bar and Foo.TGadget. In this case, to get rid of the warning, the programmer could change the code to

   Bar.foo := 123; 

or (even better) he could just get rid of the with-statement.


IMO, if we could have this kind of warning for with-statements, it would be the first steps towards patching one of the very few sorespots of the otherwise elegant Object Pascal language. (and before you ask, yes, this has been QC'ed: #8770).

Friday, August 06, 2004

The uses clause considered harmful

(The headline plays with Edsger Dijkstra's famous article "Go To Statement Considered Harmful") Because the way unit references in the uses clause work in Delphi, you could occasionally get weird and even buggy effects because of changes made in one of the units you use. Note that in general, Delphi handles modularity and code imports much cleaner than most other programming languages. Still there is room for some improvement.

My suggestion is that the Delphi compiler be improved to emit a new Warning for potential name conflicts when the same identifier is imported from two or more units. The goal is to catch unintended changes in semantics after changes have been made to used units.

If I have two units, A & B, both of which export the identifier foo and then in another unit I write:

uses A, B; 
// ...
begin
foo;
end.

Here the reference to foo is without a unit prefix. Currently I would get no warning. My suggestion is to generate a warning, something like this:


"Warning: Potential name conflict: foo declared in unit A and unit B."

To resolve the warning, the programmer would prefix foo with the intended unit name:

begin   
A.foo;
end.

This would then generate no warning. Technically, the reference to 'foo' isn't really ambiguous. That's why you shouldn't get a compile error. But like most warnings, this one should be there to catch potential human error or confusion. You have two possible sceniarios:



  1. The user meant to use A.foo, but because of the unit-ordering he is actually using B.foo.

  2. Last week, foo was only defined in unit A and the program was compiling working as intended. This week a new foo has been added to B. The program still compiles, but stops working correctly at run-time. This is something that can be really hard to debug and track down - it has happened to me...

#2 is the most dangerous and where the warning would be most useful.

Thursday, August 05, 2004

Delphi 9 is Diamondback!

John Kaster of Borland just posted a new BDN article about the upcoming BorCon 2004 and the tracks devoted to the next version of Delphi, code-named DiamondBack! Borland hotshots like Danny Thorpe, Allen Bauer, John Kaster, Jim Tierney, Corbin Dunn & al will reveal the new cool features. Check it out: http://bdn.borland.com/article/0,1410,32499,00.html