WIP - Pascal Whirlwind
Author |
Message |
wtd
|
Posted: Thu Jun 29, 2006 12:19 pm Post subject: WIP - Pascal Whirlwind |
|
|
Hello, Pascal!
Let me just open my text editor and create a file called hellopascal.pas.
code: | program HelloPascal;
begin
writeln('Hello, Pascal!')
end. |
And then assuming I've installed the Free Pascal Compiler, I simply opern my command-line, run "fpc hellopascal", and I'm left with a binary by the same name. I don't need to attach the ".pas" extension. The compiler knows to look for source files with that extension.
Names for things
Let's give that message a name.
code: | program HelloPascal;
const
greeting = 'Hello, Pascal!';
begin
writeln(greeting)
end. |
It's a tribute to Pascal that what I've done is pretty easy to see. I've started a const clause, in which I define constant values and give them names.
But why the semi-colon there? Pascal uses semi-colons as separators. The semi-colon indicates to the compiler that I wish to separate two things. In thise case, I'm separating the definition of the constant greeting, and the begin keyword. One is not necessary after the call to the writeln procedure because Pascal gives special importance to the "end" keyword.
Let's say that I now wish to give a name to the very action of writing that message. I'll create a procedure, sicne procedures and fucntions are how executable code is primarily grouped and named.
code: | program HelloPascal;
const
greeting = 'Hello, Pascal!';
procedure WriteMessage;
begin
writeln(greeting)
end;
begin
WriteMessage
end. |
Greeting anyone
A bit of flexibility would be nice. To that end I'll define a greet procedure with a name parameter, and then pass 'world' as its argument when I call it.
code: | program HelloPascal;
const
greeting = 'Hello, Pascal!';
procedure WriteMessage;
begin
writeln(greeting)
end;
procedure Greet(name: string);
begin
writeln('Hello, ' + name + '!')
end;
begin
WriteMessage;
Greet('world')
end. |
Let's discriminate
code: | program HelloPascal;
procedure Greet(name: string);
begin
if name = 'wtd' then
writeln(name + '?! That cur!')
else
writeln('Hello, ' + name + '!')
end;
begin
Greet('wtd')
end. |
But that only said one thing to wtd, and that's just not enough.
code: | program HelloPascal;
procedure Greet(name: string);
begin
if name = 'wtd' then
begin
writeln(name + '?! That cur!');
writeln('Off with the scoundrel''s head!')
end
else
writeln('Hello, ' + name + '!')
end;
begin
Greet('wtd')
end. |
A quick note
Pascal is case-insensitive, so you may see code with If or IF. That's fine. You can define Greet and then use it as greet, and that is also fine. The best advice is to pick a style and stick to it.
Let's use a type
Let's create a record type which contains a more complex name, and a procedure which acts on it.
code: | program HelloPascal;
type
name = record
first, last : string;
end;
procedure Greet(n : name);
begin
writeln('Hello, ', n.first, ' ', n.last, '!')
end;
var
bobsName : name;
begin
bobsName.first := 'Bob';
bobsName.last := 'Smith';
Greet(bobsName)
end. |
Let's add a bit of sugar
code: | program HelloPascal;
type
name = record
first, last : string;
end;
procedure Greet(n : name);
begin
with n do
writeln('Hello, ', first, ' ', last, '!')
end;
var
bobsName : name;
begin
bobsName.first := 'Bob';
bobsName.last := 'Smith';
Greet(bobsName)
end. |
Isn't consistency grand?
code: | program HelloPascal;
type
name = record
first, last : string;
end;
procedure Greet(n : name);
begin
with n do
writeln('Hello, ', first, ' ', last, '!')
end;
var
bobsName : name;
begin
with bobsName do begin
first := 'Bob';
last := 'Smith';
end;
Greet(bobsName)
end. |
Note how I provided a block of code to the with construct, rather than just a single statement. You should also note that this is how I did the same for conditionals.
New names are good
So let's create a procedure which helps us create them.
code: | program HelloPascal;
type
name = record
first, last : string;
end;
procedure InitializeName(var n : name; first, last : string);
begin
n.first := first;
n.last := last
end;
procedure Greet(n : name);
begin
with n do
writeln('Hello, ', first, ' ', last, '!')
end;
var
bobsName : name;
begin
InitializeName(bobsName, 'Bob', 'Smith');
Greet(bobsName)
end. |
There's only one problem...
In order to initialize a name, I have to have a name variable. I can't just create a name and use it directly. For that I'd need a function.
code: | program HelloPascal;
type
name = record
first, last : string;
end;
function NewName(first, last : string) : name;
var
n : name;
begin
n.first := first;
n.last := last;
NewName := n
end;
procedure Greet(n : name);
begin
with n do
writeln('Hello, ', first, ' ', last, '!')
end;
var
bobsName : name;
begin
bobsName := NewName('Bob', 'Smith');
Greet(bobsName)
end. |
Or just:
code: | program HelloPascal;
type
name = record
first, last : string;
end;
function NewName(first, last : string) : name;
var
n : name;
begin
n.first := first;
n.last := last;
NewName := n
end;
procedure Greet(n : name);
begin
with n do
writeln('Hello, ', first, ' ', last, '!')
end;
begin
Greet(NewName('Bob', 'Smith'))
end. |
Time for some cleaning up
We've got a decent-sized program now, and that's good. But what if I want to use my name type and it's associated routines elsewhere?
Well, let's create a file named nameunit.pas that will contain a unit, or module of code.
code: | unit NameUnit;
interface
type
name = record
first, last : string;
end;
function NewName(first, last : string) : name;
procedure Greet(n : name);
implementation
function NewName(first, last : string) : name;
var
n : name;
begin
n.first := first;
n.last := last;
NewName := n
end;
procedure Greet(n : name);
begin
with n do
writeln('Hello, ', first, ' ', last, '!')
end;
end. |
And now we'll rewrite our hellopascal.pas program.
code: | program HelloPascal;
uses
NameUnit;
begin
Greet(NewName('Bob', 'Smith'))
end. |
Much nicer, eh?
Whereas previous programs had been compiled with "fpc hellopascal", this new setup shall be compiled with "fpc hellopascal nameunit".
A Pointless Array
code: | program HelloPascal;
uses
NameUnit;
var
names : array [1..10] of Name;
begin
names[1] := NewName('Bob', 'Smith');
Greet(names[1])
end. |
Slightly less pointless
code: | program HelloPascal;
uses
NameUnit;
var
names : array [1..10] of Name;
i : Integer;
begin
for i := 1 to 10 do
names[i] := NewName('Bob', 'Smith');
for i := 1 to 10 do
Greet(names[1])
end. |
Or perhaps:
code: | program HelloPascal;
uses
NameUnit;
var
names : array [1..10] of Name;
i : Integer;
begin
for i := 1 to 10 do
begin
names[i].first := 'Bob';
names[i].last := 'Smith';
end;
for i := 1 to 10 do
Greet(names[1])
end. |
Or even:
code: | program HelloPascal;
uses
NameUnit;
var
names : array [1..10] of Name;
i : Integer;
begin
for i := 1 to 10 do
with names[i] do
begin
first := 'Bob';
last := 'Smith';
end;
for i := 1 to 10 do
Greet(names[1])
end. |
Pointers Galore!
Arrays are so static. Let's use a linked list instead. That means pointers.
code: | program HelloPascal;
uses
NameUnit;
type
PNode = ^TNode;
TNode = record
Data : Name;
Next : PNode;
end;
var
list : PNode;
procedure GreetAllInList(list : PNode);
var
current : PNode;
begin
current := list;
while current <> nil do
with current^ do
begin
Greet(data);
current := next;
end;
end;
procedure NewList(var list : PNode; value : Name);
begin
New(list);
with list^ do
begin
data := value;
next := nil;
end;
end;
procedure AppendToList(var list : PNode; value : Name);
var
current, last : PNode;
begin
if list = nil then
NewList(list, value)
else begin
current := list;
while current <> nil do
with current^ do
begin
last := current;
current := next;
end;
NewList(last^.next, value);
end;
end;
begin
AppendToList(list, NewName('Foo', 'Bar'));
AppendToList(list, NewName('Bob', 'Smith'));
GreetAllInList(list);
end. |
Aren't objects grand?
Wha?! Pascal has objects? Well, yes, Pascal has the ability to work with objects. In the following I'll be using the Free Pascal compiler's OO extension. As a result, I have to compile with the "-S2" option.
code: | program Test;
uses
Name, NameList;
var
list : TNameList;
begin
list := TNameList.Create;
list.Append(TName.Create('Bob', 'Smith'));
list.Append(TName.Create('Foo', 'Bar'));
list.GreetAll;
end. |
And to make that possible, the following two units.
code: | unit Name;
interface
type
TName = class
First, Last : String;
public
constructor Create(f, l : String);
function FullName : String;
procedure Greet;
end;
implementation
constructor TName.Create(f, l : String);
begin
First := f;
Last := l;
end;
function TName.FullName : String;
begin
FullName := First + ' ' + Last;
end;
procedure TName.Greet;
begin
writeln('Hello, ', FullName, '!');
end;
end. |
code: | unit NameList;
interface
uses
Name;
type
PNode = ^TNode;
TNode = record
Data : TName;
Next : PNode;
end;
TNameList = class
Head : PNode;
public
constructor Create;
procedure Append(NewName : TName);
procedure GreetAll;
end;
implementation
constructor TNameList.Create;
begin
Head := nil;
end;
procedure TNameList.Append(NewName : TName);
var
current : PNode;
begin
if Head = nil then
begin
New(Head);
Head^.Data := NewName;
Head^.Next := nil;
end
else
begin
current := Head;
while current^.Next <> nil do
current := current^.Next;
New(current^.Next);
with current^.Next^ do
begin
Data := NewName;
Next := nil;
end;
end;
end;
procedure TNameList.GreetAll;
var
current : PNode;
begin
current := Head;
while current <> nil do
begin
current^.Data.Greet;
current := current^.Next;
end;
end;
end. |
Objects and interfaces
So we've seen that it's possible to have objects in Pascal. But then, some would argue that interfaces are a key concept in object-oriented programming. Pascal can handle that too.
code: | program InterfaceTest;
type
IHasName = interface
function Name : string;
end;
TName = class(TInterfacedObject, IHasName)
constructor Create(f, l : string);
function First : string;
function Last : string;
function Name : string;
private
FFirst, FLast : string;
end;
TSingleName = class(TInterfacedObject, IHasName)
constructor Create(n : string);
function Name : string;
private
FName : string;
end;
{ The Greet function }
procedure Greet(n : IHasName);
begin
writeln('Hello, ', n.Name, '!');
end;
{ Implement TName }
constructor TName.Create(f, l : string);
begin
FFirst := f;
FLast := l;
end;
function TName.First : string;
begin
First := FFirst;
end;
function TName.Last : string;
begin
Last := FLast;
end;
function TName.Name : string;
begin
Name := FFirst + ' ' + FLast;
end;
{ Implement TSingleName }
constructor TSingleName.Create(n : string);
begin
FName := n;
end;
function TSingleName.Name : string;
begin
Name := FName;
end;
var
Names : array [1..2] of IHasName;
Index : integer;
begin
Names[1] := TName.Create('Bob', 'Smith');
Names[2] := TSingleName.Create('Foo');
for Index := 1 to 2 do Greet(Names[Index]);
end. |
Abstract Base Classes
Of course, we could accomplish much the same with an abstract class.
code: | program AbstractClassTest;
type
TNameBase = class(TObject)
function Name : string; virtual; abstract;
procedure Greet;
end;
TName = class(TNameBase)
constructor Create(f, l : string);
function First : string;
function Last : string;
function Name : string; override;
private
FFirst, FLast : string;
end;
TSingleName = class(TNameBase)
constructor Create(n : string);
function Name : string; override;
private
FName : string;
end;
{ Implement TNameBase }
procedure TNameBase.Greet;
begin
writeln('Hello, ', Name, '!');
end;
{ Implement TName }
constructor TName.Create(f, l : string);
begin
FFirst := f;
FLast := l;
end;
function TName.First : string;
begin
First := FFirst;
end;
function TName.Last : string;
begin
Last := FLast;
end;
function TName.Name : string;
begin
Name := FFirst + ' ' + FLast;
end;
{ Implement TSingleName }
constructor TSingleName.Create(n : string);
begin
FName := n;
end;
function TSingleName.Name : string;
begin
Name := FName;
end;
var
Names : array [1..2] of TNameBase;
Index : integer;
begin
Names[1] := TName.Create('Bob', 'Smith');
Names[2] := TSingleName.Create('Foo');
for Index := 1 to 2 do Names[Index].Greet;
end. |
|
|
|
|
|
![](images/spacer.gif) |
Sponsor Sponsor
![Sponsor Sponsor](templates/subSilver/images/ranks/stars_rank5.gif)
|
|
![](images/spacer.gif) |
Andy
|
Posted: Thu Jun 29, 2006 1:52 pm Post subject: (No subject) |
|
|
Thanks wtd! i always wanted to learn pascal.. gona find some time to read through this after exams. |
|
|
|
|
![](images/spacer.gif) |
Cervantes
![](http://compsci.ca/v3/uploads/user_avatars/1023105758475ab2e040bde.jpg)
|
Posted: Thu Jun 29, 2006 8:28 pm Post subject: (No subject) |
|
|
Gosh wtd, you're the best. I can really see now why they say Turing's syntax is inspired by Pascal.
As a special request, could the next whirlwind be in Scheme? I can think of at least one other person who would definitely be interested in that.
That's assuming you're willing to do another whirlwind. I realize it's a lot of work and am not trying to put any pressure on you. |
|
|
|
|
![](images/spacer.gif) |
Clayton
![](http://compsci.ca/v3/uploads/user_avatars/1718239683472e5c8d7e617.jpg)
|
Posted: Thu Jun 29, 2006 8:55 pm Post subject: (No subject) |
|
|
omg, i can actually tell whats going on its so easy to read, and its easy on the eyes, thats always a bonus, gotta like case-insensitivity too, easier to try and write, where could you get this magical Pascal compiler? hmm? |
|
|
|
|
![](images/spacer.gif) |
[Gandalf]
![](http://compsci.ca/v3/uploads/user_avatars/189297994e4c716fec7f1.png)
|
Posted: Thu Jun 29, 2006 9:09 pm Post subject: (No subject) |
|
|
SuperFreak, do a Google search.
wtd, another great whirlwind. You are definately a professional tutorial writer in addition to a great programmer. I'll read through it as soon as I finish the C version. Speaking of which... |
|
|
|
|
![](images/spacer.gif) |
wtd
|
Posted: Fri Jun 30, 2006 10:50 am Post subject: (No subject) |
|
|
As with the C whirlwind, check back frequently for updates. |
|
|
|
|
![](images/spacer.gif) |
wtd
|
Posted: Fri Jun 30, 2006 12:38 pm Post subject: (No subject) |
|
|
Cervantes wrote: As a special request, could the next whirlwind be in Scheme? I can think of at least one other person who would definitely be interested in that. ![Wink Wink](http://compsci.ca/v3/images/smiles/icon_wink.gif)
Scheme is too easy to require such a thing. |
|
|
|
|
![](images/spacer.gif) |
wtd
|
Posted: Mon Jul 10, 2006 4:32 pm Post subject: (No subject) |
|
|
Update added. A few sections on arrays. |
|
|
|
|
![](images/spacer.gif) |
Sponsor Sponsor
![Sponsor Sponsor](templates/subSilver/images/ranks/stars_rank5.gif)
|
|
![](images/spacer.gif) |
wtd
|
Posted: Sun Oct 08, 2006 11:34 am Post subject: (No subject) |
|
|
More stuff added on OOP in Pascal. |
|
|
|
|
![](images/spacer.gif) |
md
![](http://compsci.ca/v3/uploads/user_avatars/1849317514ed6c4399768d.png)
|
Posted: Sun Oct 08, 2006 4:16 pm Post subject: (No subject) |
|
|
I am almost tempted to go back to pascal now... if only classes were implemented a little bit different, C++ style syntax just seems so much more natural to me. |
|
|
|
|
![](images/spacer.gif) |
Nick
![](http://compsci.ca/v3/uploads/user_avatars/19644337547e837b41d67a.png)
|
Posted: Wed Aug 15, 2007 11:50 am Post subject: RE:WIP - Pascal Whirlwind |
|
|
thanks a lot this is great since im downloading pascal atm (special thanks to rdrake for all his help) keep up the good work |
|
|
|
|
![](images/spacer.gif) |
|
|