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

Re: Container Library?



I'm quoting from Peter's and Mark's mails:
PF> [code for ListElement type removed]
PF>    Aside from the naming issue involved, this of course makes it
PF> necessary that every application that wants to use any part of the
PF> container library must then derive its classes from StdTypes.Object. 

Correct.  This isn't necessarily bad (see below).

PF> Although this is better than the other approach, it
PF> does not really cure the problem, but on the other hand, a proper
PF> cure would only be possible by extending the language (ANYREC and
PF> ANYPTR-like types) which is not in the spirit of the OOC project
PF> AFAIK.

OOC sticks to the language report here.  As long as there is no need
for this extension, I would prefer to keep it that way.

PF>    Additionally it is not necessarily true that the class StdTypes.Object
PF> should be completely empty. For example, if one wants to be able to provide
PF> run-time type-checked containers, there has to be a method like
PF> 
PF>    PROCEDURE (self: Object) IsSupertypeOf (other: Object): BOOLEAN;
PF>    BEGIN
PF>      RETURN other IS Object;
PF>    END IsSupertypeOf;

Could you give an example for this type-proc in action?

Another suggestion regarding `StdTypes.Object':
Add type-bound procedures `Load' and `Store' to `Object'.  As
described in Moessenboeck's book "OOP in O2", these procedures can
then be used to externalize/internalize data structures.  Of course,
this assumes that Load/Store are properly redefined for every
extension of `Object' created by the user.  [I believe that
Moessenboeck also wrote a paper describing this approch; can someone
provide a link to a online version of this paper?]

I'm not sure if integrating Load/Store at this basic level would be
worthwhile, though.

PF> >This operator could be implemented as a type-bound procedure.
PF> >Advantage:
PF> >o the record, to which the type-bound proc is bound, could be used to
PF> >  pass parameters to it, and the result back to the caller
PF> >o the operator procedure is visible to module `Types'; a very useful
PF> >  thing if you are working with persistent objects
PF> 
PF>    I really don't understand both of these comments; please clarify. I
PF> personally would replace this "operator" thing with Iterator classes.

I think we are talking about the same thing in general.  Here is some
pseudo code to make things more precise:

TYPE
  Operator* = POINTER TO OperatorDesc;
  OperatorDesc* = RECORD
    PROCEDURE (op: Operator) Apply (obj: StdTypes.Object);
  END;

PROCEDURE (list : LinkedList) Iterate* (operator : Operator);
  VAR
    current : Element;
  BEGIN
    current := list.head.next;
    WHILE current # list.head DO
      operator. Apply (current);
      current := current.next;
    END
  END Iterate;


MKG> [list of arguments against extending `LinkedList.Element' deleted...]
MKG> We are actually thinking along the same lines. I agree with all these
MKG> points. However, the design I proposed does not require that the
MKG> user's type be an extension of any element types. (In fact, it cannot
MKG> be in general, as I pointed out.) The following type definitions are
MKG> similar to the original example I posted and shows how one would use
MKG> the linked list by defining an "adapter type" which is an extension of
MKG> an element type. (In the original example I used a specific type,
MKG> INTEGER, which may have confused the issue.)
MKG> 
MKG> [BTW, I am using "adapter" from the adapter pattern to mean an entity
MKG> which allows one thing to be used in a context that it was not
MKG> designed for.]
MKG> 
MKG> 	DataElement = POINTER TO DataElemDesc;
MKG> 	DataElemDesc = RECORD (LinkedList.ElementDesc)
MKG> 		datum : Data;
MKG> 	END;

Is this type defined by the user?

MKG> Note that Data can be any type defined in any module. The confusion
MKG> seems to have been that Data would have to be an extension of an
MKG> element type. It does not. It should not in a good design. Instead,
MKG> the adapter which holds datum needs to be an extension of a container
MKG> element. Thus Data is completely arbitrary and can appear in any
MKG> number of containers because it is an adapter (by virtue of being an
MKG> extension of the element type of some container) that is actually "in
MKG> the container". Hopefully it is clear that the design I proposed will
MKG> meet every one of the criteria Michael pointed out.

I'm not sure just how far we agree.  Here is the modified type
declaration again.  Notice that I derived `LinkedList' from `Object'.

  TYPE
    (* type for elements of a linked list *)
    Element* = POINTER TO ElementDesc;
    ElementDesc = RECORD
      next, prev : Element;
      car : StdTypes.Object;
    END;
    (* The linked list type *)
    LinkedList* = POINTER TO ListDesc;
    ListDesc = RECORD
      (StdTypes.Object)
      head : Element;
    END;

With this kind of definition one can

a) create a list of linked lists on user-level, without the need for
   additional data type definitions

b) provide (e.g.) a `Copy' procedure in module `LinkedList' that
   creates a duplicate of a given list; the specs of `Copy': the new
   list has the same contents as the first list, in the same order,
   but any destructive operation (like element removal) on the first
   list will not be visible in the copy

I don't see how this can be achieved by a user-defined `DataElement'
type.  But then, this may be a kind of subjective blindness :-)

MKG> Finally, I quoted this out of context, but it is one of my "favorite
MKG> irritants". (I am not picking on Michael at all. The attitude is
MKG> extremely prevalent.)

Go ahead ;-)

MKG> Memory may be getting cheaper and CPU speeds faster, but it has been
MKG> shown that applications are getting "fat and lethargic" at a faster
MKG> rate than costs have been going down and speeds have been going up.
MKG> This is not necessarily bad if we are getting sufficient additional
MKG> utility. However, often we are not. I think it is the attitude itself
MKG> that has spawned the over abundance of bloatware.

True.

MKG> Wirth's adoption of Einstein's statement (probably misquoted by me)
MKG> "Keep it as simple as possible, but no simpler" is one of the reasons
MKG> I was originally attracted to Oberon. I would like to keep that as a
MKG> guiding principle. If design A has arguably better utility than design
MKG> B but uses slightly more resources, so be it. I can live with that.
MKG> But personally I will never justify a design purely because "memory is
MKG> cheap".

Also true.  I want to stress the point that I am primarily discussing
the benefits of different designs here.  My main concern is, that we
agree on a design that maximises usefulness.  I only pointed out the
higher memory and computation costs, because a) the costs were
mentioned in the original post, and b) they are of importance,
although the minimal difference here makes them a secondary issue.

-- mva