[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
ADT Lib (6)
IR> Writers have no other state than position. After writing an
IR> object to a Bag, for instance, the only thing that's changed
IR> state is the Bag. An object without a state probably doesn't
IR> need to exist.
I agree with you. The term "Writer" has been used in a very vague
way
on this mailing list. I tried to fill it with some meaning by
incorporating it into the rider, which is both a reader and a writer,
and using replacement sematics for writers. We all know that Tim
does
not agree with this definition, but I haven't seen any other proposal
(disregarding Tim's hazy prose). Until some other practicable
proposal is made, the current AcRider module stands as it is.
IR> The functionality for modifying containers would be done as
IR> methods of each container. Add() for Set, Push() for Stack,
IR> and AddToFront(), AddToEnd(), and others for List, etc.
IR> This approach also makes simple containers much easier to
IR> use -- no intermediate writer object needed.
This is the reason why I removed `Add' and `Remove' from the
interface
of Container again. There are simply too many variants, all with
wildly different semantics.
IR> Add/Remove methods for Container:
IR> ----------------------------------------------------
IR> I'm not sure why these can't be included. Even set ADTs have Add
and
IR> Remove operations. Are there ADT's that don't?
IR>
IR> The semantics would be:
IR>
IR> PROCEDURE (c: Container) Add* (obj: AcObject.Object);
IR> (* Ensures obj becomes a member of the container.
IR> The size of the container may or may not change.
IR> eg. for Sets this method will do nothing if obj is already in c.
IR> ADTs that allow multiple copies of same object in the container
IR> would always add obj to the container.
IR> *)
IR>
IR> PROCEDURE (c: Container) Remove* (obj: AcObject.Object);
IR> (* Ensures that the membership count of obj in c is decremented
IR> by one. If obj was in c once, then it is removed. If obj was in
IR> c multiple times, then one copy of obj is removed (with no
guaruntee
IR> of which copy gets removed). If obj is not in c then nothing is
done.
IR> *)
With such semantics, I can add these methods to container again. The
question is: Is it worthwhile to have methods with such vague
semantics? Does anyone second this?
Another question: With the above specification, is it guaranteed that
the statement sequence
c.Add(foo); c. Remove(foo);
is a "no operation", i.e., will not change the state of `c' or the
system?
PF> Okay, what about Hashtables, AVL-Trees or other data
structures that
PF> actually require the "elements" stored within to support a
certain set of
PF> operations like Hash(): INTEGER or LessThan (other: Ordered):
BOOLEAN? I
PF> have repeatedly stated my opinion that a generic Container-like
base class
PF> can only have "undisputable" methods like Empty(): BOOLEAN or
Elements():
PF> INTEGER. Nothing else.
Instead of "obj.Hash()" or "o1.LessThan(o2)" I prefer proper
functions, like "Hash(obj)" or "LessThan(o1, o2)". The functions can
be implemented as a procedure variable, or as a type-bound procedure
of some base class. See also Tim's posting about a "Compare" class
some time back: http://www.uni-kl.de/OOC/ooc-list/msg00528.html
The reason for this is simple: An object has no "natural" total
ordering. If I have a "RECORD a,b: INTEGER END", then I can sort by
field `a' or `b' (or both), in ascending or descending order (but not
both ;-). Therefore a single _method_ Object.Compare is not flexible
enough. An external comparison _function_ gives this kind of
flexibility, though.
In other words: To insert an object in a hash table, one needs to
have
a hash function that can be applied to the object. The object does
not need to have a property "hashable".
IR> 2. Regarding Mike's pointers to Booch components:
IR>
IR> They use generics (ie. templates in C++) that Oberon-2 lacks.
IR> How to get around this?
Don't forget multi inheritance.
IR> 3. May I suggest that the res variable in rider be "sticky" --
that is,
IR> once it sets to a non-done value, it holds that value and the
IR> rider refuses to do any more work until r.ClearError is called.
IR> This greatly simplifies programming since res doesn't need to
IR> be checked after every operation.
I will incorporate this change into AcRider.Mod. This brings
container riders even closer to channel riders, which is a Good
Thing(tm) in my opinion.
TT> > This would be a severe case of bad design. `Reset' is a rider
method,
TT> > not a method of the container. Therefore it conflicts with
this rule:
TT>
TT> No, reset is not a rider method because reset is not a *feature*
of the
TT> rider baseclass. If the rider base class (sequential iterator)
does not
TT> now about backstepping or random indexing it also does not know
about
TT> indexing with is similar to moving backwards several times or
random
TT> indexing with index 0. Only the container knows how to handle its
own
TT> iterators so it does belong to the container.
We will agree, that rider.Reset() is equivalent to r.SetPos(0)
(assuming an indexed rider for the moment). And you will also agree
that `SetPos' is undisputable a rider operation. It has to be a
rider
operation, because only riders have any sense of `position'; the
container does not now anything about positions.
We have two identic operations. How can they differ in their
receiver
type? You should rethink your argumentation, and maybe take a look
at
the "Common Mistakes" chapter of "OOC in O2".
Additionally, a function like c.Reset(r) is unsafe in the sense, that
`r' must have been created before by the very same container through
`c.NewRider'. Therefore I am taking the "clean" way out and drop it
altogether.
-- mva