Oz and Mozart Users Mailing List

Re: "class" constraints


From: Denys Duchier (duchier@ps.uni-sb.de)
Date: Fri Jun 20 2003 - 00:38:58 CEST


t.anders@qub.ac.uk (Torsten Anders) writes:

> On the other hand, I propose a class hierarchy. In your proposal I only
> see groups/sets of, e.g., lexical entries, but no hierarchy. Besides, I
> do not only propose classes, I also propose methods for these classes.

a hierarchy can be compiled into a description... in fact, you
suggested the technique yourself using sets. The real question is
whether a description is sufficient until a corresponding solution is
found for the class description of an instance; or do you really need
to invoke methods _before_ the class is fully known _and_ expect them
to execute as early as possible. It is obvious (to me :-) that
requiring the latter is not going to be particularly efficient... to
put it plainly, it is going to suck. Also, your outlined solution is
definitely at odds with OO à la Oz. If you abandon OO (in the sense
of that fragment of Oz with linguistic support for OO idioms), then
you might as well embrace descriptions.

In any case, I had a second look at your desiderata and I thought of a
way to do...er... something like what I think you want, using OO à la
Oz. It is not a very good solution. Actually, it is more of a
"stupid pet trick" :-) I am sure there is a much better way to encode
the constraints about class compatibilities and method table
compositions, but this is not exactly my research project :-) I would
definitely not do things this way.

%% Let's first define 3 classes A, B and C.

declare
class A %% encode as 1
   meth one {Show one(a)} end
   meth two {Show two(a)} end
   meth onetwo {self one} {self two} end
end
class B %% encode as 2
   meth two {Show two(b)} end
   meth three {Show three(b)} end
end
class C from A %% encode as 3, inheriting from 1
   meth two {Show two(c)} end
end

declare
EncodeClassFull = o(a:{FS.value.make 1}
                    b:{FS.value.make 2}
                    c:{FS.value.make [1 3]})

declare
[Select] = {Link ['x-ozlib://duchier/cp/Select.ozf']}

%% Here is a tricky Vague class that at first doesn't know what it's
%% base classes are. It uses an otherwise method to perform
%% constraint-based dispatching, eeek! It make the implicit
%% assumption that, if you invoke method foo on an instance of Vague,
%% then you expect this instance to inherit from a base class that
%% implements foo.
%%
%% Vague doesn't actually have any base classes, but its @table
%% attribute maps a method label to the class that provides its
%% implementation. This mapping is computed on demand by the
%% otherwise method.

declare
class Vague
   attr classes baseClasses table
   meth init
      table <- {NewDictionary}
      baseClasses <- {FS.var.upperBound 1#3}
      classes <- {Select.union EncodeClassFull @baseClasses}
      %%
      %% add some logic to exclude ambiguous inheritance combination
      %% A and B both define method two, but have no common specialization
      %% that resolves which of the implementations to choose.
      %%
      {FS.reified.include 1 @classes}+
      {FS.reified.include 2 @classes} <: 2
   end
   meth isA(CL)
      {FS.include
       case CL
       of !A then 1
       [] !B then 2
       [] !C then 3 end
       @classes}
   end
   meth isNotA(CL)
      {FS.exclude
       case CL
       of !A then 1
       [] !B then 2
       [] !C then 3 end
       @classes}
   end
   meth otherwise(M)
      L = {Label M}
      CL
   in
      if {HasFeature @table L} then
         CL = @table.L
      else
         @table.L := CL
         case L
         of one then
            {FS.include 1 @classes}
            CL=A
         [] two then
            cond {FS.include 3 @classes} then CL=C else
               cond {FS.include 2 @classes} then CL=B else
                  {FS.include 1 @classes} CL=A
               end
            end
         [] three then
            {FS.include 2 @classes}
            CL=B
         [] onetwo then
            {FS.include 1 @classes}
            CL=A
         end
      end
      CL,M
   end
end

Now try:

declare O={New Vague init}
{O onetwo}

This prints just one(a) because then method two doesn't know whether
it should the implementation of class A or C (class B has been ruled
out by the constraint posted by the init method, because invoking
method onetwo implies that the instance must at least be a A, and
therefore is incompatible with a B).

{O isNotA(C)}

now we have ruled out that the instance can be a C, therefore it is
just a A. The suspended two method unblocks and prints out two(a).

If instead we had executed:

{O isA(C)}

Then the suspended method would also become unblock, execute the
implementation provided by the C class, and print out two(c).

I haven't thought about supporting attributes, and features are
definitely out of the question. You could add an attribute that held
a dictionary to achieve something similar to inherited attributes.

There should be an automated way to derive the logic of the otherwise
method using descriptions of the classes as input (i.e. what methods
they implement and from which other classes they inherit). With a
little work, I am sure you can come up with it :-)

Cheers,

-- 
Dr. Denys Duchier
Équipe Calligramme
LORIA, Nancy, FRANCE
-
Please send submissions to users@mozart-oz.org
and administriva mail to users-request@mozart-oz.org.
The Mozart Oz web site is at http://www.mozart-oz.org/.
Please send bug reports to bugs@mozart-oz.org.



This archive was generated by hypermail 2b29.