Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 WIP - Pascal Whirlwind
Index -> General Programming
View previous topic Printable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: 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
Sponsor
sponsor
Andy




PostPosted: 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




PostPosted: 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. Wink

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




PostPosted: Thu Jun 29, 2006 8:55 pm   Post subject: (No subject)

omg, i can actually tell whats going on Very Happy 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]




PostPosted: 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. Wink I'll read through it as soon as I finish the C version. Speaking of which...
wtd




PostPosted: Fri Jun 30, 2006 10:50 am   Post subject: (No subject)

As with the C whirlwind, check back frequently for updates.
wtd




PostPosted: 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


Scheme is too easy to require such a thing.
wtd




PostPosted: Mon Jul 10, 2006 4:32 pm   Post subject: (No subject)

Update added. A few sections on arrays.
Sponsor
Sponsor
Sponsor
sponsor
wtd




PostPosted: Sun Oct 08, 2006 11:34 am   Post subject: (No subject)

More stuff added on OOP in Pascal.
md




PostPosted: 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




PostPosted: 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
Display posts from previous:   
   Index -> General Programming
View previous topic Tell A FriendPrintable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 11 Posts ]
Jump to:   


Style:  
Search: