views:

251

answers:

5

Anybody know what is different about Delphi 2009's handling of "with"?

I fixed a problem yesterday just by deconstructing "with" to full references, as in "with Datamodule, Dataset, MainForm". Delphi 2006 and earlier applied "Close" to the Dataset. Delphi 2009 applied "Close" to the MainForm and exited the application!

+3  A: 

Using with A,B,C,D is bad practice since changes to other units can suddenly cause your code to stop working as expected. See here for more information, or here (search for "with keyword").

Vinay Sajip
+16  A: 

Nothing has changed. Your previous observation was wrong. The objects mentioned in a with statement are considered "right to left," so in your example, MainForm would be searched first, then Dataset, and then Datamodule. That's how it's always been. It's the same as if you'd written this:

with Datamodule do
  with Dataset do
    with MainForm do begin
      Close;
    end;

Go ahead and check the Delphi 2006 documentation; there should be a section named Declarations and statements, under which you'll find Structured statements, including the section on With statements.

Do yourself a favor and don't use with. It causes no end of trouble both during debugging and during maintenance, where maintenance could even be performed by the person who wrote the code just the day before.

Rob Kennedy
Hmmm... I checked the 2/7/2006 version of the unit against the 6/2/2009 version, and I indeed did add MainForm. So it wasn't different in D2006 after all.
So what is recommended instead? If one is using "with DBComponent.DataSource.DataSet do" should one introduce a local variable to hold the reference?
Larry Lustig
Yes, @Larry. For example: `var dset: TDataset; dset := DBComponent.DataSource.Dataset; dset.foo; dset.bar;`
Rob Kennedy
Ugh! Big change for me. Oh well. . .
Larry Lustig
+10  A: 

With is evil. I don't know how many times I need to say this, but apparently we're not there yet.

With can only "safely" be used with objects that are never going to change. If you apply it to objects you define in your own project, all bets are off and I'd daresay you should rather just use "if Random(50)<25" parts to execute your code, it's at least documented to executed oddly.

The problem is that once you start messing with an object, introducing new methods or properties, or renaming old ones, all existing with-statements that use those methods has the potential to change meaning. And not in the "Warning: Call to ambiguous method" change either. The code will just do something other than it did previously. Without telling you about it.

For instance, let's assume you have this:

with connection, file do
begin
    Close;
end;

then what do you expect to happen? Well, it's natural to close a file, so I would expect the file to be closed. Let's further assume that this file variable holds a object of type TSomeOddFile that doesn't define a Close method, but rather a CloseFile method. The above With-statement will then close the connection instead.

All good, it's documented, nobody wrote this piece of code thinking that the file would be closed, after all, the method is named CloseFile for that object, it's just my assumption that is wrong and I don't work on the project. Yet.

And then someone fixes that, renaming CloseFile to Close. The above code will silently start closing the file instead of the connection. No warning, no error, compiles just as fine as before you changed the method name. Runs just as fine^h^h^h, no wait, it won't.

So yeah, with will bite you in the a**.

Lasse V. Karlsen
+1, sometimes realizing how bad with is can only come from experience.
skamradt
Well, learning is supposed to work by being told about experiences, so that you don't have to go through it yourself. WITH has burned so many hours for me until I discovered what a steaming pile of .... it really is.
Lasse V. Karlsen
+1  A: 

The compiler is usually quite solid, so I wouldn't assume a bug or change before you really excluded everything else. Some things I can quickly think of:

1) Look if you use overloaded functions or operators. Since the definition of STRING (and several other types) changed, a different variant can be chosen, because the signature effectively changes.

2) it can also be that some included unit now defines an identifier that is already used, and taking precedence over the one exposed in an different unit.

If not, start isolating the code in a minimal example, using as little units as possible. Do it step by step, since the trick is what the last change was when the behaviour changed.

Post that (or an URL) here, it is always interesting to see.

Marco van de Voort
+1  A: 

With..do is to be used with care. Otherwise, is a infinite source of headaches.... I agree with Rob Kennedy and others.

As Craig Stuntz (in other post about with..do) and Lasse V. Karlsen above said, with..do can create a lot of traps.

Fabricio Araujo