[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: ADT Lib (4)



Hallo!

> The term is widely used.  With Sather the language provides a "real"
> iterator construct (in comparison to the "fake" iterator we are using
> here).  When comparing our "iterator" with the iterator concept of
> Sather, the term `rider' is very appropriate.

I'm speaking of widly known languages like C++ :-) However name are
not the most important thing so lets take Rider.

> This all is true.  Peter mentioned that very same thing in one of his
> first mails.  When I wrote "class of iterator", I meant an iterator
> class with different semantics.  A tree iterator of type "in order" is
> just an implementation of the general iterator class, not a new class
> of iterators with new semantics.  I wrote down the specs for one class
> of iterators in the attached Container module (attached to this mail).

Yes. All that in/pre/post order iterators will have the same interface
because they inherit from the same baseclass. It is up to the
implementor if he decided to define a new class for every order or if
he uses the same class configured by a flag but they wil have the same
interface, the same methods.

> Do we need a additional general iterator concept with different
> semantics?  E.g. one Rider2, with the additional property that it can
> move backwards?

I already proposed a possible hierachie for read only iterators.

> For every implementation of a container there are uncountable ways to
> enumerate its elements: forward, backward, sideways, random, etc.  If
> we distinguish between classes of enumerations, we better chose a
> criterion whose semantics are firmly established in the library.

I think one has to abstract a littele bit more. The basic iterator
(sequential) only has a next method, how this method is defined in time and
space is completely irrelevant. The next class has bidirectional movement, an
third one random-acces by indexing movement. Note for example that an
iteraotr to goes from start to end and one that goes from end to start
share the same interface, you will *not* implement a Forward iterator
with method "forward" and a backward iterator with method "backward".
You iteraotr should *not* show how the ADT stores its data. A general iterator
implemented for a tree should not show the specific details.

> True.  But the cost for a simple iteration using this mechanism may be
> high.  Take e.g. the most simple binary tree with links to two
> descendants, but no link towards the root.  For such a tree the
> iterator/rider has to keep a stack of visited nodes.  In the worst
> case this stack may grow to a length of O(n), where n is the number of
> nodes in the tree.

True. However we should try to implement at least a sequential iterator
for each ADT.

> I have the same reservations about rider base insertion/removal.
> Therefore Container.Rider (see below) only provides the means to
> replace the value of an existing element with a new value.  I don't
> see a way to use a rider to do (e.g.) insertion in the _general_
> case -- in the special case of a double linked list it is not a
> problem, of course.

Yes. Insertion is a problem because of the very different semantics.
However writers are necessary for a number of generic algorithms like
copying, moving and sorting. You will have problems to define a general
way to move data from a ADT instance to an instance of another ADT type
(for example copying a list to an array for better sorting or storring
data in two ADTs (e.g. tree and hash) to get the best of both worlds).
So we should definitely find a solution.

> BH> Even if Write has replacement semantics, how would that affect
[...]

> Yes.  :-)

Perhaps the baseclass of the Write should not define that much position
information as a reader does? F.e. a writer to a sorted list or tree
will not have any usefull position information.

> This is the first argument for an distinction between "reader" and
> "writer" riders I have seen on this mailing list.  I agree, that
> anything "sorted" (but also other ADTs) cannot even have a replacing
> rider.  If we do not split riders into two classes, we could have the
> `WriteX' procedures return an error code like "operation not
> permitted".

If a method returns a "not supported" error your class hierachie is
wrong. You then have to inherit from a baseclass without this feature
and implement it in a specialized class.

> Could you write a module outline for this data type, once you are back
> from your holiday?  With `List.Mod' and `Container.Mod' we have enough
> of a framework to make this worthwhile.

Yes, at the end of the next week. Remind me of that, please.

> specific implementations.  The basic `Rider' does not impose any
> ordering constraints.  It only requires that a specific Container's
> implementation enumerates all items.

True.

> IR> 4. Riders should have a Reset function that moves them back to the
> IR> beginning

> I have put it into Container.Mod.  By now it is halfway on its way out
> again.  Reason: The LISP-style list implementation "list1",  described
> by Tim.  With these kinds of lists, all list elements are lists of
> their own, and a list element can be part of more that one list.
> Under these circumstances, it is impossible to do a proper reset.
> Because we do not gain much with this method, I am in favor of
> removing it again.

This is no problem, if reseting is not a method of the rider itself but
of the container. A container then has two methods: Create a new
iterator and reuse and reinitialize an old one.

> I suggest we wait with a decision until Tim gives us a module for
> LISPish lists.

You can go on, this this aproach will wok with the LISP list, too.

> Please note: this iterator business is one part of the library I
> consider "low-priority" for myself.  This means, someone else has to
> take over active coordination for that part, or it will never grow
> beyond the minimal stuff in Container.Mod.  Suggestion: Create an
> abstract class `List' (an ancestor to the double-linked list I posted
> earlier), and with it more specialized iterators (i.e., with more
> properties than Container.Rider).

I see the strong need for iterators (as mentioned several times now!)
and are willing to do some for stuff for it. Shit, that I must go in
holiday at this time ;-)

> MODULE Container;
> (* Characteristics of the abstract(!) class Container:

I'm yet not sure, if a baseclass for containers is a good thing. I
already gave some arguments against it for my expiriences with my own
library. We should build up a list of possible ADTs (including the more
esoteric ones like directed and undirected graphs) to see if a basecass
for all containers makes sense. There is a rather complete list of ADTs
as part of my library sources on the VO homepage.

>   - objects can be added to and removed from the container; an object 
>     can be added to a container multiple times, each addition will
>     create a new, distinct, container element

Adding one object multiple times is not permitted on all ADTs. F.e.
hashtable are normaly not designed for multiple versions of the same
entry.

> TYPE
>   Rider = RECORD
>     res-: INTEGER;  (* result of last operation *)
>     type-: INTEGER; (* type of object "beneath" rider, see `typeXXX' below *)
>   END;
> 
> CONST
>   typeUndef* = 0;
>   typeBool* = 1; typeChar* = 2; typeShortInt* = 3; 
>   (* ... symbolic names for all basic types, and (with
>      meta-programming capabilits) also for type constructors *)
>   typeObject* = 99;

Reading and writing of build in datatypes is a fine feature but how do
you want to implement storing of basic types in your ADTs. Think of own
pseudo implementation of a double linked list! Is this realy a feature
we can support?

> PROCEDURE Init* (c: Container);
>   END Init;

> PROCEDURE New*(): Container;
>   END New;

here starts the problem. You proposed in an earlier message that each
ADTs should exacly have one constructor. What about constructoras with
parameters. E.g. a array implementation of a stack? Don't define
constructros in the container baseclass.

> (* Riders
>    ======================================================================== *)
> 
> PROCEDURE (c: Container) NewRider*(): Rider;
> (* Creates new rider, positioned at the "beginning" of the container. *)
>   END NewRider;
> 

What about ADTs which do not support riders? I don't thing that the
implementation of a specific rider should be part of the baseclass.

> PROCEDURE (r: Rider) Reset*;
> (* Resets the rider to the element at which a newly created riders
>    start.  *)
>   END Reset;

Put this into the container.

I will write some more comments later (I have to go to my 70ties
disco to meed some long haired man and woman ;-)). I wished I work ad
work to offer some C++ iterator examples. I think this would give us
some creative imput.

-- 
Gru...
       Tim.