"with" still sucks + removing features + adding features

Bill Baxter wbaxter at gmail.com
Mon May 18 11:05:13 PDT 2009

On Mon, May 18, 2009 at 10:46 AM, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org> wrote:
> Johan Granberg wrote:
>> BCS wrote:
>>> Hello Andrei,
>>>> I think "with" is a very dangerous feature due to the way it hides
>>>> symbols. It essentially makes the feeblest attempt at modular
>>>> reasoning utterly impossible:
>>>> int x, y;
>>>> with (whatever)
>>>> {
>>>> y += x;
>>>> ++x;
>>>> }
>>>> Maintenance of any type that is being used with "with" becomes a very
>>>> dangerous proposition because it can silently change meaning of code.
>>> I'd be willing to go the half way solution of making accessing a
>>> shadowing
>>> symbol an error, resulting in (loudly) not being able to access either.
>> I think this solution is a good idea but that removing or restricting
>> anything more regarding with is a bad idea as others have pointed out.
>> I'm using with quit a lot and it was one of thous things that attracted me
>> to D (I get the feeling that D has a quite pragmatic way of looking at
>> language features, if it's usefull lets have it unless it's harmfull to
>> other parts of D, sort of.).
> I personally still think it's a bad feature because it introduces
> long-distance coupling between symbols defined in two different places, both
> distinct from the place where the statement is used! Consider:
> import wyda;  // defines symbol write
> import geeba; // defines struct S { ... }
> void main()
> {
>   S s;
>   with (s) {
>      write(5);
>   }
> }
> Machiavelly would jump in joy at such code. What did I achieve? I saved a
> few "s.". What did I lose? The ability so say anything, but absolutely
> anything on what the code does.

Shouldn't the feature just follow the same rules as module imports do?

If I say
  import foo;
  import bar;
  void main() {

It's fine as long as foo and bar don't both define bar.  Why shouldn't
the same scope resolution mechanism not apply to with?

So in your example write(5) is fine as long as S and some module don't
both define a write().

I think that's what others were saying in the other thread, too.
Makes things more consistent too.   Given that do you still object to
with() so vehemently?


If S changes, the code may compile and run,
> yet doing something completely different. The dependency is not between the
> code as seen and wyda or geeba. It's between wyda and geeba, intermediated
> by "with"! I mean, if one _planned_ to design a maximally damaging language
> feature one couldn't come up with something better. And for what? Because
> you find it convenient to not type "s." a few times or just go in the
> blessed object and define a member? Is _this_ what makes or breaks your
> productivity? And are you willing to pay the ability to do the feeblest
> reasoning about your code for that doubtful benefit?
> This is so against every single good notion of language design, I kid you
> not I feel my blood pressure rising only as I think of it. No amount of "but
> I find it useful" can protect this awful non-feature. It should be taken in
> the back and shot in the head, no trial. Shoot the lawyer too if it has one.
>> On a similar note, Andrei, what is this spree of removing features? Ok
>> some
>> are obviously bad, imaginary types for example, but why remove other stuff
>> such as commplex and with?
> TDPL is coming out. This is quite literally the last chance to shed some old
> skin. Complex as a built-in does nothing of interest to anyone except a cute
> syntax for literals that nobody uses (how many remarkable complex literals
> could you imagine?) About "with"... see above before I die of a heart
> attack.
> The baroque "!<>=" operators became much more attractive since Walter said
> he's considering making them overloadable.
> On the other hand new features are coming, which I believe are "good skin".
> Narrowing integral conversions will go. Walter is working on a very cool
> scheme for inferring the range of expressions that makes casts unnecessary
> in many cases. Casts are a plague not only for safe code, but also for
> generic code that wants to be scalable and change-robust. The ease with
> which C and C++ allow losing state and the drowning necessity of integral
> casts in Java or C# are both extremes that I'm happy to see D avoid.
> Final switch works with enums and forces you to handle each and every value
> of the enum. Regular switch gets ranged cases by the syntax case a: .. case
> b: (I've always thought switch would be greatly helped by that).
> Static foreach might be making it too.
> Andrei

More information about the Digitalmars-d mailing list