<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Tomas<div class=""><br class=""></div><div class="">In your code you had the following question:<div class=""><div class="">   PROCEDURE Write(t: Term.Term; ch: CHAR);<br class=""><blockquote type="cite" class=""></blockquote>    BEGIN<br class=""><blockquote type="cite" class=""></blockquote>      ch := CAP(ch); Texts.Write(W, ch); Texts.Append(Oberon.Log, W.buf)<br class=""><blockquote type="cite" class=""></blockquote><font color="#ff2600" class="">      (* could we call base Write instead of Texts.Write/Append ? *)<br class=""></font>    END Write;<div><br class=""></div><div>Yes, you can. You could e.g. modify three lines of your CapTerm as follows:</div><div><br class=""></div><div>Instead of </div><div>(*1*)   VAR W: Texts.Writer; m: Term.Methods;</div><div>(*2*)   PROCEDURE Init*(t: CapTerm; color: INTEGER (* other data for the</div><div> CapTerm if any *) ); BEGIN t.do := m; t.col := color END Init;</div><div>(*3*) BEGIN Texts.OpenWriter(W); NEW(m); Term.InitMethods(m); m.Write := Write</div><div><br class=""></div><div>You write</div><div><div><div>(*1*)   VAR W: Texts.Writer; <font color="#ff2600" class="">self, super</font>: Term.Methods;</div><div>(*2*)   PROCEDURE Init*(t: CapTerm; color: INTEGER (* other data for the</div><div> CapTerm if any *) ); BEGIN t.do := <font color="#ff2600" class="">self</font>; t.col := color END Init;</div><div>(*3*) BEGIN Texts.OpenWriter(W); NEW(<font color="#ff2600" class="">super</font>); Term.InitMethods(<font color="#ff2600" class="">super</font>); <font color="#ff2600" class="">NEW(self); self^:= super^; self.</font>Write := Write</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">After these three modifications your CapTerm.Write could look like this:</div><div class="">   PROCEDURE Write(t: Term.Term; ch: CHAR);<br class=""><blockquote type="cite" class=""></blockquote>    BEGIN<br class=""><blockquote type="cite" class=""></blockquote>      ch := CAP(ch); super.Write(t, ch)<br class="">    END Write;</div><div class=""><br class=""></div><div class=""><br class=""></div></div><div class="">br</div></div><div>Jörg<br class=""><blockquote type="cite" class=""><div class="">Am 15.08.2018 um 14:34 schrieb Tomas Kral <<a href="mailto:thomas.kral@email.cz" class="">thomas.kral@email.cz</a>>:</div><br class="Apple-interchange-newline"><div class=""><div class="">Hi,<br class=""><br class="">I have recoded the example as advised.<br class=""><br class=""><blockquote type="cite" class="">1) Space.<br class=""></blockquote><br class="">Every Term based type (class) carries its own copy of methods, some may<br class="">be [overriden] overwritten, e.g. Write.<br class=""><br class="">NEW(m); m^ = methods^; m.Write := Write<br class=""><br class=""><blockquote type="cite" class="">2) Consistency.<br class=""></blockquote><br class="">To keep the same methods for all Term based types, we can leave out<br class="">NEW(m), and just assign a pointer.<br class=""><br class="">(*NEW(m)*); m = methods;<br class=""><br class="">QUESTION, can we somehow call base method from the overwritten one?<br class=""><br class="">(* ------- OOP EXAMPLE -------- *)<br class=""><br class="">MODULE Term; (* TK 15.8.2018 revised OOP example *)<br class="">  IMPORT Texts, Oberon;<br class=""><br class="">  TYPE<br class="">    Term* = POINTER TO TDesc;<br class="">    Methods* = POINTER TO MDesc;<br class=""><br class="">    (* Base method suite *)<br class="">    MDesc* = RECORD<br class="">      Write*: PROCEDURE(t: Term; ch: CHAR);<br class="">      Refresh*: PROCEDURE(t: Term)<br class="">      (* other methods come here *)<br class="">    END ;<br class=""><br class="">    (* Base data suite *)<br class="">    TDesc* = RECORD<br class="">      do*: Methods;<br class="">      (* generic terminal data comes here *)<br class="">    END ;<br class=""><br class="">  VAR W: Texts.Writer; methods: Methods;<br class=""><br class="">  (* ------ Initialisation for clients ------ *)<br class=""><br class="">  PROCEDURE Init*(t: Term);<br class="">  BEGIN t.do := methods<br class="">  END Init;<br class=""><br class="">  PROCEDURE InitMethods*(VAR m: Methods);<br class="">  BEGIN m^ := methods^<br class="">  END InitMethods;<br class=""><br class="">  (* ------ Term base methods ----- *)<br class=""><br class="">  PROCEDURE Write(t: Term; ch: CHAR);<br class="">  BEGIN Texts.Write(W, ch)<br class="">  END Write;<br class=""><br class="">  PROCEDURE Refresh(t: Term);<br class="">  BEGIN Texts.Append(Oberon.Log, W.buf)<br class="">  END Refresh;<br class=""><br class="">BEGIN Texts.OpenWriter(W); NEW(methods); methods.Write := Write;<br class="">  methods.Refresh := Refresh END Term.<br class=""><br class=""><br class="">MODULE CapTerm;<br class="">  IMPORT Texts, Oberon, Term;<br class=""><br class="">  TYPE<br class="">    CapTerm* = POINTER TO CTDesc;<br class="">    CTDesc* = RECORD (Term.TDesc)<br class="">      (* specific cap terminal data comes here *)<br class="">      col: INTEGER <br class="">    END ;<br class=""><br class="">  VAR W: Texts.Writer; m: Term.Methods;<br class=""><br class="">  PROCEDURE Init*(t: CapTerm; color: INTEGER (* other data for the<br class="">  CapTerm if any *) ); BEGIN t.do := m; t.col := color<br class="">  END Init;<br class=""><br class="">  PROCEDURE CAP*(ch: CHAR): CHAR;<br class="">    VAR up: CHAR;<br class="">  BEGIN<br class="">    IF (ch >= "a") OR (ch <= "z") THEN<br class="">      up := CHR(ORD(ch) + ORD("A") - ORD("a"))<br class="">    ELSE up := ch END<br class="">  RETURN up END CAP;<br class=""><br class="">  (* --------- Methods to override from Term base ------- *)<br class=""><br class="">  PROCEDURE Write(t: Term.Term; ch: CHAR);<br class="">  (* Write method specific for CapTerm *)<br class="">  BEGIN<br class="">    ch := CAP(ch); Texts.Write(W, ch); Texts.Append(Oberon.Log, W.buf)<br class="">    (* could we call base Write instead of Texts.Write/Append ? *)<br class="">  END Write;<br class=""><br class="">  (* Refresh() method not to be overriden *)<br class=""><br class="">BEGIN Texts.OpenWriter(W); NEW(m); Term.InitMethods(m); m.Write := Write<br class="">END CapTerm.<br class=""><br class=""><br class="">MODULE TestTerm;<br class="">  IMPORT Texts, Oberon, Term, CapTerm;<br class=""><br class="">  VAR<br class="">    W: Texts.Writer; t: Term.Term; c: CapTerm.CapTerm;<br class=""><br class="">  PROCEDURE Run*;<br class="">    VAR S: Texts.Scanner;<br class="">  BEGIN<br class="">    Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);<br class="">  Texts.Scan(S); WHILE S.class = Texts.Name DO<br class="">      t.do.Write(t, S.s[0]); t.do.Refresh(t); <br class="">      c.do.Write(c, S.s[0]); c.do.Refresh(c); (* calls Term.Refresh() *)<br class="">      Texts.Scan(S)<br class="">    END ;<br class="">    Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)<br class="">  END Run;<br class=""><br class="">BEGIN Texts.OpenWriter(W);<br class="">  NEW(t); Term.Init(t);<br class="">  NEW(c); CapTerm.Init(c, 20)<br class="">END TestTerm.<br class=""><br class="">TestTerm.Run  a b c ~<br class=""><br class=""><br class="">-- <br class="">Tomas Kral <<a href="mailto:thomas.kral@email.cz" class="">thomas.kral@email.cz</a>><br class="">--<br class=""><a href="mailto:Oberon@lists.inf.ethz.ch" class="">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems<br class=""><a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" class="">https://lists.inf.ethz.ch/mailman/listinfo/oberon</a><br class=""></div></div></blockquote></div><br class=""></div></div></div></body></html>