[comp.lang.modula2] You're not my type!

MSRS002@ECNCDC.BITNET ("THE DOCTOR.") (07/01/89)

This might be a question for the Zurich crew.

In the following module, are the types OneType and AnotherType compatible?
PIM3 seems to say they are both compatible with CARDINAL, but doesn't say
much about compatibility with each other.  I tried the module in JPI
TopSpeed version 1.17, and it found nothing to complain about.  I don't
think OneType and AnotherType are compatible.  Are they, or should they be?

MODULE WhatType ;

(* This module was created to answer a question about Type Checking *)

TYPE
  OneType = CARDINAL ;
  AnotherType = CARDINAL ;

VAR
  A : OneType ;
  B : AnotherType ;
  C : CARDINAL ;

BEGIN

(* Statement       My Opinion  *)
  A := C ;         (* Ok *)
  A := A + C ;     (* Ok *)
  B := C ;         (* Ok *)
  B := B + C ;     (* Ok *)
  A := B ;         (* No *)
  A := B + A ;     (* No *)
  END WhatType .


+-----------------+------------------------------------------------+
  Tom Ruby          Disclaimer:  Since I'm my own employer, the
  MSRS002@ECNCDC         views stated here are my own, and not
                         necessarily those of myself.
+-----------------+------------------------------------------------+
  Observation:  When a company is to big for innovation, it
  resorts to litigation.
+------------------------------------------------------------------+

neitzel@tubsibr.uucp (Martin Neitzel) (07/05/89)

Hi again!

> MSRS002@ECNCDC.BITNET ("THE DOCTOR."), slightly reformatted:
DOC>
DOC>	TYPE  OneType = CARDINAL;  AnotherType = CARDINAL;
DOC>	
DOC>	Are the types OneType and AnotherType compatible?  PIM3 seems
DOC>	to say they are both compatible with CARDINAL, but doesn't say
DOC>	much about compatibility with each other.

(I'm definitely not a member of the Zuerich crew, but anyway...)

You are right, pim3 doesn't say if type compatibility is a "transitive
property".

DOC>	I don't think OneType and AnotherType are compatible.  Are
DOC>	they, or should they be?

I consider them compatible.  Our different views may both be legal.

The basic reason for my view is probably the notational syntax for
type declarations: "TYPE a = b".  This suggests "type equality", and I
personally like to transfer the transitivity associated with the
mathematic equality to the compatibility of types.  ("Types declared
as equal", as the tutorial on page 65 puts it.)

But, as you have said, there is no further formal backup enforcing
this view, and you are entitled to think differently.  So, I am not
able to decide the question "Are they [compatible]?", but I can show
that they well may be.

The question of type equality is one of the major problems that our
students here run into.  This how we try to explain the "transitive
model" to them.

(This may be bothering to you, Tom, and a lot of others.  But I figure
there may be some beginners who are interested in it, and so I will
pound on this a bit.  It will explain how your JPI may compiler work,
too, but if you know all this: Skip to the next section, the "Should
they?")

\begin {tutorial}

Internally, Modula types are some kind of object with some associated
descriptive information (say, memory requirements for one data value
of this type, alignment, range of valid values, constituent types...)
Initially, each basic type is represented in this way.  To make them
accessible to the poor programmer, they must be given names like
INTEGER, CHAR, BOOLEAN...  The symbol table (one or more of them) will
usually be used to provide these links "name -> internal type
description".

The language provides mechanisms to build new anonymous types: e.g.
"VAR z,x RECORD i,r: REAL END" will implicitly construct a new record
type (==internal description for it).  (Sometimes, new types will be
created implicitly even when the user is not aware of it, e.g. VAR
parameters may lead to the construction of new POINTER types.)

Such types are anonymous because there is no identifier associated
with them.

The only way to give a (new) name to a type is the type declaration,
"TYPE foo = <id-referring-to-a-type or anon-type-constructor>".
First, this will either find the type referred to or create a new
anonymous type.  Then, the id "foo" is simply linked to it (as a new
symbol entry).

Some expamples:

TYPE	A = ARRAY [0..99] OF CHAR;		(* PIM3, p.65 *)
	B = ARRAY [0..99] OF CHAR;
	C = A;

Here, both the two ARRAY constructors will create a new internal type
each, and the symbols A and B get linked to them, respectively.
C will just be a second link to the first array.

All internal work is done referring directly to the internal type
descriptions.  This is where A and C are "equal types" in this model,
but A and B not.

You can link more identifiers to the first array, by declarations like
		TYPE  D = A;  E = A;  F = D;
Since all id's refer to the same internal type, they are all equal (and
compatible).

Your example under this model:

TYPE	OneType		= CARDINAL;
	AnotherType	= CARDINAL;

We end up with three identifiers referring to the internal cardinal
type (CARDINAL being the first one).  The second line could also have
been "AnotherType = OneType", there wouldn't be any difference.

\end {tutorial}

This model shows a "conforming behaviour".  As you said, it might also
be conforming to provide a compiler with a non-transitive behaviour,
supporting a useful, more rigid form of type strictness.  There is
nothing ``wrong'' with this.  However, it has its drawbacks too.

Remember the Frederico Heintz' STACK module on top of the LIST module?
Consider the following example in the context of non-transitive type
compatability:

MODULE A; TYPE TA = ...;  PROCEDURE DoItToA (a: TA) ...
MODULE B; TYPE TB = TA ;  PROCEDURE DoItToB (b: TB) BEGIN DoItToA(b); ...
MODULE C; TYPE TC = TB ;  PROCEDURE DoItToC (c: TC) BEGIN DoItToB(c); ...
MODULE D; TYPE TD = TC ;  PROCEDURE DoItToD (d: TD) BEGIN DoItToC(d); ...

This would still be legal.  But note that you probably aren't allowed
to skip intermediate levels.  That is, a call DoItToA(d) would be
illegal (even if such a thing will happen finally if it gets triggered
by DoItToD(d)).  The consequence is: You can't "pass" low-level
functionality to higher levels.  You must re-implement functions at
each intermediate level if you don't want to loose them.  Depending on
one's preferences, this can outweigh the benefits of a stronger type
checking, perhaps by far.

[NB1: You may modify all or some of the procedure parameters in this
example to call-by-ref to yield other potentially interesting
variants.  Also note that PIM4 introduces changes in the requirements
for the types of VAR parameters.  This could get hairy, I don't
*wanna* know...]

[NB2: The language Ada gives you both possibilities: You can derive a
compatible type as well as a "new", incompatible type from an existing
type.  Really nice.]

							Martin

nagle@well.UUCP (John Nagle) (07/24/89)

In article <NEITZEL.89Jul5042938@pollux.uucp> neitzel@tubsibr.uucp (Martin Neitzel) writes:
>
>> MSRS002@ECNCDC.BITNET ("THE DOCTOR."), slightly reformatted:
>DOC>
>DOC>	TYPE  OneType = CARDINAL;  AnotherType = CARDINAL;
>DOC>	
>DOC>	Are the types OneType and AnotherType compatible?  PIM3 seems
>DOC>	to say they are both compatible with CARDINAL, but doesn't say
>DOC>	much about compatibility with each other.
>
      It's really annoying that this comes up in Modula 2.  It was 
ambiguous in Pascal, it was ambiguous in Modula 1, and it's still giving
trouble.  At least Wirth is consistent; each new language definition
contains the same old bugs.

      Neitz gives a nice description of the argument for type compatability
by form.  There is also a good argument for compatibility by name.  One
might wish to declare types named, say, "Inches" and "Pounds", or even
"ProcessTableIndex" and "FileTableIndex" and have them be protected from
use with the wrong procedures.  Ideally, you should be able to make a
type opaque when this sort of behavior is desired.  Unfortunately,
opaque types in Modula 2 are very limited; they must be pointers.
This simplifies separate compilation, but makes the concept much less
useful.

      Of course, what we are really doing here is trying to sneak up
on object-oriented programming.  You really want the ability to declare
variables of opaque types, have them initialized properly, have them
be protected from modification outside their own module, and have them
closed out properly when they become deleted through exit from a dynamic
scope.   This describes the basics of an object-oriented programming
system.  In many ways, object-oriented programming is the end of a long
road that began with the introduction of strong typing.  Trying to fix
the typing mess short of fully supporting objects is very painful.
Ada represents a good try.

					John Nagle