[comp.lang.modula2] Overloading Operators: Extension to Language

n8243274@unicorn.WWU.EDU (steven l. odegard) (10/03/89)

In article <INFO-M2%89093000360807@UCF1VM> Modula2 List 
<INFO-M2%UCF1VM.BITNET@PSUVM.PSU.EDU> writes:
[stuff delted]
>    Which (algebraically) reads exactly as you mean it.  In Ada you can
>  define the '+' operator to be able to handle the Complex number type.
>
>    Would such a feature be warranted in Modula-2?
>    Here is some theoretical code:
[stuff deleted]

  May I add my two cents worth to the all desired extensions for a better
future language inspired by Wirth's ingenious Modula-2:

  In addition to IMPORT and EXPORT, modified modula programs will have
optional INHERIT and EXHIBIT.  These, unlike IMPORT and EXPORT, refer to
modifications to the language itself.  The syntax for INHERIT and EXHIBIT is
similar to that for IMPORT and EXPORT.

  If operator overloading is to be defined in the current module, i.e. not
INHERITed, then first define the procedure and its associated types:

    IMPLEMENTATION MODULE InternalComplexUseage ;

    TYPE Complex = RECORD RP, CP : REAL END ;
    PROCEDURE AddComplex( A, B : Complex ;  VAR R : Complex ) ;
    BEGIN R.RP := A.RP + B.RP ;  R.CP := A.CP + B.CP END AddComplex ;

  Now, overload it to the operator "+".  This shall be accomplished by a new
block option with the header QUALIFIED.  We'll assume here some other operators
have also been defined for Complex: 

    QUALIFIED complexad ;
      AddComplex( A, B : Complex ;  VAR R : Complex ) FOR R := A + B ;
      SubComplex( A, B : Complex ;  VAR R : Complex ) FOR R := A - B ;
      MulComplex( A, B : Complex ;  VAR R : Complex ) FOR R := A * B ;
      DivComplex( A, B : Complex ;  VAR R : Complex ) FOR R := A / B ;
      CopyComplex( A : Complex ;  VAR R : Complex ) FOR R := A ;
    END complexad ;

    (* ... body omitted *)

    END InternalComplexUseage .

  The compiler will now recognize A+B where A and B are Complex, and substitute
the appropriate calls.  It will also recognize and decompose objects 
like A*(B+C) + C/(A+B) .

  Now, if these objects are desired to be used elsewhere, then they must
(1) be EXHIBITed from the current module, and (2) INHERITed into the module
desired.  An INHERITance will automatically import its subsiderary objects.

    DEFINITION MODULE ComplexDefinitions ;
      
    EXPORT Complex, AddComplex, SubComplex, MulComplex, DivComplex ;
    EXHIBIT complexad ;

    (* ... definition body omitted, it is as in InternalComplexUseage *)
    END ComplexDefinitions .

    (* ... within another module now ... *)
    MODULE UseComplexDefinitions ;

    FROM ComplexDefinitions INHERIT complexad ; (* automatically imports 
	|* Complex, AddComplex, etc.;  overloads "+", "-", "*", etc. *)

    (* ... body omitted *)

    END UseComplexDefinitions .

Another example, building on the abstract type defined:

    IMPLEMENTATION MODULE MatrixDefinitions ;
    FROM ComplexDefinitions INHERIT complexad ;  (* this statement also IMPORTS
	|* Complex, AddComplex, etc. *)

    CONST NodeSize = 31 ;
    TYPE Matrix = POINTER TO MatrixListHead ;
    MatrixListHead = RECORD
      Dimensions : RECORD
	Rows, Columns : CARDINAL ;
	ChainNumber : CARDINAL ;
	Current : ARRAY [ 0 .. NodeSize ] OF Complex ;
	Next : MatrixListHead ;
      END ;

    PROCEDURE AddMatrix( A, B : Matrix ;  VAR R : Matrix ) ;
    (* ... body is deleted. *)

    PROCEDURE SubMatrix( A, B : Matrix ;  VAR R : Matrix ) ;
    (* ... body is delted. *)

    END MatrixDefinitions .

Now, its corresponding definition module is:

    DEFINITION MODULE MatrixDefinitions ;
    EXHIBIT QUALIFIED matrixad ; (* perhaps, like EXPORT QUALIFIED, these need
	|* not be included in a DEFINITION module. *)

    TYPE Matrix ; (* hidden *)
    PROCEDURE AddMatrix( A, B : Matrix ;  VAR R : Matrix ) ;
    PROCEDURE SubMatrix( A, B : Matrix ;  VAR R : Matrix ) ;
    PROCEDURE MulMatrix( A, B : Matrix ;  VAR R : Matrix ) ;
    PROCEDURE CopyMatrix( A : Matrix ;  VAR R : Matrix ) ;

    QUALIFIED matrixad ;
      AddMatrix( A, B : Matrix ;  VAR R : Matrix ) FOR R := A + B ;
      SubMatrix( A, B : Matrix ;  VAR R : Matrix ) FOR R := A - B ;
      MulMatrix( A, B : Matrix ;  VAR R : Matrix ) FOR R := A * B ;
      CopyMatrix( A : Matrix ;  VAR R : Matrix ) FOR R := A ;
    END matrixad ;

    END MatrixDefinitions .

In the same article, we have the proposed body section:
>VAR
>  Result : Complex;
>  A, B   : Complex;
>
>BEGIN
>  A := 2.0, 2.0;
>  B := 4.0, 4.0;
>  Result := A + B;
>END;

Here presupposed is the use of structured constants.  Like SETs, these
should be prefixed with the appropriate structure's name.  We require a new
form of bracket delimiter indicating this, perhaps <# and #> .  Now, then,
here is how this should appear:

  PROCEDURE DefineComplex( A, B : REAL ;  VAR C : Complex ) ;

  QUALIFIED Complexad ;
    DefineComplex( A, B : REAL ;  VAR C : Complex )
      FOR C := Complex <# A, B #> ;
  END Complexad ;

Then the body section appears
  VAR
    Result : Complex;
    A, B   : Complex;
  
  BEGIN
    A := Complex <# 2.0, 2.0 #> ;
    B := Complex <# 4.0, 4.0 #> ;
    Result := A + B;
  END;

I don't propose defining user-defined infix operators at this time.
--SLO

UI0T@DKAUNI2.BITNET (Thomas Koenig) (10/04/89)

Here comes another (more or less necessary) view...

I think that overloading operators may be nice but not necessary. In my
opinion, there is a much simpler solution with pretty much the same
effect.

How about an extension to the language which would allow functions to
return not only predefined types such as integers, reals and so on but
also records and arrays?  What I'm thinking of could look like this:

TYPE COMPLEX= RECORD RE,IM:REAL END;
PROCEDURE ADDC(A,B:COMPLEX):COMPLEX;
BEGIN
   B.RE:=B.RE+A.RE;
   B.IM:=B.IM+A.IM;
   RETURN B;
END ADDC;

This would result in expressions like
D:=ADDC(MULTC(B,A),DIVC(C,A));
which is, in effect, Polish notation. It would take a little bit of
getting used to to read, but it is better than nothing; it also wouldn't
need a drastic alteration of the language. In fact, the proposed
standard for ANSI-C has required this kind of thing for records (or
structures, as they are called in C).

Thomas  Koenig                   UI0T@DKAUNI2.BITNET
                                 UI0T%DKAUNI2.BITNET@CUNYVM.CUNY.EDU
                         (soon)  UI0T@IBM3090.RZ.UNI-KARLSRUHE.DE

abrodnik@WATDRAGON.WATERLOO.EDU ("Andrej Brodnik ", Andy) (10/04/89)

In article <"89-10-03-22:05:28.25*UI0T"@DKAUNI2.BITNET> you write:
>Here comes another (more or less necessary) view...
>
>I think that overloading operators may be nice but not necessary. In my
>opinion, there is a much simpler solution with pretty much the same
>effect.
>
>How about an extension to the language which would allow functions to
>return not only predefined types such as integers, reals and so on but
>also records and arrays?  What I'm thinking of could look like this:
>
Hi!

The problem you proposed solution for was already solved in the newest
BSI Modula-2 standard. For more information and further reference try
to get my paper, which will be presented on the First International
Modula-2 Conference, which will be held in Bled, Yugoslavia. The address
of the organizing committee is:

        Ms.Polona Blaznik
        "Jozef Stefan" Institute,
        Jamova 39,
        YU-61000 Ljubljana
        Yugoslavia

phone: +38 61 214-399
fax:   +38 61 219-385
tlx:   31-296 yu jostin

Best regards

Andrej Brodnik

PS: They will certainly send you a copy if you would ask them!

lsmith@apollo.HP.COM (Lawrence C. Smith) (10/04/89)

In article <"89-10-03-22:05:28.25*UI0T"@DKAUNI2.BITNET> Modula2 List <INFO-M2%UCF1VM.BITNET@PSUVM.PSU.EDU> writes:
>Here comes another (more or less necessary) view...
>
>I think that overloading operators may be nice but not necessary. In my
>opinion, there is a much simpler solution with pretty much the same
>effect.
>
>How about an extension to the language which would allow functions to
>return not only predefined types such as integers, reals and so on but
>also records and arrays?  What I'm thinking of could look like this:
>
>TYPE COMPLEX= RECORD RE,IM:REAL END;
>PROCEDURE ADDC(A,B:COMPLEX):COMPLEX;
...

Wirth forgot to restrict results to word-size types in the very first
Modula-2 report (the one with the yellow ETH covers).  The first compiler
implemented to this spec that did not come from Wirth himself was Modula II
for the p-System (on Apple II's and ///'s) from a company in California
whose name escapes me now.  They implemented record types for return values
and then put in a switch to disable the feature when Wirth told them it was
not supported.

Their compiler was written in Pascal, and still lives as the Pecan Modula2
compiler for the p-System.

Wirth has some very definite blind spots for language design that really puzzle
me in a man so otherwise gifted.  You'd think that returning records would be
simple, obvious, and orthogonal and so would be one of his top hot buttons.
Instead he seems to think they are anathema, and even today he just pays them
lip service.

Does Oberon allow them?  Does it allow them but not implement them?

Another of Wirth's blind spots is strings.  To get real efficiency with strings
you've just gotta have help from the compiler, but Wirth never, ever believed in
them.

Of course, if you add any of this you no longer have a sub-4000-line compiler.
The man quests for small compilers the way Percival sought the Grail.

-- 
Larry Smith
  Internet: lsmith@apollo.hp.com
  UUCP:     {decvax,mit-eddie,umix}!apollo!lsmith

preston@titan.rice.edu (Preston Briggs) (10/05/89)

In article <46075cda.1199f@apollo.HP.COM> lsmith@apollo.HP.COM (Lawrence C. Smith) writes:

>Wirth has some very definite blind spots for language design that really puzzle
>me in a man so otherwise gifted.  You'd think that returning records would be
>simple, obvious, and orthogonal and so would be one of his top hot buttons.

>Does Oberon allow them?  Does it allow them but not implement them?
>
>Another of Wirth's blind spots is strings.  To get real efficiency with strings
>you've just gotta have help from the compiler, but Wirth never, ever believed in
>them.

>Larry Smith


Oberon doesn't allow structured types (records or arrays) to be returned
from functions.  There's slightly more suport for strings than
before.  Basically, he's using null-terminated arrays of char,
rather like C.

However, I think he's correct not to allow functions to return
structured values.  In fact, I think he should modify his
standard parameter passing mechanism to something like:

	PROCEDURE zap(VAR a, b, c: aType;
		      CON x, y, z: bType);

This would allow all structured types to be passed by reference,
rather than copying.  If you need to copy it later, fine; but
not as part of the call.  As a bonus, optimizers would be able to do
a better job around procedure calls, without the necessity of
interprocedural analysis.

Overall, I'm down on "hidden" costs arising
from copying large arrays and records.

Regards,
Preston Briggs

lins@Apple.COM (Chuck Lins) (10/05/89)

In article <46075cda.1199f@apollo.HP.COM> lsmith@apollo.HP.COM (Lawrence C. Smith) writes:
>In article <"89-10-03-22:05:28.25*UI0T"@DKAUNI2.BITNET> Modula2 List <INFO-M2%UCF1VM.BITNET@PSUVM.PSU.EDU> writes:
>>Here comes another (more or less necessary) view...
>
	[Refering to returning records as function results]

Oberon specific forbids arrays and records as function results.


-- 
Chuck Lins               | "Exit left to funway."
Apple Computer, Inc.     | Internet: lins@apple.com
20525 Mariani Avenue     | AppleLink: LINS
Mail Stop 41-K           | 
Cupertino, CA 95014      | "Self-proclaimed Object Oberon Evangelist"
I speak for myself and no one else.

lins@Apple.COM (Chuck Lins) (10/05/89)

>However, I think he's correct not to allow functions to return
>structured values.  In fact, I think he should modify his
>standard parameter passing mechanism to something like:
>
>	PROCEDURE zap(VAR a, b, c: aType;
>		      CON x, y, z: bType);
>

One can simply return records and arrays by specifying them as VAR parameters.
If one really wants to specify usage of a parameter you might as well go to
Ada's paramater mode specification of either: in, out, or inout.

-- 
Chuck Lins               | "Exit left to funway."
Apple Computer, Inc.     | Internet: lins@apple.com
20525 Mariani Avenue     | AppleLink: LINS
Mail Stop 41-K           | 
Cupertino, CA 95014      | "Self-proclaimed Object Oberon Evangelist"
I speak for myself and no one else.

MARKV@UKANVAX.BITNET ("MARK GOODERUM - UNIV. OF KANSAS ACS - MARKV@UKANVAX") (10/05/89)

I really don't see what the arguement is.  If you wan't to return an
array or record why not just return the pointer?  Visually it is still
obvious in the code what you are doing and is fast also.  If you want
to return a new record or array, then there is NEW or ALLOCATE.

-Mark Gooderum
 MARKV@UKANVAX

UI0T@DKAUNI2.BITNET (Thomas Koenig) (10/05/89)

MARKV@UKANVAX writes:
> I really don't see what the arguement is.  If you wan't to return an
> array or record why not just return the pointer?  Visually it is still
> obvious in the code what you are doing and is fast also.  If you want
> to return a new record or array, then there is NEW or ALLOCATE.
>
> -Mark Gooderum
>  MARKV@UKANVAX

The point is the following: If I have to do, for example, complex
arithmetic with complicated formulas, I don't want to have to keep
track of what I have allocated in the meantime.  (Ever try a Newton
iteration with a formula like f(x)=exp((a*x**2+b*x+c)/(d*x+e)) ?)
The derivative in the case above is quite complicated, without the
added bother of either
  1) defining my own stack for calculations
  2) using auxilliary variables for intermediate results (I tried
     that once; the result was a program I could not read although
     I had written it)
  3) allocating space for intermediate results which has to be
     deallocated later (or else I am going to see some very strange
     results when space runs out on the heap)
  4) keeping track of real and imaginary parts seperately
In complicated formulas using complex arithmetic, I don't want to do
any of the four above, because the mathematics is bothersome enough
without the added complexity of bookkeeping.  If I can't do it in
Modula, I will do it in FORTRAN or C (FORTRAN because it already has
complex arithmetic).  I don't want to use either language more than I
can help it, because I think Modula is much superior to both of them
in almost every respect, but at present, Modula does not leave me
much of a choice in such matters.
With the possibilities of returning at least records via function
values and with of passing multidimensional arrays of varying size to
procedures, like level 1 ISO Pascal, which allows the construct

procedure something(var a:array[1..n,1..m] of real); ,

after which the array a and the integers n and m can be accessed,
Modula would be my language of choice for numerical work.  As it is
today, it isn't.

Thomas  Koenig                   UI0T@DKAUNI2.BITNET
                                 UI0T%DKAUNI2.BITNET@CUNYVM.CUNY.EDU
                         (soon)  UI0T@IBM3090.RZ.UNI-KARLSRUHE.DE

firth@sei.cmu.edu (Robert Firth) (10/05/89)

In article <INFO-M2%89100500031512@UCF1VM> Modula2 List <INFO-M2%UCF1VM.BITNET@PSUVM.PSU.EDU> writes:
>I really don't see what the arguement is.  If you wan't to return an
>array or record why not just return the pointer?  Visually it is still
>obvious in the code what you are doing and is fast also.  If you want
>to return a new record or array, then there is NEW or ALLOCATE.

Leaving aside the efficiency considerations of using dynamic
storage needlessly, you still cannot do it this way.  The
syntax of Modula-2 does not allow the result of a function call
to be dereferenced.  Yet another mindlessly stupid restriction
whose sole purpose seems to be to enforce one person's view
of programming style on the world.

tom@MIMS-IRIS.WATERLOO.EDU (Tom Haapanen) (10/06/89)

In article <"89-10-03-22:05:28.25*UI0T"@DKAUNI2.BITNET> you write:
> In fact, the proposed
> standard for ANSI-C has required this kind of thing for records (or
> structures, as they are called in C).

No no no ... you should say "this kind of thing for structures (or records,
as they are called in Modula-2)".

:)  :)  :)  :)

                                        \tom haapanen
"now, you didn't really expect          tom@mims-iris.waterloo.edu
 my views to have anything to do        watmims research group
 with my employer's, did you?"          university of waterloo

"I don't even know what street Canada is on"  -- Al Capone

MARKV@UKANVAX.BITNET ("MARK GOODERUM - UNIV. OF KANSAS ACS - MARKV@UKANVAX") (10/06/89)

Are you sure about dereferencing.  What about this imaginary code fragment:

MODULE FakeReturn;

VAR
   FooPtr:      POINTER TO StructuredData;

PROCEDURE GetStructuredData(Some parameters):ADDRESS; (* Forgot to Import *)
                                                      (* ADDRESS, oh well..*)
BEGIN
     do some stuff...
     RETURN(SomeAddress);
END GetStructuredData;

BEGIN
  blah blah.
  FooPtr:=GetStructuredData(blahBlah);
  AReference:=FooPtr^.SomeElement;
END FakeReturn;

I know I didn't declare everything, but this is off the top of my head and
you get the idea.  Now I personally don't see what is wrong with Dynamic
allocation, especially for large arrays, records, etc, since it keeps program
file size down and speeds load times.

In fact I have some programs that are ALL dynamic allocation or local variables
since I occasionally need/want to write reeentrant code.

Cordially,

Mark Gooderum
MARKV@UKANVAX

MARKV@UKANVAX.BITNET ("MARK GOODERUM - UNIV. OF KANSAS ACS - MARKV@UKANVAX") (10/06/89)

One other thought about dynamic allocation.  You only need to allocate
global variables of course, and if you do have an iterative procedure
that needs lots of scratch space what about Mark and Release (although
not all compilers support this kind of heap management).

Other tricks I use to keep track of allocations are software stacks by
pushing size and address on a stack and popping the whole stack and
deallocating, or singly linked list.

But MY big complaint in Modula-2 is lack of easy string support and file
handling.  If I have a program I want to work with several files I either
have to do all the high level stuff myself or be opening and closing files
left and right (now THERE is a way to slow down a machine).

-Mark

Pat.Terry@p101.f4.n494.z5.fidonet.org (Pat Terry) (10/06/89)

In Message-ID: <"89-10-03-22:05:28.25*UI0T"@DKAUNI2.BITNET> Koenig writes

 > How about an extension to the language which would allow functions to
 > return not only predefined types such as integers, reals and so on but
 > also records and arrays? 

That's supposed to be in already.  Certainly will be in the ISO standard.
Some compilres have always had it, others not - usual reason, PIM-2
doesn't discuss it, without saying that records and arrays are wrong either.

 > TYPE COMPLEX= RECORD RE,IM:REAL END;

But if you're proposing an extension, why not propose a proper COMPLEX?

 




--  
-----
uucp: { uunet!tektronix | sun!nosun }!qiclab!m2xenix!puddle!5!494!4.101!Pat.Terry
Internet: Pat.Terry@p101.f4.n494.z5.fidonet.org