Contents

Comparing THINK Pascal to CodeWarrior Pascal

Water's Edge Software, creators of Tools Plus, has extensive experience using CodeWarrior
compilers (C/C++/Pascal for 680x0 & PPC). We originally came from a THINK Pascal
background and we've spent a lot of time with CW Pascal specifically, so we can make
a fare comparison between the two. Here are our thoughts:

CW Pascal does not have the simplicity of THINK Pascal. It has more dependencies
on various libraries, uses only the new Universal Pascal Interfaces (UPIs), and has
a lot of options in its "preferences" dialog. On the positive side, you
can also do a number of things with CodeWarrior that you can't with THINK Pascal,
like generate PowerPC code and building 68K A4-relative libraries for things like
plug-ins.

The CodeWarrior installation required a LOT more disk space: about 30 MB compared
to THINK Pascal's 2.5 MB. Much of this is the UPIs.

Unlike THINK Pascal, there is no pretty printing in CodeWarrior. Code indenting
for records and program structure is manual, but key words, comments, strings and
other useful things can be automatically color coded. CodeWarrior's auto-indenting
works like THINK C's: non-intelligent, relying on "balancing," that is
_your_ effort to make sure code is correctly indented. We much prefer THINK Pascal's
source editor because it indents the code correctly and shows you where your mistakes
are as you type.

Unlike "regular" Pascal, CW Pascal inherits some good qualities from
C, such as being tolerant of units that are not in a specific build order. CodeWarrior
requires that your main application be listed first in your compile order whereas
THINK Pascal wants it last.

CW Pascal's debugger is more robust, letting you click from a list of variables
and structure, and letting you view them in different ways. In THINK Pascal you have
to drop into LightsBug. On the other hand, THINK Pascal lets you evaluate expressions
on the fly as you are debugging by using the "Instant" window. Also, THINK
Pascal lets you work directly with your source code by putting in stop signs right
in your source window. The CodeWarrior debugger still has some problems displaying
the values in packed records, and it refuses to display any correct values on a 680x0
Mac running System 7.1.2.

CW Pascal compiles/links faster than THINK Pascal. On a 25MHz '040 compiling
and linking a 45000 line app, here are the results:

THINK Pascal: 230 secs
CW Pascal...: 162 secs (42% faster)

THINK Pascal creates a smaller executable than CodeWarrior. When including only
the executable code generated by the compiler, here is how they compare in our 45000
line app:

THINK Pascal: 132,818 bytes
CW Pascal...: 142,583 bytes (7% larger)

CodeWarrior has a PowerPC compiler that compiles the same code as their 68K compiler.
Symantec has Language Systems' LS Pascal translator for their Symantec C/C++ (version
8.0.5 or later). It's not for the faint of heart. The product is still in a raw,
pre-beta state, and documentation and technical support are weak. There is no commitment
from Symantec that it will ever become a "real" product. Also, your THINK
Pascal code won't run on the "LS Pascal translator" without serious changes,
and even then, there are numerous low-level bugs lurking. With the Symantec solution,
you'll have to dedicate considerable effort to producing a single source code base
that can be compiled by both the 68K THINK Pascal compiler and the PowerPC LS Pascal
translator. With CodeWarrior, it's effortless. In fact, CodeWarrior will compile
your THINK Pascal code with minimal changes.

THINK Pascal is a solid, reliable product while CW Pascal has attained this status
only in CodeWarrior 10. It used to have codegen bugs and problems with packed records
in prior versions.

According to our customers, they prefer Metrowerks' tech support over Symantec
by a wide margin. They also mention Metrowerks' commitment to Pascal right from day
1. Over a quarter of our Symantec customers have switched to CodeWarrior for these
reasons.

Migrating To CodeWarrior Pascal

If you are thinking about making the transition from THINK Pascal to CodeWarrior,
or if you want to use THINK Pascal for your 68K work and CodeWarrior for your PowerPC
work and have both use the same source code, here are the areas when you need to
be aware of the differences:

CW Pascal projects expect your application file to be first in your projects's
build order whereas THINK expects it to be last.

CW expects the unit name and its source file to be the same. For example, a unit
named MyUnit must be in a source file named MyUnit.p. This means your source _files_
must be named in a way that is consistent with the unit's name. For example, you
can't have a file named "1Thing.p" because a Pascal unit can't start with
a number. You also can't include spaces or other characters in your file names that
would not be allowed in a Pascal unit.

THINK Pascal assumes a "uses" statement for all the standard toolbox
units. CodeWarrior makes no assumptions, so you will likely need to include a uses
clause that looks like this:

Fortunately, CW also lets you turn on "Used Propagation" so you can
have all these items listed once in your application's "globals" unit which
in turn will be used by each unit in your project.

CW supports only Universal Headers and Universal Pascal Interfaces (UPIs). As
you compile your THINK Pascal source code under CW, every time CW runs across a routine
that has been renamed in the new UPIs, you must rename it in your app. The same applies
for some constants that have been renamed in the UPIs.

NOTE: If your source code must be compiled by both THINK Pascal and CW, you'll
want to take a different approach:

Create a special unit called UPI in a file named UPI.p (this is short for "Universal
Pascal Interface")

All your units will use the UPI unit.

Your UPI unit will have an interface part, and the implementation will be empty

Bracket the interface part with:

{$IFC THINK_Pascal}

{$ENDC}

You will put all your "unifying" code between these brackets. THINK
Pascal will now understand how to use the new Universal Pascal Interfaces without
actually having to deal with the complexities of true UPI's in THINK Pascal.

Compile your THINK Pascal code using CW

Each time your CW compiler finds a routine, constant, or type that has been changed,
find where it has been defined in the CW UPIs, then copy that definition into your
UPI unit. The new routines will have inline code, such as:

Function GetControlValue (theControl: ControlRef): SInt16;

inline
$A960;

This lets you use the new routine names found in the new Universal Pascal Interfaces
while continuing to use the original (and simpler) Apple interfaces with THINK Pascal.
The inline code maps the new routine name to the original traps in the toolbox. The
net result is that the old routines are available with the new names found in the
Universal Pascal Interfaces.

The original Apple interfaces and headers are for 680x0 Macs only whereas the
new UPIs let you use the same source code for both 680x0 Macs and PowerPC Macs. A
problem arises in callback routines. For example, in the old interfaces, you could
say:

SetClikLoop(@myProc, hTE);

@myProc is simply a pointer to a Pascal routine. When using the new UPIs, they
take PowerPC differences into account, and with a PowerPC, it is possible to call
a routine that is made of either 68K or PowerPC native executable code. The caller
has to know this, so PowerPC introduces the Mixed Mode Manager.

When using the UPIs, you have to create something called a Universal Procedure
Pointer (UPP). When compiled into 680x0 code, it is nothing more than a pointer to
the routine, just like it has been in the past. When compiled into PowerPC native
code, creating a UPP actually allocates a structure that tells the calling routine
what kind of code it will call (68K or PowerPC) and how the parameters are passed.

Remember that on PowerPC, a UPP is an _allocated_ _structure_ that points to a
routine. It's not just a pointer. The same UPP can be used throughout your application,
so it's a smart idea to allocate the UPP only once early in your app, then use that
one UPP throughout your app as required. Here's the code you can use to allocate
the UPP early in your app:

Your app references QuickDraw globals through the "qd" global. For
example, use "qd.Gray" instead of "Gray" for the gray pattern.
More common is the use of qd.screenBits.Bounds to determine the boundary of your
monitor.

Look out if you work with packed records where a 2 byte or 4 byte record is made
up of various bit patterns. For example, the low 9 bits being a number from 0 to
511, the next bit up being a boolean, etc. We've experienced problems in CW 6, 8
and 9. As far as we can see, CW10 and later work correctly with packed record.