[Oberon] Protocols (interfaces) in Oberon-2

Charles Perkins chuck at kuracali.com
Sun Oct 25 16:01:56 CET 2020


Apologies for this : " x0, x1, u: REAL;" was a fragment that snuck in from
testing. I have the above code successfully parsing in a fork of Andreas's
Extended Oberon compiler. I don't have the method table generation code
working yet. It turns out that the Run-time needs to have symbolic type
information available, which could be simply loading the smb file alongside
the rsc file for code that uses interfaces, or it could involve embedding a
hash of the name and parameters of the type-bound procedure in another
section of the rsc file. I haven't decided yet.

On Sun, Oct 25, 2020 at 7:33 AM Charles Perkins <chuck at kuracali.com> wrote:

> I think Interfaces / Protocols / Dynamic Traits (what Rust calls them)
> would be a quite useful extension to Oberon. I'm looking at doing it a
> different way, like this:
>
>   VAR W: Texts.Writer;
>
>   TYPE
>        I* = POINTER TO IDesc;
>        IDesc* = RECORD
>             h: INTEGER
>        END ;
>
>        R* = POINTER TO RDesc;
>        RDesc* = RECORD
>             h: REAL
>        END ;
>
>        Stringer* = INTERFACE OF
>             PROCEDURE String* (VAR a: ARRAY OF CHAR) ;
>        END ;
>
>
>   PROCEDURE ( i : I ) String* (VAR a: ARRAY OF CHAR) ;
>   BEGIN a := "integer"
>   END String;
>
>   PROCEDURE ( r : R ) String* (VAR a: ARRAY OF CHAR) ;
>   BEGIN a := "real"
>   END String;
>
> In the above scheme an Interface looks just like a collection of
> type-bound procedure definitions with no bodies.
>
> The trick is when it comes time to use the interface, which is when the
> code needs to know which actual procedure to call based on the record type
> assigned to it during execution. The record type assigned to an interface
> could be any record that contains the String type-bound procedure (in this
> case.) It might be the first method, or the third, or the sixth... Go
> solves this by generating a dispatch table for the Interface when a type is
> assigned to it.
>
> In Oberon that table-making routine could be satisfied by adding another
> Trap condition in Kernel.Trap much like how New is implemented.
>
>   PROCEDURE Test*;
>       VAR i: I; r: R; t: ARRAY 32 OF CHAR;
>         s,s2: Stringer;
>         x0, x1, u: REAL;
>
>   BEGIN
>       NEW(i); NEW(r);
>       i.h := 3;
>       r.h := 7.5;
>       s := i;
>       s.Stringer(t);
>       Texts.WriteString(W,t);
>       s := r;
>       s.Stringer(t);
>       Texts.WriteString(W,s);
>    END Test;
>
> The above idea for Interfaces builds on the mechanisms already in place in
> the Oberon-2 compiler and run-time. I think it would be quite useful for
> allowing a program to choose from multiple implementations of an interface
> without constraining them to derive from the same base type while still
> keeping strong static typing and separate linking and loading.
>
> Chuck
>
> On Sun, Oct 25, 2020 at 6:27 AM Luca Boasso <luke.boasso at gmail.com> wrote:
>
>> A key feature of protocols / interfaces is the safe multiple inheritance:
>> you can explicitly or implicitly (like in the Go language) implement
>> several interfaces and be type compatible with each one of them.
>>
>> Do you support something like the following?
>>
>> TextDesc = RECORD (TextProtocol.TextDesc, WriteProtocol.WriterDesc) END
>> ;  (*this means: “implements TextProtocol.TextDesc AND
>> WriteProtocol.WriterDesc "*)
>>
>> If this is not supported I don't see this feature being that useful. To
>> support the feature above the implementation is more complicated than
>> Oberon-2's bound procedures. See https://research.swtch.com/interfaces
>> for one way of doing this, or "Efficient implementation of Java
>> interfaces: Invokeinterface considered harmless"
>> <http://www.academia.edu/download/42084165/Efficient_Implementation_of_Java_Interfa20160204-28309-28q4h3.pdf>
>>
>> On Sun, Oct 25, 2020 at 6:46 AM Andreas Pirklbauer <
>> andreas_pirklbauer at yahoo.com> wrote:
>>
>>> Correction: In Text1, it’s TextDesc = RECORD (TextProtocol.TextDesc) of
>>> course
>>>
>>> —————————
>>>
>>> Protocols (sometimes called interfaces) can be added to
>>> Oberon-2 without adding any keywords to the language.
>>>
>>> This is one of the key differences to how it is usually defined
>>> and implemented, e.g. in Swift [*] or in Integrated Oberon [**]
>>>
>>> Under the new minimalistic design, what distinguishes a protocol
>>> from an actual implementation (of the class) is that in the protocol
>>> definition the implementations of the class methods are simply not
>>> defined. Instead, any module that *imports* a protocol definition
>>> can “adopt” (i.e. implement) it. See the example below.
>>>
>>> An experimental implementation showed that if the language
>>> is extended in *this* way, the implementation cost is minimal.
>>>
>>> But the question is: Is it worth it? Simplicity of implementation
>>> should of course not be a criteria for adopting a new feature.
>>>
>>> Personally, I am rather sceptical of the usefulness of protocols.
>>> But perhaps someone provides a good reason to adopt them.
>>>
>>> -ap
>>>
>>>
>>> Example:
>>>
>>>   MODULE TextProtocol;  (*protocol definition*)
>>>     TYPE Text = POINTER TO TextDesc;
>>>       TextDesc = RECORD data*: (*text data*) END ;
>>>       PROCEDURE (t: Text) Insert (string: ARRAY OF CHAR; pos: LONGINT);
>>>       PROCEDURE (t: Text) Delete (from, to: LONGINT);
>>>       PROCEDURE (t: Text) Length (): LONGINT;
>>>   END TextProtocol;
>>>
>>>   MODULE Text1; (*one implementation of the Text protocol*)
>>>     IMPORT TextProtocol;
>>>     TYPE Text = POINTER TO TextDesc;
>>>       TextDesc = RECORD (TextProtocol.TextDesc) END ;  (*this means:
>>> “implements TextProtocol.TextDesc"*)
>>>
>>>     PROCEDURE (t: Text) Insert (string: ARRAY OF CHAR; pos: LONGINT);
>>>     BEGIN (*implementation of Insert*)
>>>     END Insert;
>>>
>>>     PROCEDURE (t: Text) Delete (from, to: LONGINT);
>>>     BEGIN (*implementation of Delete*)
>>>     END Delete;
>>>
>>>     PROCEDURE (t: Text) Length (): LONGINT;
>>>     BEGIN (*implementation of Length*)
>>>     END Insert;
>>>   END Text1;
>>>
>>>
>>>   MODULE Text2; (*another implementation of the Text protocol*)
>>>     IMPORT TextProtocol;
>>>     TYPE Text = POINTER TO TextDesc;
>>>       TextDesc = RECORD (TextProtocol.TextDesc) END ;  (*this means:
>>> “implements TextProtocol.TextDesc"*)
>>>
>>>     PROCEDURE (t: Text) Insert (string: ARRAY OF CHAR; pos: LONGINT);
>>>     BEGIN (*implementation of Insert*)
>>>     END Insert;
>>>
>>>     PROCEDURE (t: Text) Delete (from, to: LONGINT);
>>>     BEGIN (*implementation of Delete*)
>>>     END Delete;
>>>
>>>     PROCEDURE (t: Text) Length (): LONGINT;
>>>     BEGIN (*implementation of Length*)
>>>     END Insert;
>>>   END Text2;
>>>
>>>
>>> [*] https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#
>>> [**] https://github.com/io-core/technotes/blob/main/technote014.md
>>>
>>> --
>>> Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems
>>> https://lists.inf.ethz.ch/mailman/listinfo/oberon
>>>
>> --
>> Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems
>> https://lists.inf.ethz.ch/mailman/listinfo/oberon
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.inf.ethz.ch/pipermail/oberon/attachments/20201025/50d6b582/attachment.html>


More information about the Oberon mailing list