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.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,555956c1cdd22308 X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: Help - Constructors - ASAP. Date: 1998/08/01 Message-ID: #1/1 X-Deja-AN: 376892235 Sender: matt@mheaney.ni.net References: <6p75qi$rcj@news.latnet.lv> <6pi4jq$j73$1@nnrp1.dejanews.com> <6pqdr2$hn2$1@nnrp1.dejanews.com> <35C1043E.9FFB23D0@elca-matrix.ch> NNTP-Posting-Date: Fri, 31 Jul 1998 21:59:32 PDT Newsgroups: comp.lang.ada Date: 1998-08-01T00:00:00+00:00 List-Id: eachus@spectre.mitre.org (Robert I. Eachus) writes: > Note that there ARE cases where you do want to have a dispatching > constructor. In those cases you really do want to have a constructor > that is derived, and you (or someone else) will have to do the > explicit overriding. Note that there are two kinds of dispatching: dispatch on the return type, and dispatch on a parameter. Bob is talking about the first case, dispatching on the return type. A common example of this sort of thing is a set type with a constructor that returns the empty set: generic type Set_Item is private; with function "=" (L, R : Set_Item) return Boolean is <>; package Sets is type Root_Set is abstract tagged null record; function Empty_Set return Root_Set'Class; ... end Sets; I might use the constructor like this: procedure Op (Set : in Root_Set'Class) is Local : Set'Class := Set; begin Local := Empty_Set; end Op; The function Empty_Set is a constructor that dispatches on the tag of object Local. Here is a case where you really want to have a constructor that returns the specific type. Each non-abstract type that derives from Root_Set will have to provide an Empty_Set constructor. That's an example of the first kind of constructor. The other kind of constructor returns a class-wide object, and dispatches on a parameter. An example of this kind of constructor is a "factory method." Consider our set type again. Suppose we have an operation that takes a class-wide parameter, and we want to iterate over that set. What we can do is have the set provide a factory method to construct an iterator that can be used to iterate over that that kind of set. Let's add an iterator type to our example: generic ... package Sets is type Root_Set is abstract tagged null record; type Set_Iterator is abstract tagged null record; function New_Iterator (Set : access Root_Set) return Set_Iterator'Class; function Is_Done (Iterator : Set_Iterator) return Boolean is abstract; function Get_Item (Iterator : Set_Iterator) return Set_Item is abstract; procedure Advance (Iterator : in out Set_Iterator) is abstract; ... end Sets; Note that the constructor, New_Iterator, returns a class-wide type. Let's use our constructor to implement a passive iterator that works for any type in the set class. Here's the spec: generic with procedure Process (Item : in Set_Item; Done : in out Boolean); procedure For_Every_Item (Set : access Root_Set'Class); Note how the Set parameter is class-wide. Here's the body: procedure For_Every_Item (Set : access Root_Set'Class) is Iterator : Set_Iterator'Class := New_Iterator (Set); Done : Boolean := False; begin while not Is_Done (Iterator) loop Process (Get_Item (Iterator), Done); exit when Done; Advance (Iterator); end loop; end For_Every_Item; The New_Iterator constructor dispatches on the Set parameter. Each of the iterator operations (like Get_Item) then dispatches on the tag of the Iterator object. There you have it. Two examples of constructors, one returning a specific type, the other returning a class-wide type. Both techniques are appropriate for different kinds of problems. Happy constructing! Matt