Subject: language issues ( was RE: [hackers-il] [[email-masked]: Shimon Schocken on Tu esday 05/06/2001] )

From: Omer Musaev <[email-masked]>
Date: Tue, 10 Apr 2001 12:33:52 +0200

> > > a rant on Pascal: how can a language have none of
> > > case sensitivity
> > > initialization of const arrays
> > > no return from functions or procedures (!)
> 
> I didn't do Pascal for a long time, but:
> 
> 1) I don't think there is any inherit advantage to case 
> sensitivity over
> case insensitivity in programming languages. Its more of a 
> matter of taste
> and common practices.
> What is very important is the proper use of case in variable 
> names, but this
> has nothing to do with the language.

In some ways, case sensitivity decreases value of self-documentation of 
programs. It can be very misleading to following function:

char *Open( char *foo, long *goo, struct timeval *tv ) ; 
/* almost open(2), which is int open( char*, int ) */

but this one is even worse:

int Open( char *fname, int mode ) ;
/* TOO close to open (2) */

However, in some cases case sensitivity can help. 
For example consider a following convention:
 we have variables fsize, bsize and ssize, which carry sizes of 
 various variable size structures. Constants FSIZE, BSIZE and SSIZE hold
 minimal size of appropriate structures.

Here, case sensitivity is a win.
   
> 2) What do you mean by "no return from functions"? IIRC you 
> call a function
> and get a returned value, no?

If I got it right, Muli refers to absence of multiple return points. 
A well known approach in C is to return from function as soon as you 
discover that you can not continue, for example:

/**
* read first word from file, convert it to unsigned integer.
* \return Converted integer value, 0 in case of error
* \param fname - name of file to read the value from
*/
#define ERR -1
#define FSIZE 16
int read_first_int( char *fname ) {
         char *fmt = "%du" ; /* for fscanf */
         FILE *fd ; 
         int val = 0 ;

   if ( !( fd = fopen( fname, "r" ) ) ) {
       return ERR ; /* open failed, return 0 now */
   }
   fclose( fd ) ;
   switch ( fscanf( fd, fmt, &val ) ) {
      case EOF: case 0: return ERR ;
      default: return val ;
   }
} 

Here we have 2 points of return. Given more requisites for function to 
start doing its job, we can have more of those.

However, there are 2 techniques for avoiding multiple points of return 
in cases when this approach is not appropriate:

First is use of conditionals. Abovementioned function can be rewritten in
following 
way:

int read_first_int( char *fname ) {
         char *fmt = "%du" ; /* for fscanf */
         FILE *fd ; 
         int val = 0 ;

   if ( ( fd = fopen( fname, "r" ) ) ) {
      int fsout ; 
      switch ( fscanf( fd, fmt, &fsout ) ) {
         case EOF: case 0: val = ERR ;
         default: val = fsout ;
      }
      fclose( fd ) ;
   }
   else 
       val =  ERR ; /* open failed, set val to 0 */
   }
   return val ;
} 

The second is use of goto operator for cheap exception handling:

#define ERR -1
#define FSIZE 16
int read_first_int( char *fname ) {
         char *fmt = "%du" ; /* for fscanf */
         FILE *fd = NULL ; 
         int val = 0 ;

   if ( !( fd = fopen( fname, "r" ) ) ) {
       goto out_err ;
   }
   
   switch ( fscanf( fd, fmt, &val ) ) {
      case EOF: case 0: goto out_err ;
      default: goto out ;
   }
out_err:
   val = ERR ;
   if ( fd ) fclose( fd ) ;
out:
   return val ;
} 

Again, this technique, crude as it is, can be used with some care in cases 
when a programmer must implement constructors for huge structures.

The point of above snippets is that multiple return points is a nice and
convenient 
feature. Pascal ( and some other languages, including scheme ) does not have
it.
> 
> The worse part about Pascal IMO is that there's no pointer to 
> functions, and
> no anonymous functions. On the other hand it has nested functions (I
> think), which I wouldn't mind seeing in more languages.

Brian Kernighan had written a brilliant critique on Pascal:
--- Citing BWK ---
To close, let me summarize the main points in the case against Pascal. 

* Since the size of an array is part of its type, it is not possible 
  to write general-purpose routines, that is, to deal with arrays 
  of different sizes.  In particular, string handling is very difficult. 

* The lack of static variables, initialization and a way to communicate 
  non-hierarchically combine to destroy the ``locality'' of a program - 
  variables require much more scope than they ought to. 

* The one-pass nature of the language forces procedures and functions to 
  be presented in an unnatural order; the enforced separation of various 
  declarations scatters program components that logically belong together.
 
* The lack of separate compilation impedes the development of large programs

  and makes the use of libraries impossible. 

* The order of logical expression evaluation cannot be controlled, which
leads 
  to convoluted code and extraneous variables.
 
* The 'case' statement is emasculated because there is no default clause.
 
* The standard I/O is defective.  There is no sensible provision for dealing

  with files or program arguments as part of the standard language, 
  and no extension mechanism. 

* The language lacks most of the tools needed for assembling large programs,

  most notably file inclusion.
 
* There is no escape. 

This last point is perhaps the most important.  The language is inadequate
but 
circumscribed, because there is no way to escape its limitations.  
There are no casts to disable the type-checking when necessary.  
There is no way to replace the defective run-time environment with a 
sensible one, unless one controls the compiler that defines the 
``standard procedures.'' 
The language is closed. 

People who use Pascal for serious programming fall into a fatal trap.

--- end of citation ---

You can found this document here:
http://www.lysator.liu.se/c/bwk-on-pascal.html