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.  | 	 
  | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
		 
		Sponsor Sponsor 
		 
  
		 | 
		
 | 
	 
	 
		  | 
	 
				 
		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. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		Cervantes
 
  
 
    
		 | 
		
		
			
				  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. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		Clayton
 
  
 
    
		 | 
		
		
			
				  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? | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		[Gandalf]
 
  
 
    
		 | 
		
		
			
				  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... | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		wtd
 
 
 
    
		 | 
		
		
			
				  Posted: Fri Jun 30, 2006 10:50 am    Post subject: (No subject)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				| As with the C whirlwind, check back frequently for updates. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		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.    
 
 
Scheme is too easy to require such a thing. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		wtd
 
 
 
    
		 | 
		
		
			
				  Posted: Mon Jul 10, 2006 4:32 pm    Post subject: (No subject)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				| Update added.  A few sections on arrays. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
		 
		Sponsor Sponsor 
		 
  
		 | 
		
 | 
	 
	 
		  | 
	 
				 
		wtd
 
 
 
    
		 | 
		
		
			
				  Posted: Sun Oct 08, 2006 11:34 am    Post subject: (No subject)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				| More stuff added on OOP in Pascal. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		md
 
  
 
    
		 | 
		
		
			
				  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. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		Nick
 
  
 
    
		 | 
		
		
			
				  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 | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		 | 
	 
 
	
	
	 
	
	 |