4

I am trying to figure out whether Oberon allows addressing of a field in a record that is not present in said record's type declaration, but only in one of its extensions and do so without a type guard.

In PIO ("Programming in Oberon") page 62, last sentence of the first paragaph, Wirth writes (1):

This concludes our brief introduction to the object-oriented paradigm of programming. We realize that almost no language features had to be added to Oberon to support it. Apart from the already present facilities of records and of procedural types, only the notion of type extension is both necessary and crucial. It allows to construct hierarchies of types and to build inhomogeneous data structures. As a consequence of abandoning the rule of strictly static typing, the introduction of dynamic type tests became necessary. The further facility of the type guard is merely one of convenience.

In PIO page 59, first three sentences of the last paragraph before scetion 23.2 he writes (2):

The simple designator p.radius would not be acceptable, because p is of type Figure, which does not feature a field radius. With the type guard, the programmer can ascertain that in this case p is also of type Circle, in which case the field radius is indeed applicable. Whereas p is of base type Figure, p(Circle) is of type Circle.

On the one hand I interpret #2 such that the type guard is absolutely necessary in order to be able to address a field that is not in the designator's type declaration. Were it not for the type guard, addressing such a field should cause a compile time error.

On the other hand, if the type guard is merely a convenience as suggested by #1, then it could also be omitted. Its facility would simply be that of an assert and consequently the compiler could allow the addressing of a field that is not in the designator's type declaration.

Since the latter is not type safe I would be surprised if Wirth intended it that way.

I am therefore inclined to completely disregard #1 and implement #2.

Before I bother Wirth with an email I'd appreciate if Oberon practitioners (and compiler implementers) could share how this is interpreted in their respective Oberon compilers.

thanks in advance

trijezdci
  • 5,284
  • 2
  • 19
  • 15

1 Answers1

4

I emailed Professor Wirth to ask for clarification.

It turns out that in the earlier Oberon language reports the statement "merely a convenience" has indeed been misleading because in these versions of Oberon the type guard syntax was necessary to address fields of extensions not present in the base type. There was no other way to do this.

However, as Wirth pointed out, in his latest revision of Oberon the semantics of the CASE statement have been extended to perform both type test and addressing of fields in extensions not present in their base type.

CASE msg OF
  DrawMsg : msg.draw(self)
| MoveMsg : msg.move(self, msg.dx, msg.dy)
...

In this case, neither the IS type test, nor the type guard syntax is strictly necessary. Thus, in the current Oberon version they are indeed merely convenience.

The language report for the latest Oberon version can be found at:

https://www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.Report.pdf

The CASE statement is described in section 9.5.

trijezdci
  • 5,284
  • 2
  • 19
  • 15
  • 1
    One big difference is that the type guard aborts the program if the variable is not of the suggested type, whereas in the CASE statement the program execution may proceed even if a variable is not matched by any type label. – August Karlstrom Dec 07 '15 at 14:56
  • I would consider a compiler that continues in this case to be defective. Of course the compiler should insert the runtime code for checking and raising a runtime fault just as it has to do when checking other runtime conditions such as runtime array boundary violations. – trijezdci Dec 12 '15 at 12:59
  • Then Astrobe is one example of such a "defective" compiler: http://www.astrobe.com/forum/viewtopic.php?f=4&t=456&sid=fc4d5d9e8f5eeaabb0f0d0ea4835eed3#p995 – August Karlstrom Dec 12 '15 at 14:56
  • I'd say it depends, if none of the fields are actually accessed then there is not necessarily a reason to abort. And if you want to abort in case that the type tag doesn't match any of the CASE branches you can raise a runtime fault in the ELSE branch. However, if any access to a field is attempted that is not part of the type then the compiler must abort or it is defective. – trijezdci Dec 12 '15 at 20:55
  • The CASE statement has no ELSE clause. – August Karlstrom Dec 13 '15 at 14:13
  • Thanks for the clarification, but even so, I'd rather add an ELSE clause to the CASE statement than adding a type guard just to cover a very marginal use case. Having two different ways to do the same thing is generally bad design. Even if that same thing turns out ever so slightly different in a very marginal use case. Luckily, I don't need to worry about any of this because I am not actually interested in Oberon itself, but only in its extensive record types as I am in the process of adding those to the M2C Modula-2 compiler which of course has a proper CASE statement with an ELSE clause. – trijezdci Dec 16 '15 at 12:06
  • 1
    I recently discovered that if you use the declared type, e.g. *Message*, as the last label, it will work like an ELSE clause. – August Karlstrom Sep 14 '17 at 10:12