[M3devel] mixing INTEGER and LONGINT?

Tony Hosking hosking at cs.purdue.edu
Fri Jan 8 19:19:58 CET 2010


To summarise the discussion so far...

1. Do we really need LONGINT?  Some have expressed a desire for it.  The only use-case so far is large file sizes.

2. If we do need LONGINT then Rodney's proposal seems sound apart from the question of resolution of the builtin overloaded arithmetic operators.  Rodney's proposal is that they resolve to the maximal type of their operands.  Jay, I am very concerned about your definitions for MOD/DIV below because I think they are inherently unintuitive (witness your own claims of "subtlety" -- Modula-3 should not ever have subtle semantics!).  I forget what the rules for C happen to be... (with good reason since I've never wanted to try to remember them and avoid mixed type operands like the plague!).  So, do I hear strong arguments for or against mixed type integer operands?

On 8 Jan 2010, at 12:33, Rodney M. Bates wrote:

> 
> 
> Jay K wrote:
>> This simple diff in the front end allows the "obvious" mixing of INTEGER and LONGINT without any need for ORD or VAL.
>>   LONGINT + INTEGER => LONGINT
>>  LONGINT - INTEGER => LONGINT
>>  LONGINT * INTEGER => LONGINT
>>  LONGINT DIV INTEGER => LONGINT
>>  INTEGER DIV LONGINT => LONGINT (subtle and I think incorrect, should be INTEGER)
>>  INTEGER MOD LONGINT => INTEGER (subtle but I believe correct)   LONGINT MOD INTEGER => INTEGER (subtle but I believe correct)   MIN(INTEGER, LONGINT) => LONGINT (This is wrong actually, should be INTEGER)   MAX(INTEGER, LONGINT) => LONGINT   LONGINT := INTEGER
> 
> Making INTEGER and LONGINT mutually assignable (or even one-way
> assignability of INTEGER to LONGINT) implies all of the above.
> The arithmetic operators are defined as generalizations of Modula-3
> procedures, with parameters of VALUE mode.  And the rule for VALUE
> requires only that the actual be assignable to the formal, not
> have identical type.  This is what I originally proposed.
> 
> Actually, with LONGINT in the picture, the arithmetic operators have
> to be defined more carefully, in order to avoid or remove ambiguity in
> resolution of builtin overloaded arithmetic operators. Particularly,
> we have to eliminate the possibility that, e.g., an expression of the form
> INTEGER <op> INTEGER would resolve to the LONGINT <op> LONGINT -> LONGINT
> operator, by assignability of INTEGER to LONGINT.  This would completely
> the efficiency of native machine arithmetic.
> 
> Whatever we do, I feel very strongly that we should preserve consistency
> with both the existing rules that assignment statements and passing
> VALUE parameters require assignability.  That means that explicitly coded
> VAL/ORD functions will be required either in both assignments and mixed
> arithmetic, or neither.  The same applies to a number of other places
> that require assignability.
> 
> 
>> Other mixes are less obvious and would require runtime checks.
>> I think the backend will just work but I haven't tried that yet.
>> (Truth be told, I can only affectively edit files on NT...)
>> Thoughts?
>>  - Jay
>> Index: builtinOps/Dec.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/builtinOps/Dec.m3,v
>> retrieving revision 1.9
>> diff -u -r1.9 Dec.m3
>> --- builtinOps/Dec.m3 25 Sep 2009 02:42:10 -0000 1.9
>> +++ builtinOps/Dec.m3 8 Jan 2010 07:35:43 -0000
>> @@ -44,7 +44,7 @@
>>     IF (NUMBER (ce.args^) > 1) THEN
>>       IF Type.IsSubtype (t, LInt.T) THEN
>>         t := Type.Base (Expr.TypeOf (ce.args[1]));
>> -        IF (t # LInt.T) THEN
>> +        IF t # LInt.T AND t # Int.T THEN
>>           Error.Txt (name, "second argument must be a LONGINT");
>>         END;
>>       ELSE
>> Index: builtinOps/Max.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/builtinOps/Max.m3,v
>> retrieving revision 1.3
>> diff -u -r1.3 Max.m3
>> --- builtinOps/Max.m3 18 Sep 2007 20:25:36 -0000 1.3
>> +++ builtinOps/Max.m3 8 Jan 2010 07:35:43 -0000
>> @@ -25,11 +25,14 @@
>>  PROCEDURE DoCheck (name: TEXT;  ce: CallExpr.T) =
>>   VAR ta, tb: Type.T;
>> +      resultType: Type.T := NIL;
>>   BEGIN
>>     ta := Type.Base (Expr.TypeOf (ce.args[0]));
>>     tb := Type.Base (Expr.TypeOf (ce.args[1]));
>> -    IF (NOT Type.IsEqual (ta, tb, NIL)) THEN
>> +    IF (ta = LInt.T AND tb = Int.T) OR (tb = LInt.T AND ta = Int.T) THEN
>> +      resultType := LInt.T;
>> +    ELSIF (NOT Type.IsEqual (ta, tb, NIL)) THEN
>>       Error.Txt (name, "incompatible argument types");
>>     ELSIF (ta = Int.T) OR (ta = LInt.T) OR (Type.IsOrdinal (ta)) THEN
>>       (* ok *)
>> @@ -39,7 +42,11 @@
>>       Error.Txt (name, "wrong argument types");
>>       ta := Int.T;
>>     END;
>> -    ce.type := ta;
>> +    IF resultType # NIL THEN
>> +      ce.type := resultType;
>> +    ELSE
>> +      ce.type := ta;
>> +    END;
>>   END DoCheck;
>>  PROCEDURE Compile (ce: CallExpr.T) =
>> Index: exprs/AddExpr.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/AddExpr.m3,v
>> retrieving revision 1.3
>> diff -u -r1.3 AddExpr.m3
>> --- exprs/AddExpr.m3 4 May 2008 11:03:45 -0000 1.3
>> +++ exprs/AddExpr.m3 8 Jan 2010 07:35:43 -0000
>> @@ -67,6 +67,7 @@
>>  PROCEDURE Check (p: P;  VAR cs: Expr.CheckState) =
>>   VAR ta, tb, range: Type.T;
>> +      resultType: Type.T := NIL;
>>   BEGIN
>>     Expr.TypeCheck (p.a, cs);
>>     Expr.TypeCheck (p.b, cs);
>> @@ -74,8 +75,9 @@
>>     tb := Type.Base (Expr.TypeOf (p.b));
>>     IF    (ta = Int.T)   AND (tb = Int.T)   THEN
>>       p.class := Class.cINT;
>> -    ELSIF (ta = LInt.T)  AND (tb = LInt.T) THEN
>> -      p.class := Class.cLINT
>> +    ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
>> +      p.class := Class.cLINT;
>> +      resultType := LInt.T;
>>     ELSIF (ta = Reel.T)  AND (tb = Reel.T)  THEN
>>       p.class := Class.cREAL;
>>     ELSIF (ta = LReel.T) AND (tb = LReel.T) THEN
>> @@ -96,7 +98,11 @@
>>     ELSE
>>       ta := Expr.BadOperands ("\'+\'", ta, tb);
>>     END;
>> -    p.type := ta;
>> +    IF resultType # NIL THEN
>> +      p.type := resultType;
>> +    ELSE
>> +      p.type := ta;
>> +    END;
>>   END Check;
>>  PROCEDURE Prep (p: P) =
>> Index: exprs/DivExpr.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/DivExpr.m3,v
>> retrieving revision 1.5
>> diff -u -r1.5 DivExpr.m3
>> --- exprs/DivExpr.m3 4 May 2008 11:03:46 -0000 1.5
>> +++ exprs/DivExpr.m3 8 Jan 2010 07:35:43 -0000
>> @@ -60,7 +60,7 @@
>>     tb := Type.Base (Expr.TypeOf (p.b));
>>     IF (ta = Int.T) AND (tb = Int.T) THEN
>>       p.type := Int.T;
>> -    ELSIF (ta = LInt.T) AND (tb = LInt.T) THEN
>> +    ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
>>       p.type := LInt.T;
>>     ELSE
>>       p.type := Expr.BadOperands ("DIV", ta, tb);
>> Index: exprs/ModExpr.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/ModExpr.m3,v
>> retrieving revision 1.5
>> diff -u -r1.5 ModExpr.m3
>> --- exprs/ModExpr.m3 4 May 2008 11:03:46 -0000 1.5
>> +++ exprs/ModExpr.m3 8 Jan 2010 07:35:43 -0000
>> @@ -60,6 +60,7 @@
>>  PROCEDURE Check (p: P;  VAR cs: Expr.CheckState) =
>>   VAR ta, tb: Type.T;
>> +      resultType: Type.T := NIL;
>>   BEGIN
>>     Expr.TypeCheck (p.a, cs);
>>     Expr.TypeCheck (p.b, cs);
>> @@ -67,8 +68,18 @@
>>     tb := Type.Base (Expr.TypeOf (p.b));
>>     IF    (ta = Int.T)   AND (tb = Int.T)   THEN
>>       p.class := Class.cINT;
>> +
>>     ELSIF (ta = LInt.T)  AND (tb = LInt.T)  THEN
>>       p.class := Class.cLINT;
>> +
>> +    (* The result of MOD cannot be higher than either of its inputs.
>> +     * small divided by big is 0 remainder small
>> +     * big divided by small has a remainder of at most small
>> +     *)
>> +    ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
>> +      p.class := Class.cINT;
>> +      resultType := Int.T;
>> +
>>     ELSIF (ta = Reel.T)  AND (tb = Reel.T)  THEN
>>       p.class := Class.cREAL;
>>     ELSIF (ta = LReel.T) AND (tb = LReel.T) THEN
>> @@ -78,7 +89,11 @@
>>     ELSE p.class := Class.cERR;  ta := Int.T;
>>       ta := Expr.BadOperands ("MOD", ta, tb);
>>     END;
>> -    p.type := ta;
>> +    IF resultType # NIL THEN
>> +      p.type := resultType;
>> +    ELSE
>> +      p.type := ta;
>> +    END;
>>   END Check;
>>  PROCEDURE Prep (p: P) =
>> Index: exprs/MultiplyExpr.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/MultiplyExpr.m3,v
>> retrieving revision 1.3
>> diff -u -r1.3 MultiplyExpr.m3
>> --- exprs/MultiplyExpr.m3 4 May 2008 11:03:46 -0000 1.3
>> +++ exprs/MultiplyExpr.m3 8 Jan 2010 07:35:43 -0000
>> @@ -66,6 +66,7 @@
>>  PROCEDURE Check (p: P;  VAR cs: Expr.CheckState) =
>>   VAR ta, tb, range: Type.T;
>> +      resultType: Type.T := NIL;
>>   BEGIN
>>     Expr.TypeCheck (p.a, cs);
>>     Expr.TypeCheck (p.b, cs);
>> @@ -73,8 +74,9 @@
>>     tb := Type.Base (Expr.TypeOf (p.b));
>>     IF    (tb = Int.T)   AND (ta = Int.T)   THEN
>>       p.class := cINT;
>> -    ELSIF (tb = LInt.T)  AND (ta = LInt.T)  THEN
>> +    ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
>>       p.class := cLINT;
>> +      resultType := LInt.T;
>>     ELSIF (tb = Reel.T)  AND (ta = Reel.T)  THEN
>>       p.class := cREAL;
>>     ELSIF (tb = LReel.T) AND (ta = LReel.T) THEN
>> @@ -90,7 +92,11 @@
>>       ta := Expr.BadOperands ("\'*\'", ta, tb);
>>       p.class := cINT;
>>     END;
>> -    p.type := ta;
>> +    IF resultType # NIL THEN
>> +      p.type := resultType;
>> +    ELSE
>> +      p.type := ta;
>> +    END;
>>   END Check;
>>  PROCEDURE Prep (p: P) =
>> Index: exprs/SubtractExpr.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/SubtractExpr.m3,v
>> retrieving revision 1.4
>> diff -u -r1.4 SubtractExpr.m3
>> --- exprs/SubtractExpr.m3 4 May 2008 11:03:46 -0000 1.4
>> +++ exprs/SubtractExpr.m3 8 Jan 2010 07:35:43 -0000
>> @@ -73,6 +73,7 @@
>>  PROCEDURE Check (p: P;  VAR cs: Expr.CheckState) =
>>   VAR ta, tb, range: Type.T;
>> +      resultType: Type.T := NIL;
>>   BEGIN
>>     Expr.TypeCheck (p.a, cs);
>>     Expr.TypeCheck (p.b, cs);
>> @@ -80,8 +81,9 @@
>>     tb := Type.Base (Expr.TypeOf (p.b));
>>     IF    (ta = Int.T)   AND (tb = Int.T)   THEN
>>       p.class := Class.cINT;
>> -    ELSIF (ta = LInt.T)  AND (tb = LInt.T)  THEN
>> +    ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
>>       p.class := Class.cLINT;
>> +      resultType := LInt.T;
>>     ELSIF (ta = Reel.T)  AND (tb = Reel.T)  THEN
>>       p.class := Class.cREAL;
>>     ELSIF (ta = LReel.T) AND (tb = LReel.T) THEN
>> @@ -113,7 +115,11 @@
>>       ta := Expr.BadOperands ("\'-\'", ta, tb);
>>       p.class := Class.cINT;
>>     END;
>> -    p.type := ta;
>> +    IF resultType # NIL THEN
>> +      p.type := resultType;
>> +    ELSE
>> +      p.type := ta;
>> +    END;
>>   END Check;
>>  PROCEDURE Prep (p: P) =
>> Index: types/Type.m3
>> ===================================================================
>> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/types/Type.m3,v
>> retrieving revision 1.8
>> diff -u -r1.8 Type.m3
>> --- types/Type.m3 4 May 2008 11:03:49 -0000 1.8
>> +++ types/Type.m3 8 Jan 2010 07:35:43 -0000
>> @@ -543,6 +543,10 @@
>>     IF IsEqual (a, b, NIL) OR IsSubtype (b, a) THEN
>>       RETURN TRUE;
>>     ELSIF IsOrdinal (a) THEN
>> +      (* INTEGER is assignable to LONGINT *)
>> +      IF a = LInt.T AND b = Int.T THEN
>> +        RETURN TRUE;
>> +      END;
>>       (* ordinal types:  OK if there is a common supertype
>>          and they have at least one member in common. *)
>>       IF IsEqual (Base(a), Base(b), NIL)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20100108/c8b64398/attachment-0002.html>


More information about the M3devel mailing list