with
statement's intended purpose is to reduce repetitive typing. Some developers think its the greatest thing since sliced bread. Others are certain it was created by Satan. Let's examine a few languages that support it.Pascal
Thewith
keyword was present in the original Pascal language, developed in 1968-70 and published in Acta Informatica, Vol. 1 in 1971. I've found no description of a with
statement in Wirth's prior language projects or in any of the languages which influenced Pascal's design. Though admittedly, my research into its origins is limited. I'll assume for the moment that it was an original idea.
The
with
statement was originally intended to only be used with record variables. Here's a modification of a sample record from the original language description.
type
Date = record
day: 1..31;
month: 1..12;
year: 0..9999;
end;
var
today: Date;
The two following blocks are equivalent:
begin
with today do
begin
day := 25;
month := 12;
year := 2011;
end;
end;
begin
today.day := 25;
today.month := 12;
today.year := 2011;
end;
Object oriented descendants of Pascal added support for classes and interfaces. The main criticism of
with
is that it introduces the possibility of ambiguous references:var
day: integer;
today: Date;
begin
with today do
begin
day := 25;
month := 12;
year := 2011;
end;
end;
Which day
is being assigned to? Intuition may lead you to think that it is the one within the scope of the date
record and you'd be right, at least in this case. However, when this block is in the body of an object method, which references multiple other objects in the same with
statement it isn't so clear.
Where things really fall apart is when you are referencing a local variable from within the body of a
with
statement and a field or property with the same name is added to the definition of the object or record referenced by the with
statement. Suddenly code that was working flawlessly fails and all you did was add a field to a class definition. Heck, you haven't even referenced the new field in your code yet... or so you think.So that's Pascal's implementation. I would recommend you avoid using it whenever possible and use great care if you find it necessary to use it. What other languages support the
with
statement? Let's take a look.VisualBasic
With today
.day = 25
.month = 12
.year = 2011
End With
Here we see dot notation preceding the fields. This makes it apparent which identifiers are fields and which are not. This syntax was carried forward into VB.NET as well. There is still the possibility of ambiguity if you write a nested
with
statement. According to the documentation the compiler would only see the fields of the object referenced by the inner with
statement until the statement's end. A novice developer could easily overlook this.JavaScript
JavaScript's
with
statement functions more or less the same as Pascal's and JS developer's opinions of it are just as polarized as Pascal developer's. ECMAScript 5th Edition "Strict" mode forbids its use and many implementations now emit a warning that it has been deprecated and/or suggest an alternative.D
Digital Mars' D language supports a
with
statement with behavior similar to Pascal's with one notable exception: local identifiers and identifiers within the scope of the with
statement cannot have the same name. This results in a compilation error, effectively preventing the ambiguity caused by the introduction of new object members.
struct Date
{
int day;
int month;
int year;
}
void main()
{
int day;
Date today;
with (today)
{
day++; // error, shadows the local day declaration
}
}
Languages with similar features
These languages have similar features but the purpose and/or syntax is too different for them to be consider the same as
with
.- Smalltalk cascades - multiple messages can be sent to the same object separated by a semicolon
- C#
using
statement - encapsulates the more verbose try..except..finally syntax when working with implementors of IDisposable- object and collection initializers - a more concise syntax for setting object properties at creation time
- Python
with
statement - similar to C#'s using statement, it encapsulates the try...except...finally pattern into a less verbose syntax.
Fluent Interfaces are another programming style that can be used to accomplish the same goal as
with
statements. They use varying combinations of method chaining, nested functions and object scoping along with careful method naming to produce concise, readable statements. The Date record could be rewritten as:type
Date = class
private
FDay: 1..31;
FMonth: 1..12;
FYear: 0..9999;
public
function Day(Day: integer): Date;
function Month(Month: integer): Date;
function Year(Year: integer): Date;
end;
function Date.Day(Day: integer): Date;
begin
self.FDay := Day;
Result := Self;
end;
function Date.Month(Month: integer): Date;
begin
self.FMonth := Month;
Result := Self;
end;
function Date.Year(Year: integer): Date;
begin
self.FYear := Year;
Result := Self;
end;
Then in place of the with
statement you could write:begin
today := Date.Create
.Day(25)
.Month(12)
.Year(2012);
end.
When I started coding in Pascal (probably somewhere 1987) I also thought using "with" was as easy as sliced bread.
ReplyDeleteBut once you start copying / pasting code blocks and get some code fragments out of their context, the "with" statement is indeed a devil! I have been burnt many times by it, so I put a "personal ban" on that statement.
However, there are tons of KB in my repository and every now and then I still need to kill one :) Comes together with the "hanging begins"..
Kind regards, Nils