views:

653

answers:

6

Hi, is there a way to reference an object instance that is created using the "with" statement?

Example:

with TAnObject.Create do
begin
  DoSomething(instance);
end;

Where DoSomething would use the instance reference as if you were passing an instance from a variable declared reference to the object created.

Example:

AnObject := TAnObject.Create;

Thanks.

+11  A: 

You should never use with either because future changes might introduce more into that scope than you intended.

Take this for instance:

procedure Test;
var
    x: Integer;
begin
    with TSomeObject.Create do
    begin
        DoSomethingWithX(x);
        Free;
    end;
end;

and then later on you tuck on a X property on the TSomeObject class. Now, which X do you think it's going to use? The local variable or the X property of the object?

The best solution is always to just create a local variable with a short name, and alias the object to that variable.

procedure Test;
var
    x: Integer;
    o: TSomeObject;
begin
    o := TSomeObject.Create;
    o.DoSomethingWithX(x);
    o.Free;
end;
Lasse V. Karlsen
Also see http://stackoverflow.com/questions/71419/whats-wrong-with-delphis-with
Lars Truijens
Ok, i'll bite :-) 'with' can cause major confusion if you're not careful, but there are situations where it just makes code a lot more readable. Careful naming can be of some help here. Using naming schemes to avoid confusion is a common technique for Delphi code anyway (use TXxx for types, FXxxx for private members, GetXxx and SetXxx for getters and setters, etc). Just use MyXxx or something similar for local variables and you won't have as much confusion as you would have by calling variables "x" and "o".
Wouter van Nifterick
I would not trade the few cases where it *might* make it more readable for those occasions where I've been bit by the auto-scope feature of it. I have literally wasted weeks on problems related to this. No code can be justified as so readable that it's worth that much time in order to find odd bugs.
Lasse V. Karlsen
I agree on not using with. But I would advise to use a try after the create and a finally before the free.
Gamecat
That is good advice as well.
Lasse V. Karlsen
+9  A: 

Well, you can use such approach:

// implement:

type
  TSimpleMethod = procedure of object;

function GetThis(const pr: TSimpleMethod): TObject;
begin
  Result := TMethod(pr).Data;
end;

// usage:

  with TStringList.Create do
  try
    CommaText := '1,2,3,4,5,6,7,8,9,0';
    ShowText(TStringList(GetThis(Free)));
  finally
    Free;
  end;

or class helpers:

type 
  TObjectHelper = class helper For TObject
  private
    function GetThis: TObject; Inline;
  public
    property This: TObject read GetThis;
  end;

...

function TObjectHelper.GetThis: TObject;
begin
  Result := Self;
end;

But, actually, previous replies are correct: you should better forget about "with" statement.

Alexander
+1 :) None of this helper stuff existed way back when I was originally doing Delphi.
altCognito
+1 for insane usage of Delphi :)) Great!
gabr
Thanks :D
Alexander
funny to see this, as I wrote this blog post last week to be scheduled next week (when I will be really busy finishing up and preparing my leave for the Delphi Live! conference):http://wiert.wordpress.com/2009/04/27/delphi-bizarre-use-of-class-helpers-to-circumvent-with/PS: pitty I can't read Russian and the google Russian -> English translator forgets a lot while translating your very interesting blog!
Jeroen Pluimers
Bevare that declating a helper for TObject would break any existing helper for TObject. There can only be one helper for each class.I don't like helpers...
Vegar
A: 

Thanks guys. I will avoid using "with" when creating an object.

yozey
It is better to avoid using "with" at all times not just when you are creating objects - else your code will be hard to debug see http://stackoverflow.com/questions/312321/debugging-problems-with-with-statement-in-delphi-2006
Charles Faiga
A: 

I've learnt the hard way - only use 'With' in the following scenarios:

With TMyForm.Create( Owner ) do
  try
    ShowModal
  finally
    Free;
  end;


procedure Notify( Sender : TObject );
begin
  With Sender as TSomething do
    VerySimpleProperty := Something      
end;

i.e keep the visibility of With as simple as possible. When you take into account the fact that the debugger cant resolve 'With', it's actually better and clearer to use a simple local variable or to fully declare the target i.e MyRecord.Something

Brian Frost
+2  A: 

You gave the answer yourself: declare local variable. If you want you can use the with keyword on that.

var
  MyInstance: TMyObject;
begin
  MyInstance := TMyObject.Create;
  with MyInstance do
  try
    Foo;
    Bar;
    DoSomething(MyInstance);
  finally
    Free;
  end;
end;

In above example the only reason to use with is code readability, which is very subjective, you could also ditch the with keyword and use MyInstance directly. It's just a matter of personal taste. I don't agree on the "never use with" answers, but you should be aware of it's drawbacks.

See also this question: Is delphi "with" keyword a bad practice?

The_Fox
+2  A: 

An addition to Brian's example on a Notify handler is to use an absolute variable (win32 only):

procedure Notify( Sender : TObject ); 
var 
  Something : TSomeThing absolute Sender;
begin 
  if Sender is TSomething then 
  begin
    VerySimpleProperty := Something.Something;
    OtherProperty := Something.SomethingElse;
  end;
end;

It basically avoids having to assign a local variable or have a lot of type casts.

Gerry
+1 for attending us on the use of 'absolute' (which long ago was introduced for absolute memory references, but your example is the only usage that is compatible with both the .net and the native world).
Jeroen Pluimers