From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,2ff5c149712ec0eb,start X-Google-Attributes: gid103376,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news4.google.com!proxad.net!213.200.89.82.MISMATCH!tiscali!newsfeed1.ip.tiscali.net!news.tiscali.de!news.belwue.de!th!lucks From: Stefan Lucks Newsgroups: comp.lang.ada Subject: Ada Interfaces and the Liskov Substitution Principle Date: Wed, 23 May 2007 21:47:32 +0200 Organization: InterNetNews at News.BelWue.DE (Stuttgart, Germany) Message-ID: NNTP-Posting-Host: th.informatik.uni-mannheim.de Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed X-Trace: news.BelWue.DE 1179949656 15533 134.155.91.85 (23 May 2007 19:47:36 GMT) X-Complaints-To: news@news.belwue.de NNTP-Posting-Date: Wed, 23 May 2007 19:47:36 +0000 (UTC) Xref: g2news1.google.com comp.lang.ada:15891 Date: 2007-05-23T21:47:32+02:00 List-Id: Hi all, to me, it seems as if Ada 2005 is bluntly violating the Liskov Substitution Prinicple. E.g., define ---Start--- package Parents is type Parent is Interface; -- primitive operation procedure Do_Something(Self: in out Parent) is abstract; -- class-wide operations procedure Do_Nothing(From: in Parent'Class; To: out Parent'Class); procedure Convert(From: in Parent'Class; To: out Parent'Class); end Parents; ----End---- with the primitve operations defined in ---Start--- package body Parents is procedure Do_Nothing(From: in Parent'Class; To: out Parent'Class) is begin null; -- warning: "To" is never assigned a value. end Do_Nothing; procedure Convert(From: in Parent'Class; To: out Parent'Class) is begin To := From; end Convert; end Parents; ----End---- Now, Do_Nothing is harmless (except for generating a compiler warning). But Convert uses the assignment ":=", which seems OK, as the interface Parents.Parent is not limited. Now there are two children to inherit from Parents. The first one is Child.Object: ---Start--- with Parents; package Child is type Object is new Parents.Parent with private; procedure Do_Something (Self: in out Object); private ... doesn't matter ... end Child; ----End---- Child.Object gets everything there are no limits to using Parents.Parent'Class. But look at Stepchild.Object: ---Start--- with Parents, Ada.Finalization; package Stepchild is type Object is new Ada.Finalization.Limited_Controlled and Parents.Parent with private; procedure Do_Something (Self: in out Object); private ... doesn't really matter ... end Stepchild; ----End---- Stepchild.Object is really a poor cousin, prohibited from using Parent.Convert: ---Start--- with Ada.Text_IO, Parents, Child, Stepchild; procedure Family is procedure All_Well(X: in out Parents.Parent'Class) is begin X.Do_Something; end All_Well; Procedure Not_So_Well(X, Y: in out Parents.Parent'Class) is begin Parents.Convert (X,Y); end Not_So_Well; Alice, Charles: Child.Object; Bob, Eve: Stepchild.Object; begin All_Well(Alice); All_Well(Bob); All_Well(Charles); All_Well(Eve); Ada.Text_IO.Put("first OK "); Not_So_Well(Alice, Charles); Ada.Text_IO.Put("second OK "); Not_So_Well(Bob, Eve); -- this raises Eception Constraint_Error -- with "... tag check failed". Ada.Text_IO.Put("will we ever get here?"); -- no, nay, never!!! end Family; ----End---- My understanding of the Liskov substitution principle, see http://en.wikipedia.org/wiki/Liskov_substitution_principle is that as Partens.Parent implicitely (by not being limited) provides certain primitve operations, such as ":=" and "=", and Stepchild.Object takes away these primitive operations, Stepchild.Object should not be in Parents.Parent'Class, i.e., Not_So_Well(Bob, Eve); and even All_Well(Bob); and All_Well(Eve); ought to be a syntax error. I think, it is a flaw that when calling Not_So_Well(X,Y) you need to know (a) of what type X and Y actually are (instead of just knowing that these are of type Parents.Parent'Class) and (b) and the implementation details of Not_So_Well (here the fact that it uses the assignment over Parents.Parent'Class). What do you guys think about this? -- Stefan Lucks (moved to Bauhaus-University Weimar, Germany) ------ I love the taste of Cryptanalysis in the morning! ------