The Dangers of With

I have known about the dangers of using the with statement for a long time now.  Today, I encountered a new one.  I was refactoring code in a datamodule used to iterate over a dataset and insert each record into the database (a common construct).  The numerous ParamByName() calls were enclosed in a ‘with query do’ and I received a run-time error in a FieldByName() call.  The FieldByName() was to be called on the dataset which was not yet part of a with clause so it resolved to the query and of course the field didn’t exist.  A classic problem with using FieldByName() exacerbated by the with statement.

The issue I didn’t expect, was when I tried to modify the with statement the XE4 IDE stopped responding.  I waited a few seconds thinking it would come back after the the parser finished.  It didn’t.  I decided to go for lunch…when I came back about 20 minutes later the IDE was still unresponsive and I had to kill the process.  Thankfully I have always enabled the Autosave options in the IDE, so I didn’t really lose any work.

10 Responses to “The Dangers of With”

  1. Jolyon Smith Says:

    I suspect it’s not a danger of “with” so much as a danger of the attitude toward it,

    The “anti-with” lobby has gained so much traction in recent years that I suspect that the engineers at Embarcadero now consider it a vestigial part of the language and so do not give it the attention it needs.

    “No one uses ‘with’ these days, so there’s no need to test the parsing/refactoring/whatever code with it [sic]“

  2. Peter Says:

    Not “with” is the enemy, but the low IDE quality since Delphi 2005.

  3. Kenneth Cochran Says:

    http://codeelegance.blogspot.com/2011/08/with-statement.html

    History of the feature, similarities to other language constructs, alternatives and one example of a language that got it right.

  4. Ghoy Says:

    I’ve been using it for years, not a lot but it comes useful. The irony is that most people don’t know when it should be used, or even how to use it properly. It’s not a statement to be taken lightly. I’ve personally never had a problem with the “with” statement.

  5. Justin Says:

    I don’t know why ‘with’ is to be deprecated. Unless it hinders internally some compiler optimizations or kind of showstopper to modernize the delphi compiler. For me, it is very useful and one of the language feature I longed when I’m working with other language. Saves a lot of typing especially when you want to instantiate/create visual components at runtime.

  6. Wouter Says:

    With is just a way to get even shorter shortcuts to access stuff.

    The problems that people run into is that they get confused by the actual scope of the code that they’re dealing with, but those exact same scoping issues exist on routine, class, method and unit levels.

    When you run 2 * x, you don’t know if x is a variable in a local subroutine, its outer subroutine, or a global variable. It might even reside in another unit, and in recent delphi’s, it might even be a struct with an implicit overload so that it acts like a float or an int.

    I’m happy that Delphi lets me shoot my own foot when I want to. If we want to get rid of all scoping confusion, we need to start writing ugly dotnet-like code, where you would write VCL.System.string because some idiot might have redeclared the string type somewhere.

  7. Wouter Says:

    Because people complain about the dangers of the with statement, i see the risk of having it removed from the language altogether, instead of getting bugs like the one mentioned here fixed.

  8. Jeroen Pluimers Says:

    I occasionally have such IDE hangs too while editing, usually with code completion induced by using a dot/period/point (.). More recent Delphi versions suffer less and less from this though. The hang manifests itself by the IDE taking 100% usage of 1 CPU core.

    I’m in the `with haters` camp (: http://wiert.me/2013/03/27/delphi-you-should-avoid-the-with-statement-as-it-makes-your-code-less-future-proof/ and I like http://codeelegance.blogspot.nl/2011/08/with-statement.html Thanks Kenneth for that link!

  9. Alister Christie Says:

    My recommendation is to never use WITH statements, it can make code shorter to write and easier to read, but sometimes very hard to debug and modify. The refactoring tools don’t work where WITH is concerned (although some could justifiably argue that they don’t work at all). Sometimes APIs are modified and this can cause really fun to find issues.

  10. Joseph Says:

    >With is just a way to get even shorter shortcuts to access stuff.

    At the expense of clarity and at the potential risk of bugs if the entity being used with the with statement changes its definition.

    There was a good example on another blog relating to graphics. The code was

    with whatever do

    and within the block x and y were referred to, which were variables outside the scope of the with statement. When the 3rd party library that contained the definition of whatever was updated, whatever gained x and y variables. Now, instead of the x and y assignment statements changing the outside variables x and y they were changing the new ones instead. Of course this code compiles but gives wrong results which took hours of exasperated testing before finally realizing that there were now x and y variables in the whatever object and with was using them.

    That’s the danger of with for a small amount of typing saved. Delphi could save lots more typing by gaining things like type inference without any potential drawbacks. Heck, it could stop implementing separate interface and implementation sections and needing to define object method headers twice and improve code size AND readability. Come to think of it, I could probably give you a dozen ideas about where we could much more safely save typing. :-(

    >The problems that people run into is that they get confused by the actual scope of the
    >code that they’re dealing with, but those exact same scoping issues exist on routine,
    >class, method and unit levels.

    The above example I cited had nothing to do with getting confused; it had to do with changing the definition of the object with is using. This would only affect a with statement.

    >When you run 2 * x, you don’t know if x is a variable in a local subroutine, its outer
    >subroutine, or a global variable.

    ? Sure you do, by seeing where it’s defined. It’s a lot clearer in a statically typed language like Delphi than a dynamically typed one.

    >I’m happy that Delphi lets me shoot my own foot when I want to.

    There’s a difference between power and something that doesn’t offer any advantages while having potential disadvantages. With doesn’t let you do anything extra in the language; it’s only a syntax shortcut, so that doesn’t apply here.

    > If we want to get rid of all scoping confusion, we need to start writing ugly dotnet-like >code,

    Have you looked at Delphi lately? The boilerplate in the language just keeps growing and what isn’t growing is starting to look positively ancient. Let’s not throw stones.

    >where you would write VCL.System.string because some idiot might have redeclared
    >the string type somewhere.

    You can indeed use similar syntax now in Delphi to deal with different units using the same name. It should be used anywhere ambiguity in the code exists.

    What would be nice is something like Python’s handling of imports.

    import math

    does require you to use math.random, etc.

    from math import random

    This style statement lets you choose what to port from modules (very nice!) and anything imported this way does not need to be qualified by the name of the module it was imported from. Importing this way one is hopefully choosy and aware of any duplicate name issues.

    from math import *

    This imports the whole unit but doesn’t require you to qualify names. It is discouraged in the style guide but can be useful for doing some work at the command line (obviously not an issue with Delphi).

    And now we come to this bit of awesomeness….

    from math import random as new_random

    You can change the name of things you import! This is a great way to deal with duplicate name issues or use a class that is compatible with some existing code you have but has a different name.

    You can even do this (just learned this yesterday):

    def SomeFunction(a, b, c):
    from math import random
    …….

    Imports can even be limited in scope to a function/method! I presume this works at the class level as well.

    If we could gain abilities like that, it would really make managing Unit imports easy.

Leave a Reply