Oberon-2 *restriction* proposal 
Author Message
 Oberon-2 *restriction* proposal

With respect to dynamic type testing and guarding,
Oberon-2 offers some redundancy:

(i)   type test  (VarIdent "IS" TypeIdent),
(ii)  type guard  (VarIdent "(" TypeIdent ")"),
(iii) type tests with regional type guards  ("WITH" statement).

      (Recall that the WITH statement was promoted from a simple
       regional type guard in Oberon(-1) to a multi-case type test
       with guards in Oberon-2.)

Actually, (iii) covers (i) and (ii) and would thus be sufficient.
BTW, I find the function-like syntax of (ii)  VarIdent "(" TypeIdent ")"
particularly confusing.  IMHO, at least (ii) could be dropped.

Any Comments?

(Unless I get bashed too badly, my next proposal will possibly refer to
 the second-order facilities.)

--



Fri, 23 Feb 1996 17:03:28 GMT  
 Oberon-2 *restriction* proposal

Quote:

>With respect to dynamic type testing and guarding,
>Oberon-2 offers some redundancy:

>(i)   type test  (VarIdent "IS" TypeIdent),
>(ii)  type guard  (VarIdent "(" TypeIdent ")"),
>(iii) type tests with regional type guards  ("WITH" statement).

>      (Recall that the WITH statement was promoted from a simple
>       regional type guard in Oberon(-1) to a multi-case type test
>       with guards in Oberon-2.)

>Actually, (iii) covers (i) and (ii) and would thus be sufficient.
>BTW, I find the function-like syntax of (ii)  VarIdent "(" TypeIdent ")"
>particularly confusing.  IMHO, at least (ii) could be dropped.

There are some relevant differences between (i) and (ii) on one side and
(iii) on the other side. (i) delivers a boolean result whether some object
is of a certain type (that is, it is an expression), (ii) delivers a reference
to an object of a certain type (that is, it is a designator), while (iii)
is a statement with non-local effects. Let me give you some examples that
you cannot express nicely using just (iii).

        (a)     SomeProc(operand(Constant))

        (b)     SomeOtherProc(operand IS Constant)

        (c)     b.isConstant := (operand0 IS Constant) & (operand1 IS Constant)

        (d)     WHILE ~(block IS Header) DO ... END

        (e)     instr.operand(Constant).val := 0

(a) would require that you surround it with a WITH-statement, (b) requires an
additional WITH-statement and a boolean variable just to evaluate the
condition, (c) two nested WITH-statements, (d) two additional WITH-statements
and a boolean variable, and (e) a variable to keep "instr.operand".

On the other hand, the non-local effects of the WITH-statement are not such
a great thing. From the Oberon report (section 9.10 With statements):

        If a pointer variable or a variable parameter with record structure is
        of a type T0, it may be designated in the heading of a with clause
        together with a type T that is an extension of T0. Then the variable
        is guarded within the with statement as if it had been declared of
        type T. [...]

Now assume v is a parameter of this procedure of type T0, and we do have
another variable w of type T0.

        PROCEDURE p (VAR v: T0);
          VAR w: T0;
        BEGIN
          WITH v: T DO p(w) ... END
          ...

This procedure will not compile, as the parameter 'v' of 'p' looks as if it
had been declared as 'T' inside the WITH statement, so p(w) will not compile
as 'w' is not assignment compatible to 'v:T'.

This is one example of the non-local effects of the WITH statement. Another
one are problems with non-local pointers that lead to the warnings that the
compilers omit on encountering some WITH statements.

        VAR
          root: Node;

        PROCEDURE q;
        BEGIN NEW(root)
        END q;

        PROCEDURE p;
        BEGIN
          WITH root: ExtendedNode DO
            q;
            (* here, root is not an ExtendedNode any more, although the
               WITH statement implies this
            *)
        END p

Considering that the desired and safe effects of the WITH statement can be
achieved using (i) and (ii), I would rather vote for dropping (iii) and
leaving the other two in the language. The main objective against dropping
the WITH statement is performance, as it has to be replaced by guarding the
designator on each occurence. A simple compiler may not be able to remove
redundant guards, making some kinds of code considerably slower.

Marc

Marc-Michael Brandis
Institute for Computer Systems
ETH-Zentrum (Swiss Federal Institute of Technology)
CH-8092 Zurich, Switzerland



Sat, 24 Feb 1996 00:32:57 GMT  
 Oberon-2 *restriction* proposal


wrote about the non-local effects of WITH statements:

Quote:
> Now assume v is a parameter of this procedure of type T0, and we do have
> another variable w of type T0.

>       PROCEDURE p (VAR v: T0);
>         VAR w: T0;
>       BEGIN
>         WITH v: T DO p(w) ... END
>         ...

> This procedure will not compile, as the parameter 'v' of 'p' looks as if it
> had been declared as 'T' inside the WITH statement, so p(w) will not compile
> as 'w' is not assignment compatible to 'v:T'.

Do you mean it seriously that a WITH statement on a formal argument (v)
affects the signature of the procedure (p) ?

Quote:

> [explanations of the insecurity of the WITH statement deleted]
> Considering that the desired and safe effects of the WITH statement can be
> achieved using (i) and (ii), I would rather vote for dropping (iii) and
> leaving the other two in the language. The main objective against dropping
> the WITH statement is performance, as it has to be replaced by guarding the
> designator on each occurence. A simple compiler may not be able to remove
> redundant guards, making some kinds of code considerably slower.

Well, are we speaking of the WITH statement as a notational convenience
(which then might make other notations obsolete because it covers the
most frequent cases, IMHO), or as a construct with its own
--possibly insecure-- semantics?

A regional guard could very well be understood as a purely notational
facility which does not impair security (nor immediately implies
greater efficiency).

Section 9.11 in "The Programming Language Oberon-2" is self-
contradictory in this respect:  First, it states that WITH statements

  "... apply a type guard to every occurrence of the tested variable
   within this statement sequence";

later on, it speaks of the guarded variable

  "... where v is regarded as if it had the static type T1",

which suggests that there is only one type test at the entry of the
WITH statement but no further type tests in its body.

Which semantics was actually intended for the WITH statement?  Putting
things straight would give a reasonable basis for further discussion.

--



Sat, 24 Feb 1996 17:23:58 GMT  
 Oberon-2 *restriction* proposal

Quote:


>wrote about the non-local effects of WITH statements:

>> Now assume v is a parameter of this procedure of type T0, and we do have
>> another variable w of type T0.
>>       PROCEDURE p (VAR v: T0);
>>         VAR w: T0;
>>       BEGIN
>>         WITH v: T DO p(w) ... END
>>         ...
>> This procedure will not compile, as the parameter 'v' of 'p' looks as if it
>> had been declared as 'T' inside the WITH statement, so p(w) will not compile
>> as 'w' is not assignment compatible to 'v:T'.

>Do you mean it seriously that a WITH statement on a formal argument (v)
>affects the signature of the procedure (p) ?

Not exactly.  The WITH statement affects the variable that it is acting
upon.  In this case, the type of the parameter is changed during the
compilation of the WITH statement.  That is, when p(w) is encountered, the
actual parameter's type (which is T0) is checked against the formal
parameter's type (which in this case is 'masked' to be 'T'..  Getting an
error message for this case is particularly confusing.

Performing p(w) outside the WITH statement, or within a with v:T0 would be
perfectly legal.

- Show quoted text -

Quote:

>Section 9.11 in "The Programming Language Oberon-2" is self-
>contradictory in this respect:  First, it states that WITH statements

>  "... apply a type guard to every occurrence of the tested variable
>   within this statement sequence";

>later on, it speaks of the guarded variable

>  "... where v is regarded as if it had the static type T1",

>which suggests that there is only one type test at the entry of the
>WITH statement but no further type tests in its body.

>Which semantics was actually intended for the WITH statement?  Putting
>things straight would give a reasonable basis for further discussion.

There is no actual need to apply a 'type guard to each occurrence'.  The
WITH will verify that the type is valid at the beginning, and then 'v is
regarded as if it had the static type of T1'.  A case where a warning
should be issued is if you alter the WITHed variable, as it may no longer
actually be a T1.

Taylor "FederalHolidayMan" Hutt
Favorite dessert: cheese cake.  Least favorite dessert: Bleu Cheese cake.



Sat, 24 Feb 1996 19:40:05 GMT  
 Oberon-2 *restriction* proposal

I wrote about the non-local effects of WITH statements:

Quote:
>>       PROCEDURE p (VAR v: T0);
>>         VAR w: T0;
>>       BEGIN
>>         WITH v: T DO p(w) ... END
>>         ...

>> This procedure will not compile, as the parameter 'v' of 'p' looks as if it
>> had been declared as 'T' inside the WITH statement, so p(w) will not compile
>> as 'w' is not assignment compatible to 'v:T'.

>Do you mean it seriously that a WITH statement on a formal argument (v)
>affects the signature of the procedure (p) ?

Yes. The formal argument is part of the signature, so making v 'look as if it
had been declared as T' also affects the signature. I am not saying that this
is the only possible semantics of it, but this is the way it is now.

Quote:

> [explanations of the insecurity of the WITH statement deleted]
>> Considering that the desired and safe effects of the WITH statement can be
>> achieved using (i) and (ii), I would rather vote for dropping (iii) and
>> leaving the other two in the language. The main objective against dropping
>> the WITH statement is performance, as it has to be replaced by guarding the
>> designator on each occurence. A simple compiler may not be able to remove
>> redundant guards, making some kinds of code considerably slower.

>Well, are we speaking of the WITH statement as a notational convenience
>(which then might make other notations obsolete because it covers the
>most frequent cases, IMHO), or as a construct with its own
>--possibly insecure-- semantics?

The WITH statement is not just a notational convenience. Note that other such
'notational conveniences' were dropped when Oberon was developed, for example
the unqualified import. I believe the most important reason for its
introduction was efficiency.

In my opinion, there are enough cases where having just the WITH statement
would be a major inconvenience. Let me give you an additional example, where
it really is a pain.

        TYPE
          Node = POINTER TO NodeDesc;
          NodeDesc = RECORD
          END;
          ListNode = POINTER TO ListNodeDesc;
          ListNodeDesc = RECORD (NodeDesc)
            x: INTEGER;
            next: Node
          END;

        VAR
          p: Node;
        BEGIN
          p := root;
          WHILE (p # NIL) & (p(ListNode).x # key) DO
            p := p(ListNode).next
          END

Writing this using the WITH statement would get you more complex code which is
harder to read in my opinion.

        VAR
          found: BOOLEAN; p, q: Node;
        BEGIN
          p := root; found := FALSE;
          WHILE (p # NIL) & ~found DO
            WITH p: ListNode DO found := p.x # key; q := p.next END;
            IF ~found THEN p := q END
          END

Quote:
>A regional guard could very well be understood as a purely notational
>facility which does not impair security (nor immediately implies
>greater efficiency).

How would that be defined? Would it also apply to complex designators, e.g.
could I write

        WITH p.next : ListNode DO ... END

? For a notational convenience, this looks reasonable to me. But there are
more complex cases, e.g.

        WITH p.a[i+1] : ListNode DO ... END

Which designators would that guard apply to? Would it mean that every
occurence of 'p.a[i+1]' (lexically) would be guarded, or would 'p.a[i]' also
be guarded?

Quote:
>Section 9.11 in "The Programming Language Oberon-2" is self-
>contradictory in this respect:  First, it states that WITH statements

>  "... apply a type guard to every occurrence of the tested variable
>   within this statement sequence";

>later on, it speaks of the guarded variable

>  "... where v is regarded as if it had the static type T1",

>which suggests that there is only one type test at the entry of the
>WITH statement but no further type tests in its body.

Agreed. This is why I used the definition in the original Oberon report. The
idea is that there is only a single type test at the entry of the WITH
statement.

Marc-Michael Brandis
Institute for Computer Systems
ETH-Zentrum (Swiss Federal Institute of Technology)
CH-8092 Zurich, Switzerland



Sat, 24 Feb 1996 19:31:41 GMT  
 Oberon-2 *restriction* proposal


statement:

Quote:
>There is no actual need to apply a 'type guard to each occurrence'.  The
>WITH will verify that the type is valid at the beginning, and then 'v is
>regarded as if it had the static type of T1'.  A case where a warning
>should be issued is if you alter the WITHed variable, as it may no longer
>actually be a T1.

Oberon does not assume that you apply the type guard to each occurence,
although the language definition does not explicitly prohibit this. As you
raised the issue of assignments to the WITHed variable, this is a case where
applying the guard is actually very different from the definition of the
WITH in the original Oberon report, where 'v ... as if it had been declared
of type T1'.

        WITH p: T1 DO
          p := q
          ...
        END

In this case, you can only compile it if 'q' statically is a T1 or an extension
of T1. This is not the same as

        p(T1) := q

where it is checked whether the object referenced by 'p' is a T1. Such
assignments to the WITHed variable are not dangereous, however, as the guard
made in the WITH clause still holds, and as T1 must be an extension of the
static type of p, you cannot make unsafe assignments this way.

The dangereous case is another one, and that one is not so simple to recognize.
It would require interprocedural information, and when used in conjunction
with other modules could not be recognized at all.

        VAR
          p: T;

        PROCEDURE Proc (VAR q: T);
        BEGIN
          WITH q: T1 DO
            NEW(p);     (* p will now point to a T, and not to an extension *)
            q.x := ...  (* dangereous operation, see below *)
          END
        END Proc;

        BEGIN
          Proc(p)
        END

In this example, 'q' is guarded to a T1, then 'p' is changed. If 'q' is an
alias for 'p' - which it is if you call Proc(p) - the modification of p will
also modify q and therefore violate the guard. The assignment to 'q.x' may
be outside of the allocated storage for 'p' and may even overwrite other
data structures.

Marc-Michael Brandis
Institute for Computer Systems
ETH-Zentrum (Swiss Federal Institute of Technology)
CH-8092 Zurich, Switzerland



Sat, 24 Feb 1996 22:39:24 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. >Oberon-2 *restriction* proposal

2. One more Oberon restriction proposal

3. CCR restrictions (was Re: Local Antenna Restrictions)

4. Unofficial list of Oberon language and library proposals

5. Unofficial list of Oberon language and library extension proposals

6. proposal for a module for dynamic strings in Oberon-2

7. Closures in Oberon - A Modest Proposal (long)

8. Subject: A proposal (Another proposal)

9. Frage Oberon 3 / Question Oberon 3

10. CD-Oberon - Oberon/F

11. CD-Oberon Oberon 3 Printer Problem

12. Oberon System 3 / Native Oberon projects

 

 
Powered by phpBB® Forum Software