[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