Subject: $object_utils:isa

From: Kent Pitman <[email-masked]>
Date: Sat, 29 May 1993 08:35:35 -0700

I ran into some troubles with isa that I wanted to log.  Please do NOT
waste time sending code examples of how to work around this.  I know
how to do that trivially.  My only purpose in reporting this is to log
the conceptual problem to help in future design.

It seems to me that $object_utils:isa(#-1,#-1) should return 1, not 0.
I have an object that has a list of places it is permitted to move,
and I put #-1 in the list.  I then wrote an is_unlocked_for verb that
contained the following, which returns 0 even though #-1 is in x:

 for x in (this.lock_keys)
   if ($object_utils:isa(args[1], x))
     return 1;
   endif
 endfor
 return 0;

To put my claim another way, I think the self-consistent definition of
isa for the moo world as currently portrayed should not be
  :isa(x,y) == valid(x) && (y==x || y in :ancestors(x))
but should instead be:
   :isa(x,y) == (x==y || ( valid(x) && y in :ancestors(x) ))
I think it's reasonable to validity check x before you try to walk it,
but I think everything (even nothing) isa whatever it is.

For what it's worth, I also think that it's a design error that isa
does the x==y check.  If it didn't, I wouldn't be sending the above
report, but I don't think the class of foo is necessarily of class
foo.  This is necessary in the weird case where you instantiate my
wristwatch, but it's not necessary in the case where I go to the
trouble to first make a Generic Wristwatch that both you and I
instantiate in order to wear.  It is enough for our two wristwatches
to be of type Generic Wristwatches; it is not necessary that a Generic
Wristwatch be of that type.  And, in fact, it screws up lots of my
programs that try to manipulate things of that type specially when
they get a generic that isn't all filled in with proper values and try
to frob it randomly.

I think the service that isa provides should be called is_or_isa, and
that really isa should just check parentage (and checking validity at
the same time then would be fine).  I don't think there should be a
separate verb is, since == works fine.  Then I would write:

 for x in (this.lock_keys)
   if (x == args[1] || $object_utils:isa(args[1], x))
     return 1;
   endif
 endfor
 return 0;

In fact, I -can- write this now, and it will work although it will do
some yucky and unwanted (though harmless) tests in the isa.  But even
though I can write it, the current definition of isa would make it
look like I didn't need to, so I might not think to unless I thought
about this fringe case.  The fact that I'm writing this bug report
suggests that people won't always do this.  I originally didn't have
#-1 in this.lock_keys; and I later added it because I thought the
program was data-driven and that I shouldn't have to look at the
program itself just because I was adding data.