RemObjects' Chrome is an innovative
implementation of Object Pascal for Microsoft's Visual
Studio .NET. Huw
Collingbourne wonders if this could this really
be the rebirth of the Pascal language?
See also: The Bitwise interview
with Chrome chief architect, marc
hoffman. |
These days, C-like languages seem to
have swept through the developer world like the Mongol
Hordes, crushing all other languages that should dare
to cross their path. From the baroquely complex C++ to
the simplified syntax of Java and its .NET cousin, J#,
curly braces and plus-plus operators have become almost
inescapable. When Microsoft created a new language, C#,
specifically for the .NET platform, it really looked
as though other syntaxes might as well admit defeat.
Not
even that old warhorse, Visual Basic, was entirely
welcome in
the brave new world of .NET. So what hope for Pascal…?
Chrome 1.5 integrates with Visual Studio 2003 or
2005 (some features are only available in VS 2005)
and supports application development using .NET 1.1,
.NET 2.0, the .NET Compact framework and Mono. |
The Chrome IDE
There is nothing surprising about the Chrome development
environment. Hosted by Visual Studio, it has all
the form design and coding features that you would
expect
You have access to the Visual Studio debugger
so that you can easily set breakpoints, watch variables
and step through Chrome code
In the editor, you can complete
code statements (here in a sample project illustrating
Chrome’s
Generics) by selecting items from drop-down lists |
In modern times, one company alone has really championed
Pascal. In spite of flirtations with languages ranging
from Prolog to C++ (and a long term relationship with
Java), Borland is, perhaps, pre-eminently The Pascal
Company. In the early days Borland built its reputation
on its Turbo Pascal compiler for MS DOS. Over the last
decade or so, its fine Delphi product has put an object
orientated version of Pascal at the core of a suite of
visual design and coding tools for Windows.
With the advent of .NET, many vendors chose
to integrate their languages into Microsoft’s
Visual Studio. Borland, however, decided to host Delphi
within its own multi-language programming product called
The Borland Developer Studio (see the
Bitwise Review).
This meant that Visual Studio users were left without
a full, professional Pascal implementation. That is,
until RemObjects launched a Chrome – a version
of the Object Pascal language for Visual Studio. Launched
for Visual Studio 2003 last year, Chrome is now on
version 1.5 which also supports Visual Studio 2005.
In this review, I’ve been trying
to find out what sets Chrome apart from other .NET languages.
Life After Delphi?
As you might expect, a long-time Delphi programmer
(like me) will quickly feel at home when coding in
Chrome. To take a simple example, let’s suppose
you create a new Windows application that displays ‘Hello
world’ in textBox1 when button1 is
clicked. You begin the process by selecting the Chrome
Windows Application template. This loads up a blank form
into the Visual Studio workspace. Onto this you drop
a button and a Textbox and double-click the button to
go into the editor and add some code.
Your cursor is now placed inside this event-handling
method:
method MainForm.button1_Click(sender: System.Object;
e: System.EventArgs);
begin
end;
Now, between the begin and end keywords, you insert
this simple Object Pascal assignment:
textBox1.Text := 'Hello world';
And that’s it. A ‘Hello world’ program
in one line of code. If you glance at the code which
Chrome has automatically created for this project, you
will see much in common with Delphi. There’s the
interface section for declarations at the top of the
unit and the implementation section for executable code
beneath it. The form definition block is similar to Delphi’s
with its type declaration and private, protected and
public methods.
Chrome is far from being a slavish Delphi ‘clone’ however.
Already one difference is obvious. The button1_Click()
method is declared using the keyword method rather
than the keyword procedure as
in Delphi. In Chrome, a procedure or a function can be
declared as a method though
the keywords procedure and
function are also
available as alternatives. In the above code, for example,
if you replace the method keyword
with the procedure keyword
the code will still compile.
It Takes Two…
When installed into Visual Studio 2005, Chrome supports
a number of features specific to version 2 of the .NET
Framework such as generics to allow you to code type-safe
list processing routines which can be used with lists
of varying data types. This lets you write (say) one
sorting or reversing routine for use with lists of
strings, integers or user-defined objects. Without generics
you would either have to write multiple routines or do
a great deal of type checking and casting. A generic
routine is initialised to a specific object type when
it is used to ensure reliable type checking. You can
create your own for each loops to enumerate through generic
lists.
There are also nullable types which allow you to assign
a nil value to types for which nil has hitherto not been
available. So you can, for example, set an integer or
a Boolean to nil (indicating that it is unknown or undefined)
rather than merely to something like -1 or false to indicate
a precise and fixed value.
As with Microsoft’s languages for .NET 2.0, Chrome
1.5 lets you use ‘nested’ classes in which
one class is restricted for use ‘inside’ another
class. Chrome also provides this feature for .NET 1.1,
if you happen to be using VS 2003. Let’s see how
this works. Let’s suppose you have a Room class
and a Treasure class. This is how you might define your
Room:
Room = public class
private
t
: Treasure;
_name
: string;
public
property
name: string read _name write _name;
property
treasurename: string read t.name write t.name;
constructor(
aName, aTreasureName : String );
end;
Rooms can exist anywhere but Treasure objects
can only exist in Rooms. You don’t want them
to be accessible by Troll and Dragon classes, for instance.
To make this so, you declare the Treasure class to
be nested in the Room class like this:
Treasure nested in Room = public
class
private
_name
: string;
public
property
name: string read _name write _name;
constructor(
aName : String );
end;
Now, if you try to create Treasure object
outside of a Room, the compiler will complain that
Treasure is an unknown type. Inside a Room object,
however, Treasure is a valid type; if you need to access
the class from outside a Room you can use dot notation
like this:
var
aTreasure : Room.Treasure;
Another new feature in Chrome 1.5 is ‘variable
type inference’. This means that it is possible,
in some circumstances, to omit type declarations of
variables. By tradition Pascal, being a strongly typed
language, requires variable names and types to be specified
in a var block before used in code, like this:
var
x : Integer;
begin
x := 2;
textBox1.Text
:= x.ToString();
end;
Chrome lets you use this shortcut type-free variable
definition:
begin
var x := 2;
textBox1.Text :=
x.ToString();
end;
I must say that I can’t honestly see much
point in this. I have always thought that distinct,
unambiguously typed variable declaration blocks were
a strength rather than a weakness of Pascal. However,
other people will doubtless disagree with me.
You can also declare inline variables within for loops
as here:
for i: integer := 1 to 10 do
x
:= x + 1;
There are too many syntactical differences from standard
Pascal or Delphi to enumerate fully here. A few things
which have struck me include case statements in which
the selector can be a string; case
type of in which a
selection is made by matching the specific type of a
variable rather than its value; and with statements in
which inline variables are used and objects may be created,
like this:
with r: Room := new Room() do begin
r.name
:= 'Bright cave';
r.treasurename
:= 'Torch (on)';
end;
Other notable language features of Chrome include
full namespace support – the scope of a single namespace
may extend across several code ‘units’; asynchronous
methods for multi-threading; partial classes allowing
a single class definition to span multiple files; and
operating overloading A full list of Chrome’s principal
language features can be found here: http://www.chromesville.com/language/.
The Compact Framework?
On the Chrome web site, you will read that Chrome
can be used to write “fully managed native
.NET applications for the Microsoft .NET Framework,
the Compact Framework or the Mono and Portable.NET
platforms”.
Well yes, it can. Up to a point. I should say
that I have only been using Chrome for the .NET
platform so I have to take on trust that it works
well with Mono and Portable .NET. However, I remain
unpersuaded that Chrome would be my language of
choice for Compact Framework development. I was
expecting to be able to start a Chrome ‘Smart
Device’ Wizard,
as I can with C# and Visual Basic; in those languages,
this gives me access to a full suite
of visual design and debugging tools including
a set of on-screen ‘emulators’ for
testing applications on my PC prior to downloading
them into a hand-held device. Chrome has
no such wizards. Instead, you are supposed to develop
applications in Visual Studio and link against
Compact Framework assemblies subsequently, in the
same way that you might link to Mono or Portable
.NET. While the Chrome web site optimistically
describes this procedure as “almost too
easy”, the Chrome help system does (if you
search hard) admit to significant deficiencies
in its support for CF design and deployment:
“At
this time, Chrome does not support automatic deployment
to CF. You will need to copy file(s) across using
ActiveSync and run the applications manually on
the device. There is no current support
for the Form Designer or Debugger - these are
under investigation for a future release.”
In short, while you can design CF applications
with Chrome, I cannot imagine why anyone should
choose to do so given the hugely superior tools
provided by C# and VB.NET. |
Contractual Obligations
The Chrome language also includes a rather unusual
feature called ‘Class Contracts’. This is similar
to the ‘Design By Contract’ features of the
Eiffel language; RemObjects claims that Chrome is the
first mainstream .NET language to provide native support
for this.
Class Contracts aim to provide a mechanism for enforcing
requirements upon a class and its methods rather than
merely stating those requirements in the specification
or comments. This is how RemObjects describes
the problem:
“In classical programming,
even for today's object oriented programming, such
requirements are usually specified in documentation
somewhere (if documentation is written at all), or
might even just exist in the mind of the developer.
Sooner or later, the code will outgrow the specification
and requirements will be broken.”
To avoid the possibility that documented requirements
may be ignored, the requirement itself is entered into
the code itself like this:
method MainForm.test_contract(aValue : Integer)
: Integer;
require
aValue >=0;
begin
end;
In the above example, while it is possible to
send a minus value as the aValue argument,
the code that follows will, in such a case, produce
an invalid result. The require statement
tests the value and, if it is less than zero, an error
condition (which is called an ‘assertion’ but,
to all intents and purposes, resembles an exception)
is raised. You can also add an ensure condition
at the end of a method to test the value of some variable
when the method exits, like this:
method MainForm.test_contract(aValue : Integer)
: Integer;
begin
ensure
aValue > 0;
end;
Class contracts also let you define required
values (invariants) for properties. Don’t get
the idea, however, that class contracts somehow ‘fix’ potential
errors. They don’t. The require and ensure parts
are debugging aids. When their requirements are not
met, an error occurs and it is up to the programmer to
fix it.
Let’s look at another example. Suppose
our Room object has multiple constructors, each of which
take varying numbers of arguments to initialise internal
data. One constructor initialises only the Room itself
but not the Treasure object, a_treasure,
which it contains. It is quite possible that a certain
Room will not contain an initialised Treasure object.
So what happens if such a Room is passed to this method?
method MainForm.ShowRoom( aRoom : Room );
begin
Messagebox.Show('Room:
' + aRoom.name + ' contains: ' +
aRoom.treasurename);
end;
In fact, this is what happens:
You get a pretty uninformative error message
and you now have to squirrel away through your code
in order to try to track down the source of the problem.
Now let’s
try this again with this rewritten method:
method MainForm.ShowRoom( aRoom : Room );
require
aRoom.a_treasure <> nil;
begin
Messagebox.Show('Room:
' + aRoom.name + ' contains: ' +
aRoom.treasurename);
end;
This time, this is what happens;
OK, so it’s still an error message. But at least
it’s an informative one. The screenshot above is
too small to read all the text - and the error message
box is too big to fit comfortably onto this web page,
so here’s a close-up of just a part of the text:
As you can see this gives you some useful information – not
least of which being the method name and the precondition
which failed. My feeling is that, while class contracts
are a handy way to document and debug your code, they
are no more than that. Careful programmers would, in
any case, test values before executing code or use exception
handling for trapping unpredictable errors. That said,
the more debugging the better so they are to be welcomed.
The Development Tools
Chrome’s programming environment is Visual
Studio so, if you are already familiar with this, there
is no much more to be said. It has the same form designer
and coder with code-colouring, collapsing, IntelliSense
and all the rest. Other editing features include easy
navigation between a class declaration and implementation
and class-completion which adds implementation code
to match the class definition.
Chrome can take advantage
of Visual Studio tools such as the improved form
designer available in VS 2005 with its visual alignment
guides to help you fine-tune the position of controls
Some editing capabilities are supplied by a free third-part
tool called DXCore from
Developer Express . One of the more obvious of these
capabilities is synchronised renaming. When your cursor
is in the name of an identifier such as a method or class
type it causes the identifier to be highlighted and any
change you make to its name causes the same change to
be made to all other occurrences of the name in your
source code. At first sight this looks like a good idea.
In fact, I find it to be more of a hindrance than a help.
Here I am changing the name
of the class Room. When I edit it in one place the
changes instantly propagate to all other occurences
of the class name.
Let’s suppose you have a class called Room and
you want to change its name to MyRoom.
To do this you simply edit any occurrence of the name Room and
all other occurrences are kept in sync. But now let’s
suppose you have a nested class, Treasure,
which is inside Room.
Now you edit the constructor name, Room.Treasure().
As soon as your cursor lands upon the name Room,
it is automatically highlighted. Now when you add .Treasure all
other occurrences of Room have .Treasure appended
to them – not at
all what you want to happen! Similar problems arise if
you specifically want to edit just one occurrence of
the identifier, Room.
While you may not see it happening, all the other references
to Room scattered through your code will also be altered.
To be fair, I should say that you can ‘break
the link’ to prevent synchronised renaming by pressing
the Enter key when an identifier is highlighted. If (like
me) you often forget to that that, however, you can accidentally
mess up your code big time. As far as I can work out,
there is no way to disable Sync Editing without uninstalling
DevExpress itself – something I plan to do soon.
While the editing features, on the whole, are
comparable with those offered by other Visual Studio
languages, I did notice one or two rough edges. The
code alignment, for example, is a bit eccentric. When
you press the Enter key after a begin keyword,
the next line is indented, even if it happens to be
the
end keyword. The end part
of a begin block
has to be aligned manually. Moreover, the alignment
process is a bit slow (you can see it happening on
screen). This contrasts with Microsoft’s C#,
which correctly and quickly auto-aligns begin and end
braces and indents any enclosed code. RemObjects tells
us that improvements to code alignment are planned for
a future release.
Mono and Portable .NET
In addition to .NET programming, Chrome also can
be used for creating Mono and Portable .NET programs.
Mono is the name of
an open source project aimed at providing software
for developing and running .NET applications on
Linux, Solaris, Mac OS X, Windows and Unix. It
is sponsored by Novell. At the time of writing,
Mono is at version 1.1.13. RemObjects says that “In
general, applications compiled with the normal
.NET framework will deploy just fine for Mono.”
Portable
.NET is the name given to an open source implementation
of tools and libraries compatible with the .NET
CLI (Common Language Infrastructure). Developed
by the DotGNU Project, it aims to operate on multiple
platforms including Windows, Linux, Mac OS X and
others. Portable .NET is still in development but
has not yet reached a version 1.0 release. Chrome
1.5 claims “tentative support” for
Portable.NET. RemObjects says “our
testing under pnet has been limited, so it is not
considered an officially supported platform at
this time.”
To develop Mono and Portable .NET applications
you can create .NET Chrome projects within Visual
Studio and then link them against other CLR assemblies
(e.g. Mono or Portable .NET) for deployment. This
is explained
in more detail on the Chrome web site. |
Summary
For anyone used to Pascal, particularly Delphi, the
Chrome language has the obvious attraction of familiarity.
Since (unlike Delphi) it is hosted by Visual Studio,
new releases are rapidly able to make use of innovations
in .NET itself. This explains why Chrome 1.5 already
works with .NET 2.0 whereas the current release of Delphi
is still restricted to .NET 1.1. Moreover, if your company
is already using Visual Studio .NET you may
encounter less resistance to the idea of evaluating a
fairly low cost language plug-in for Visual Studio than
to the idea of investing thousands of dollars on the
Borland Developer Studio.
That said, the question has to be asked: what
is Chrome for? In the past, the distinctions between
various language and development tools was pretty clear
cut. If you wanted to do efficient, low-level programming,
C or C++ was likely to be your first choice. For ‘safer’ programming
with good visual design tools, Visual Basic would have
been preferred. And then, of course, there were those
farsighted developers who demanded the best of both
worlds – real
programming power plus excellent visual design tools – and
that’s where Delphi came into the picture.
These days, the choices are not so clear cut.
This is particularly so once you enter the world of
.NET – in
which the same class library, visual design tools and
runtime system are shared by a multitude of languages.
As a consequence, when choosing a .NET language, I suppose
the first question that many people will ask may be:
why should we use anything other than C#?
Microsoft created C# from the ground up specifically
for .NET. Just to rub salt into Pascal programmers’ wounds,
the chief architect of the language was none other than
the creator of Delphi, Anders
Hejlsberg. Now, while Pascal
programmers may have some aesthetic objections to the
syntax of C# (I myself am far from being seduced by the
curly braces, case sensitivity and peculiar for loops),
fundamentally it is a perfectly good language – in
essence, it is the ‘standard’ .NET language;
and, anyhow, if you have a full copy of Visual Studio,
you already have C#.
So why would you want to use any other language? In
my opinion this is a question to which even Microsoft
itself has found no good answer. Its attempts to convince
people of the merits of Visual Basic .NET are unconvincing.
Previous versions of VB had distinct advantages over
C++. The present version of VB.NET has no significant
advantages over C#.
In spite of some interesting language extensions
in Chrome, I can find no truly compelling reason to
use Chrome in preference to C#. By ‘compelling reason’ I
mean something which you could tell your boss in order
to convince him or her that Chrome was a definitively
better .NET language than C#.
Delphi at least can offer such a reason: its
ability to span the Win32 and .NET platforms provides
developers with a unique way of migrating existing
applications to .NET or embarking upon simultaneous
development of ‘cross
platform’ (Win32 and .NET). It is, of course, possible,
that Chrome’s ‘cross platform’ support
for Mono and Portable .NET may have a similar appeal
for some developers. For an example of a project utilising
Chrome for cross-platform development, see the Chrome:Portal Content Management System site.
It is too early to predict how well Chrome will succeed
for this kind of development.
Delphi developers who have moved to .NET may
be tempted by Chrome mainly due to the close similarity
of its Object Pascal syntax to that of Delphi’s
Object Pascal. Moreover, if you are already using Visual
Studio, you can add in Chrome for around $240 whereas
even the ‘entry
level’ edition of Delphi will cost you in excess
of $1,000. Don’t think that you will simply be
able to import old Delphi projects, however. You may
be able to cut and paste a good chunk of Delphi code
but Chrome does not offer full Delphi compatibility so
it’s not just a case of ‘load and run’.
For most people, the main reason for choosing Chrome,
it seems to me, is likely to be personal preference.
I can understand why you might favour the Pascal syntax
and why you might, moreover, wish to program Pascal from
within Visual Studio. This is essentially the argument
given by RemObjects themselves:
“Most of those who move from
Delphi to .NET choose to use Visual Studio, and within
it the choice of languages is, in most cases, between
C# and VB.NET. While both these languages would be
acceptable choices, many developers would still prefer
to use Object Pascal and not have to learn a completely
new language. So why not give them Object Pascal inside
Visual Studio?”
If you are in the fortunate position to act
purely on your personal preferences, Chrome may be
a good choice. I suspect, however, that rather few
professional developers are likely to have quite so
much freedom…
February 2006 |