6
procedure questiontype;  
 begin  
  writeln ('Enter the type of question you would like...');  
  writeln ('1. Add');  
  writeln ('2. Multiply');  
  writeln ('3. Subtraction');  
  writeln ('4. Division');  
  readln (typeofquestion);  
   case typeofquestion of
    1: add;
    2: multiply;
    3: subraction;
    4: division   
else writeln ('Choose again'); 
end;
end;          

The add, multiply, subtraction and division are all procedures. If i put this in the main program, it will work fine, but when i make this as a procedure itself, i get the error undeclared identifier. I've looked on many websites for an example that is like this but i can't find any.

How do make add, multiply, subtraction, division go to their procedures from inside this one?

captiv
  • 107
  • 2
  • 9

3 Answers3

14

You have to declare procedures before routines that call them. Although you haven't shown how the other routines are defined, I deduce that they are declared after the routine you have shown.

So you can simply re-order your code so that add, multiply, subtraction and division are defined before they procedure that calls them.

So this will work:

procedure add;
begin
  //do something;
end;

procedure questiontype;  
begin  
  add;  
end;

But this will not compile:

procedure questiontype;  
begin  
  add;  
end;

procedure add;
begin
  //do something;
end;

Pascal and its variants are compiled in a single pass and if the compiler does not know about a routine at the point at which it is mentioned, it cannot continue.

Pascal does support co-routines where A calls B and B calls A, by the use of a *forward declaration`. For example:

procedure B; forward;

procedure A;
begin
  B;
end;

procedure B;
begin
  A;
end;

Naturally this is an infinite loop as written which will terminate with a stack overflow (how appropriate!) but there are of course real examples where this is necessary.

However, forward declarations are rarely needed and should be avoided if possible since they increase complexity. Invariably a solution can be found by simply re-ordering your declarations.

As a final aside, the ordering constraint that declaration occurs before use is explicitly mentioned in Brian Kernighan famous article, Why Pascal is Not My Favorite Programming Language.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @David, how many downvotes did you get in the latest few days? Significantly more then usual? To me it looks like an epidemic. I've got a total of 8 downvotes since I opened my SO account, 4 of them in the last 4 days. My numbers are statistically irrelevant, they're too small. – Cosmin Prund Mar 19 '11 at 17:20
  • 2
    My guess is that the downvoter only read the first tag of the question, namely, `[delphi]`, and noted that you said nothing about the `interface` section. Or maybe the downvoter was merely in a bad mood. Still, you should never downvote without leaving a comment, IMO. – Andreas Rejbrand Mar 19 '11 at 17:21
  • @Cosmin: A few weeks ago someone (apparently) downvoted every answer I had given the last week or so. – Andreas Rejbrand Mar 19 '11 at 17:22
  • @Cosmin Quite a few in recent days. Irony is that the downvoters are only depriving themselves of rep! – David Heffernan Mar 19 '11 at 17:22
  • @Andreas, I downvote from time to time without leaving comments for two reasons: There are reprisals from offended users in form of more downvotes (It happened to me twice) and there are times where the question is in too bad form, with unattended clarification requests or such things that I feel commenting is a waste of time, but you can still contribute by downvoting to automatically delete this bad quality questions someday. – jachguate Mar 19 '11 at 18:51
  • ISO 7185 does not have units. The later standard (10206) does have a module system, but its syntax is more Modula2 like, with iirc MODULE DEFINITION and IMPLEMENTATION as substitute resp. UNIT/INTERFACE/IMPLEMENTATION keywords. The UCSD model that TP derived from was afaik based on an early concept draft for 10206, but the syntax was later changed. – Marco van de Voort Mar 21 '11 at 20:46
  • Careful with the term co-routines. That term usually means something different. – Rudy Velthuis May 11 '16 at 09:01
6

I see you have tagged your question [delphi] as well as [pascal], so I guess you are in fact writing Delphi code. Then you got a few more options, besides caring about the order of the procedures and the forward directive discussed by David.

Most often a Delphi project (GUI or console) is divided into "units". A typical unit looks like this:

unit MyUnit;

interface

const
  RANDOM_NUMBER = 17;

var
  PrintExtraNiceMessage: boolean;

procedure DoThis;
procedure DoThat;

implementation

const
  BUFFER_SIZE = 256;

procedure InitSomething;
begin
  // TODO: do some internal work...
end;

procedure DoThis;
begin
  // TODO: do something
end;

procedure DoThat;
begin
  // TODO: do something else
end;

You will notice that the unit is divided in two parts: the interface part, and the implementation part. The interface part contains only declarations (of functions, procedures, types, constants, and variables); the functions and procedures declared here are defined (that is, implemented) in the implementation section. Notice that there can be functions and procedures defined in the implementation section that have no declarations in the interface section.

The grand idea is that the contents of the interface section is visible to all other units in your program, whereas the contents of the implementation section is only visible inside this very unit. So any other unit in your program can use the RANDOM_NUMBER constant, the PrintExtraNiceMessage variable and the two procedures DoThis and DoThat. But you can only use InitFunction in this very unit (for instance, inside DoThis or DoThat). In addition, the constant BUFFER_SIZE is not visible outside this very unit, either.

This is a very elegant approach. The interface section describes how this unit is used in other units (e.g., what functions there are and how they are used), and the implementation details are "hidden" in the implementation section.

A benefit of this approach is that it solves your problem, at least possibly. If the add, multiply, subtract, and divide procedures should be visible to other units, then they should be declared in the interface section. But then they are indeed known to the compiler by the time it comes to your questiontype procedure, and so you can use call these even if they are defined (implemented) below the questiontype procedure inside the implementation section. But, on the other hand, if it makes no sense at all to let other units use these procedures, then they should not be declared in the interface section, and you need to do as David suggests. This also applies if you have no normal units at all in your project, that is, if you only have the program file, which has no division into interface and implementation parts.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
2

Notice that the OP's example has an else that only applies to the last "if". Presumably, if they enter 1, 2, or 3, the corresponding procedure fires, returns, and then they see 'Choose again'. If they enter 4, they do not. This would be well served by a Case or cascading if..else if structure where the final else is only triggered "when all else fails", which is like what the OP intended.

Chris Thornton
  • 15,620
  • 5
  • 37
  • 62