With Blocks

A "with block" is a form of SyntacticSugar -- a way of saying "I'm going to do a couple (or a bunch) of things with this one instance of this structure/record/class, so please assume that the following method/property/field accesses are relative to this object."

See also WithBlockCodeSmell -- largely an argument that you shouldn't use WITH blocks.


[VisualBasic]

In VisualBasic and most variations, one can simplify the syntax of multiple method/property calls to the same object, like this:

  With ActiveDocument:
    .SaveAs "backup.doc"
    Set HeaderTable = .Tables(1)
    Set AddressTable = .Tables(2)
    Set InvoiceTable = .Tables(3)
  End With
  HeaderTable.Select   ' selects ActiveDocument.Tables(1)

Unfortunately, VbScript doesn't have With blocks, making this kind of code much uglier, and perhaps even slower (see the bit on dereferencing in Pascal below).


[PascalLanguage]

PascalLanguage has had "with" statements since the very beginning, and they're still present in current implementations, such as Borland's DelphiLanguage. On the plus side, they can make the code much more readable. On the minus side, they can lead to bugs that cause you to tear your hair out, because you can't see what's right in front of you, namely that the variable named Foo is actually SomeObject.Foo and not the outer-level Foo that you think it is. I've pretty much given up on using "with" in my own code, although there are times when I look wistfully at a tedious-looking block of code and consider relenting.

(aside: Visual Basic gets around this problem by assuming that all variables are specified as usual, only assuming an object member if the name is preceded by a dot.)

There used to be another advantage for using "with": If you had some (Delphi) code that looked like this...

  MyObject.Foo := 42;
  MyObject.Bar := 'forty-two';
  MyObject.Baz := MyOtherObject.Baz;
then the compiler would have to dereference the MyObject pointer for each and every statement. Using "with" meant doing the dereferencing only once:

  with MyObject do begin
    Foo := 42;
    Bar := 'forty-two';
    Baz := MyOtherObject.Baz end;
But nowadays, the Delphi optimizer is smart enough to factor out the pointer dereferencing, even if you write code that looks like the first example. -SteveSchafer

Err... how can a "with" block remove the dereference of the MyObject pointer? I can see how the code below could reduce pointer dereferences by caching the value of O1.O2.O3 and avoiding multiple dereferences through O1 and O2, but in the code above I cannot imagine how use of the MyObject pointer could be avoided.

  with O1.O2.O3 do 
  begin
    Foo := 42;
    Var := 'forty-two'
  end
The "with" block doesn't eliminate all dereferencing of the MyObject pointer, only the redundant dereferencing. Let's look at what goes on when accessing MyObject.Foo (we'll assume that Foo is a simple field of the object). MyObject is a variable that holds a pointer to the actual object instance, allocated on the heap. Given

 MyObject.Foo := 42;
this is the code generated by the Delphi 5.0 compiler:

 mov eax,[MyObject]  // get the value of the pointer to 
                     // MyObject into the EAX register
 mov [eax+32],42     // offset that value by 32 to get to the Foo field,
                     // then store the value 42 into that location
Now, in the naive (Delphi 1.0) implementation, repeated references to MyObject.<whatever> would cause the EAX register to be reloaded from the MyObject variable each time, whereas a "with" block would cause it to be loaded only once. Since Delphi 2.0, the compiler's optimizer has been able to figure out that it doesn't need to do the repeated register reloads, even without the "with" block. -ss


[CobolLanguage]

COBOL has "MOVE CORRESPONDING source-structure TO destination-structure" which copies the values of all fields with the same names, recursively. This is not the same as a PascalLanguage/VisualBasic "with" statement, but in some ways it's a related concept.


[SmalltalkLanguage]

SmalltalkLanguage has semicolons for this purpose:

 Transcript show: 'a'; show: 'b'.


[CeeLanguage, CeePlusPlus and other block structured (AlgolFamily) languages]

In C++, and most other languages, you can create an extra locally-scoped variable to hold the common subexpression:

    {
         Document *d = activeDocument;
         d->SaveAs( "backup.doc" );
         d->SetHeaderTable( tables[1] );
         d->SetAddressTable( tables[2] );
         d->SetInvoiceTable( tables[3] );
    } // d goes out of scope here.
It just comes out with the wash if you write short functions. This would become a function with a signature like:
    void SetTables( Document *d, const Table tables[3] );
and called with activeDocument as argument.

or

  activeDocument->SetTables(tables);  //at which point you should see why with smells.

[see WithBlockCodeSmell]


[PythonLanguage]

As in C++, you can create an extra variable to hold the common subexpression. Yet, unlike C++, there are no curly braces in Python to limit its scope and name visibility.

 # reference to object
 annoyinglyLongNameForActiveDocument = Document()

# new reference to existing object d = annoyinglyLongNameForActiveDocument d.saveAs('backup.doc') d.setHeaderTable(table[1]) d.setAddressTable(table[2]) d.setInvoiceTable(table[3]) # delete d from namespace now (GarbageCollection happens later) del d

# object and long reference still exist annoyinglyLongNameForActiveDocument.saveAs('backup.doc')

Although it's perfectly doable, using this construct could indicate poor design in your program (WithBlockCodeSmell).


[RubyLanguage]

I know of instance_eval in RubyLanguage, but I suspect it's not a true analogue of the above.

True, but you can easily write this:

 def with(obj,&block)
  obj.instance_eval &block
 end
 with 'foo' do
  puts size #=> 3
  puts self #=> foo
 end
Nice showing of blocks' power, ain't it?


[JavaScript]

In JavaScript you can use "with". The runtime will search the provided object for fields and methods before searching the normal search path:

 with ( activeDocument ) {
     saveAs("document.doc");
     setHeaderTable( tables[0] );
     setAddressTable( tables[1] );
 }


[CommonLisp]

 (with-slots (a b)
     obj
   (setf a 1
         b 2))

You can avoid any aliasing problems by renaming the slots. eg.

 (let ((a 42))
   (with-slots ((aa a) b)
       obj
     (setf aa 99
           b 2))
   (values a (slot-value obj 'a))) => 42, 99

with-accessors is also available. with-accessors works the same way but deals with the object's accessors (generic functions) rather than directly with the instance variables.


[IoLanguage]

Object (the top-level prototype) provides the do message, which evaluates all its contents in that object's scope. Often used to produce the analogue of a class definition:

  NewObj? := Object clone do (
    method_one := method(do_stuff)
    method_two := method(do_other_stuff)
  )


Is there anything similar in other languages? PerlLanguage's DollarUnderscore construct? or is that another can of worms? Yes, Perl is a can of worms.

Perl is a cannery of worms.

Perl can worm its way out of anything.


EditText of this page (last edited August 14, 2011) or FindPage with title or text search