WITH IS EVIL!

WITH IS EVIL!

God damn it, I know it makes code easier to type, but its hard to read and maintain.  Get rid of the bloody thing completely!

Of course, I'm even more cross because this is some of my very own code I am complaining about, I really don't know why I used a with, the block was only half a dozen lines and just confused matters.

Whilst upgrading the code to remove the Containers unit (its not supported on NextGen platforms, so I have to make things work with Generics.Collections instead, bye bye D7 support for this code) and refactor a couple stupidities in my original design (they always creep in, don't they) I ended up with two class members of the same name.  The with block then looked OK but I was in fact not access the member I thought I was.  

I wasted a morning stepping and debugging a stupid error that would have been obvious had I avoided the WITH block.  In fact the error would never have happened if I hadn't used it in the first place.

Now why the heck won't my XE2 written unit tests compile in XE5? GRRRRRRRR!

Comments

  1. Two simple changes would make the with statement more bearable:

    1. Fix the freak'n debugger - with has been a part of the pascal language since it's inception in the early 70s. Absolutely no excuse for the debugger going silent inside a with statement.

    2. An ambiguous reference warning - with isn't the only place this would be useful. There are plenty of places where identifiers with the same name but different scopes can get confusing.

    ReplyDelete
  2. Agreed, but perhaps its time to move away from it?

    Actually I like the ambiguous reference idea, that would help with debugging things.

    ReplyDelete
  3. Kenneth Cochran About your second point: unless Delphi will get case sensitivity just please NO! I like to use unprefixed argument names (usually write them lowercase like f.i. count) that might have the same name as a property (Count). This would just produce unnecessary warnings.

    If they are going to change something that it's fine grained scoping of variables and introduction of something like using (or revamped with syntax). But that actually looks a bit weird with the way pascal defines variables (type after the identified).

    with x: TFoo := TFooBar.Create do
    try
      x.Baz;
    finally
      x.Free;
    end

    or with an interface where it gets niled after the with scope:

    with x: IFoo := TFooBar.Create do
      x.Baz; // after that x gets set to nil and thus TFooBar gets destroyed
    x.Something;  // compiler error, variable not defined

    ReplyDelete
  4. if the with is to remain, it would be a huge benefit to do away with support for multiple items in the with: with a, b, c do is beyond dangerous.

    ReplyDelete
  5. Was bitten by with just the other day. but saved by a "method not used" hint.  Turned out a that an event handler was named the same in the current scope, as for the with referenced variable, so 
    procedure TThisClass.Setup;
    begin
      with SomeObject do
      begin
        OnEvent := DefaultEvent;
        // lots of more setup
      end
    referenced SomeObject.DefaultEvent instead of TThisClass.DefaultEvent;
    leaving TThisClass.DefaultEvent unreferenced.

    ReplyDelete
  6. Stefan Glienke  - I'd like something like that, but can't the type of x be implicit? If you need a different type, you do the on the right side?

    with x := TFooBar.Create as TFoo do
    try
      x.Baz;
    finally
      x.Free;
    end

    as well as

    with x := Some.Long[z].Reference[y]
    do begin
      if not x.IsLevel
      then x.RotateTo(0);
      x.Rotate(Delta);
    end

    ReplyDelete
  7. having sorted my problem and gotten my unit tests to work again (which was not the problem I thought it was) I have once again been pleased at how useful the unit testing has been, mostly passed but a couple of things have cropped up as test failures which I probably wouldn't have spotted otherwise.

    ReplyDelete
  8. Lars Fosdal That is indeed a good idea - I like it!

    ReplyDelete
  9. Even if the ambiguous reference idea were only implemented within the scope of the with statement it would be a tremendous help.

    ReplyDelete
  10. Source code is for humans to read. With makes that more difficult.  I never use it, and become quite agitated when I have to deal with it in someone else's code.

    ReplyDelete
  11. Kevin Powick Any fool can write code that a computer can understand. Good programmers write code that humans can understand. --Martin Fowler

    ReplyDelete
  12. While I hate With, unfortunately some optimizations are only possible using it. Still, I would welcome it's permanent removal. A good start would be a compiler directive to treat it as an error.

    ReplyDelete
  13. What optimizations are you talking about?

    ReplyDelete
  14. Anthony Frazier For example if you have an array of records, and you need to access a couple of fields from one element.

    Using a local pointer-to-record variable mostly gets the same performance, but at least in my experience the compiler can be smarter when you use With.

    ReplyDelete
  15. I agree.   We have a lot of code here that have WITH statements.  And, being new to the system, I keep saying "withs are going to be the death of me".   That and pointers..

    ReplyDelete
  16. Asbjørn Heid Isn't the local temp variable /exactly/ what the compiler does with the with statement?

    ReplyDelete
  17. Anthony Frazier I don't have Delphi installed on this computer so I can't whip up an example, but I'm certain I've seen cases where the compiler did better registry scheduling when not using a local variable or use less temporaries. Something along those lines.

    A difference is that With has a limited scope that the compiler knows about, while a local variable technically lives for the entire function.

    I'll see if I can recall the case. Shouldn't be too hard to find a With in my code, it'll stick out as a sore thumb ;)

    ReplyDelete
  18. On my code, I tend to use With in a safe way, i.e.:

    procedure CreateForm( AClass : TMyFormClass );
    begin
      With AClass.Create( Application ) Do
      Begin
         ShowModal;
         Free;
      End;
    end;

    Other than that, I cringe any time I encounter a With :D

    A

    ReplyDelete

Post a Comment