<div dir="ltr">Thomas <div>I am no great specialist anymore on oberon, but as a general rule you could have the Term module totally abstract and let the extensions define the write procedure.</div><div>So then you have only 1 VAR  t*: Term in the abstact Module; and assign the needed PROCEDURE Write( ) to it from the extension module.</div><div><br></div><div>But in your example you might hit other issues. i.e. it is not an ideal example.</div><div><br></div><div>Also read chapter 12 in "Programming in Oberon" Reiser and Wirth. (The green book)</div><div>It has a beautiful example of a drawing program.</div><div><br></div><div>Cheers,</div><div><br></div><div>j.</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Aug 14, 2018 at 1:51 PM, Tomas Kral <span dir="ltr"><<a href="mailto:thomas.kral@email.cz" target="_blank">thomas.kral@email.cz</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
Just reading Oberon book on OOP by Hanspeter Mosenbok. I would like<br>
to set a reusable code pattern for that, not sure how close I am, my<br>
try below. There is also other way of doing it, using so called<br>
`message' handler.<br>
<br>
Cheers Tomas<br>
<br>
MODULE Term; (* TK 14.8.2018 lower/capital case terminal, simple OOP<br>
example *)<br>
  IMPORT Texts, Oberon;<br>
<br>
  TYPE<br>
    Term* = POINTER TO TermDesc;<br>
    TermDesc* = RECORD<br>
      write*: PROCEDURE(t: Term; ch: CHAR)<br>
    END ;<br>
<br>
    VAR<br>
      W: Texts.Writer; t*: Term;<br>
<br>
    (* Generic output routine accepting any Term based type *)<br>
<br>
    PROCEDURE Out*(t: Term; ch: CHAR);<br>
    BEGIN t.write(t, ch)<br>
    END Out;<br>
<br>
    PROCEDURE Write(t: Term; ch: CHAR);<br>
    BEGIN<br>
      Texts.Write(W, ch); Texts.Append(Oberon.Log, W.buf)<br>
    END Write;<br>
<br>
BEGIN  Texts.OpenWriter(W); NEW(t); t.write := Write;<br>
END Term.<br>
<br>
<br>
MODULE CapTerm; (* capital terminal *)<br>
  IMPORT Term, Texts, Oberon;<br>
<br>
  TYPE<br>
    CapTerm* = POINTER TO CapTermDesc;<br>
    CapTermDesc* = RECORD (Term.TermDesc) END ;<br>
<br>
  VAR<br>
     W: Texts.Writer; ct*: CapTerm;<br>
<br>
  PROCEDURE CAP(ch: CHAR): CHAR;<br>
    VAR up: CHAR;<br>
  BEGIN<br>
    up := CHR(ORD(ch) + ORD("A") - ORD("a"));<br>
  RETURN up END CAP;<br>
<br>
  PROCEDURE Write(t: Term.Term; ch: CHAR);<br>
  BEGIN<br>
    IF (ch >= "a") OR (ch <= "z") THEN ch := CAP(ch) END ;<br>
    Texts.Write(W, ch); Texts.Append(Oberon.Log, W.buf)<br>
  END Write;<br>
<br>
BEGIN Texts.OpenWriter(W); NEW(ct); ct.write := Write;<br>
END CapTerm.<br>
<br>
<br>
MODULE TestTerm;<br>
  IMPORT Term, CapTerm, Texts, Oberon;<br>
<br>
  VAR<br>
    W: Texts.Writer; t: Term.Term; ct: CapTerm.CapTerm;<br>
<br>
  PROCEDURE Run*;<br>
    VAR S: Texts.Scanner;<br>
  BEGIN<br>
    Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);<br>
  Texts.Scan(S);<br>
    WHILE S.class = Texts.Name DO<br>
      Term.Out(t, S.s[0]); Term.Out(ct, S.s[0]);<br>
      Texts.Scan(S)<br>
    END ;<br>
    Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)<br>
  END Run;<br>
<br>
BEGIN Texts.OpenWriter(W); t := Term.t; ct := CapTerm.ct;<br>
END TestTerm.<br>
<br>
TestTerm.Run  a b c ~<br>
<span class="HOEnZb"><font color="#888888"><br>
<br>
<br>
-- <br>
Tomas Kral <<a href="mailto:thomas.kral@email.cz">thomas.kral@email.cz</a>><br>
--<br>
<a href="mailto:Oberon@lists.inf.ethz.ch">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems<br>
<a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" rel="noreferrer" target="_blank">https://lists.inf.ethz.ch/<wbr>mailman/listinfo/oberon</a><br>
</font></span></blockquote></div><br></div>