From: Juanjo
Subject: Can SUBTYPEP fail?
Date: 
Message-ID: <ab4b7d4.0303221309.a4ac19b@posting.google.com>
Dear all,

I am in the process of writing a new SUBTYPEP and TYPEP routines for
ECL (A Common-Lisp implementation hosted at SourceForge,
http://ecls.sf.net). I am almost there, but in comparison to other
implementations, I have currently chosen to signal an error when the
type specifier is not known to be a type to the system.

My decision was inspired by

1) In the definition of SUBTYPEP, the two first arguments are said to
be "type specifiers" = "an expression which denotes a type", according
to the glossary.

2) A paragraph in the HyperSpec which states that, except for a few
pathological cases (SATISFIES, AND, FUNCTION, ...), SUBTYPEP has to
determine the type relationship precisely.

However

3) In CLISP and CMUCL, when the arguments passed is not a valid type
specifier, they both return (VALUES NIL NIL).

4) The ANSI specification says nothing about exceptional conditions in
SUBTYPEP.

I am wondering whether I should rewrite my implementation to follow
"common use" or whether I have misinterpreted the HyperSpec. What do
commercial implementations do? What would people find less annoying?
To myself, that SUBTYPEP may signal an error has been useful in the
last week, as it has pointed out a few errors in other parts of the
code.

Best regards

Juanjo

[Please forgive if I am not very responsive next week, but I will be
abroad for some days]

From: Paul F. Dietz
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <ZP-cnc8U6owFSOGjXTWcrg@dls.net>
Juanjo wrote:

> 3) In CLISP and CMUCL, when the arguments passed is not a valid type
> specifier, they both return (VALUES NIL NIL).
> 
> 4) The ANSI specification says nothing about exceptional conditions in
> SUBTYPEP.

In general, unless the spec promises that an error will be signaled,
you can't count on that (and even then only in safe code.)  In situations
where behavior is undefined, a conforming implementation can do whatever
it wishes (including return NIL NIL).

There doesn't appear to be any portable way to determine if an object
is a valid type specifier.

	Paul
From: Steven M. Haflich
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <3E7E87F3.6020906@alum.mit.edu>
Paul F. Dietz wrote:

> In general, unless the spec promises that an error will be signaled,
> you can't count on that (and even then only in safe code.)

Paul, this is completely bogus!  In circumstances where the ANS says
an error _will_ be signalled (with no provision for safety) a
conforming implementation _must_ signal an error.  There are many such
places where such errors are _not_ conditionalized on safety.  One,
recently referenced on another thread, is this requirement in the
dictionary page for defmethod:  "If function-name names an ordinary
function, a macro, or a special operator, an error is signaled."

> There doesn't appear to be any portable way to determine if an object
> is a valid type specifier.

True.  If it were portably true that an implementation would signal error
for an invalid type specifier, then one could detect same by wrapping an
error handler around a typep test. But if the ANS guaranteed that, then it
might as well have provided an explicit predicate.

The problem with providing an explicit predicate is handling the boundary
cases in type specifier syntax and semantics.  For example, is

   (array t (4 22/7))

a valid specifier?  Clearly not, but would the suggested predicate be
guaranteed to detect the bogosity?  And that about this?

   (deftype square-array (n) `(array * (,n ,n)))
   (type-specifier-p '(square-array 22/7))

It's trickier to specify than you might think, and if you don't think
carefuly about the specification, then conforming implementation may
be impossible...
From: Paul F. Dietz
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sZacnVMxweZYn-KjXTWcow@dls.net>
Steven M. Haflich wrote:
> Paul F. Dietz wrote:
> 
>> In general, unless the spec promises that an error will be signaled,
>> you can't count on that (and even then only in safe code.)
> 
> 
> Paul, this is completely bogus!  In circumstances where the ANS says
> an error _will_ be signalled (with no provision for safety) a
> conforming implementation _must_ signal an error.


Oops.  My mistake.  I meant 'should'.

	Paul
From: Nils Goesche
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <lyel4wzxju.fsf@cartan.de>
"Paul F. Dietz" <·····@dls.net> writes:

> Steven M. Haflich wrote:
> > Paul F. Dietz wrote:

> >> In general, unless the spec promises that an error will be
> >> signaled, you can't count on that (and even then only in safe
> >> code.)

> > Paul, this is completely bogus!  In circumstances where the ANS
> > says an error _will_ be signalled (with no provision for safety) a
> > conforming implementation _must_ signal an error.

> Oops.  My mistake.  I meant 'should'.

I wonder how many times a typical standards writer has had this
thought :-)

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0
From: Steven M. Haflich
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <3E811812.6090708@alum.mit.edu>
Paul F. Dietz wrote:

> Oops.  My mistake.  I meant 'should'.

OK, you're forgiven.

But to open another subthread, I do feel that subtypep is underspecified,
and experience supporting users for almost two decades has provided
evidence.

The problem is that there is a wide range of expectation on the speed
of subtypep and how much consistency checking it does.  This affect
expectations on whether and where subtypep might be used in execution-time
code.  Much use of sybtypep happens at compile or macro time, and perhaps
also at class finalization time, but occasional needs for subtypep arise
at execution time.  We all have certain expectations and understanding
about the speed of hash tables and gf dispatch, and trust market pressure
to keep main-line implementations all somewhere in the same ballpark.
But I'll bet there is significantly more variance in the behavior of
subtypep in certain  boundary cases between different implementations, and
in its execution speed.

One sample test case would be something like this:

(subtypep '(member 1 2 3 ... 99 100) '(member 1 2 3 ... 98.6 99 100))
From: Kent M Pitman
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sfw7kambxqp.fsf@shell01.TheWorld.com>
"Steven M. Haflich" <·················@alum.mit.edu> writes:

> Paul F. Dietz wrote:
> 
> > Oops.  My mistake.  I meant 'should'.
> 
> OK, you're forgiven.
> 
> But to open another subthread, I do feel that subtypep is underspecified,
> and experience supporting users for almost two decades has provided
> evidence.
> 
> The problem is that there is a wide range of expectation on the speed
> of subtypep and how much consistency checking it does.  This affect
> expectations on whether and where subtypep might be used in execution-time
> code.  Much use of sybtypep happens at compile or macro time, and perhaps
> also at class finalization time, but occasional needs for subtypep arise
> at execution time.  We all have certain expectations and understanding
> about the speed of hash tables and gf dispatch, and trust market pressure
> to keep main-line implementations all somewhere in the same ballpark.
> But I'll bet there is significantly more variance in the behavior of
> subtypep in certain  boundary cases between different implementations, and
> in its execution speed.
> 
> One sample test case would be something like this:
> 
> (subtypep '(member 1 2 3 ... 99 100) '(member 1 2 3 ... 98.6 99 100))

My favorite has always been the one from the CMU python group some years 
ago where they asked something like:

 (subtypep '(member 1.0s0 #.(+ 1.0 small-float-epsilon))
           '(real 1.0s0 #.(+ 1.0 small-float-epsilon)))

That is, are the reals really understood not to be a continuous set but
instead to be a finite enumeration of representable numbers that amounts
to the same kind of set that you could, if you had the patience, enumerate.
It's hard to set up a set that is small enough to test, but I believe
this is one of them...

           
From: Christophe Rhodes
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sq4r5qbivv.fsf@lambda.jcn.srcf.net>
Kent M Pitman <······@world.std.com> writes:

> "Steven M. Haflich" <·················@alum.mit.edu> writes:
>
>> One sample test case would be something like this:
>> 
>> (subtypep '(member 1 2 3 ... 99 100) '(member 1 2 3 ... 98.6 99 100))
>
> My favorite has always been the one from the CMU python group some years 
> ago where they asked something like:
>
>  (subtypep '(member 1.0s0 #.(+ 1.0 small-float-epsilon))
>            '(real 1.0s0 #.(+ 1.0 small-float-epsilon)))
>
> That is, are the reals really understood not to be a continuous set but
> instead to be a finite enumeration of representable numbers that amounts
> to the same kind of set that you could, if you had the patience, enumerate.
> It's hard to set up a set that is small enough to test, but I believe
> this is one of them...

(I think you meant to put those arguments the other way round -- as it
is, it would always return T, T or NIL, NIL if you did s/small/short
:-)

Just in case there are implementors in the field who aren't aware of
it, it might be worth mentioning Henry Baker's paper, available from
his archive, about the implementation of SUBTYPEP; while sbcl's
SUBTYPEP doesn't exactly follow his model, because of constraints
coming from requirements of the type checking engine, there are
nonetheless good ideas in there for representation and
canonicalization of types.

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Juanjo
Subject: Henry Baker's SUBTYPEP decision tree
Date: 
Message-ID: <ab4b7d4.0303310055.73d15104@posting.google.com>
Christophe Rhodes <·····@cam.ac.uk> wrote in message news:<··············@lambda.jcn.srcf.net>...
> Just in case there are implementors in the field who aren't aware of
> it, it might be worth mentioning Henry Baker's paper, available from
> his archive, about the implementation of SUBTYPEP; while sbcl's
> SUBTYPEP doesn't exactly follow his model, because of constraints
> coming from requirements of the type checking engine, there are
> nonetheless good ideas in there for representation and
> canonicalization of types.

Hi,

thanks for reminding us this paper. Reading the paper again, I have
come with a better implementation which uses Baker's approach of
tagging types with integers (as infinite bitvectors), so that AND, OR,
NOT and (SUBTYPEP t1 t2) = (ZEROP (AND t1 (NOT t2))) may be easily
computed.

For instance, when the routine for bringing types into a canonical
form finds an interval (INTEGER 1 10), it creates a new tag to
identify it. The formula is (logior (ash 1 number-of-existing-types)
tag-of-subtype-1 ....), where TAG-OF-SUBTYPE-[1..n] are the tags of
the pre-registered subtypes of this interval (As you see, I store
types which are not orthogonal to each other). However, since this
interval is also a subtype of INTEGER and of many other pre-registered
intervals, the tags for these types have to be updated by "LOGIORing"
with the newly created type. This means a side effect on the type
database, which either has to be re-created on each call to SUBTYPEP
or has to carry these newly-registered (and possibly useless) types as
long as our lisp image runs.

Has anybody come with a better alternative? If someone wants to have a
look at the prototype of the code (works mostly, but has bugs and
cannot boot ECL!!!), see http://www.arrakis.es/~worm/predlib-new.lsp

Juanjo
From: Christophe Rhodes
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sqllz7xc7r.fsf@lambda.jcn.srcf.net>
····@arrakis.es (Juanjo) writes:

> I am in the process of writing a new SUBTYPEP and TYPEP routines for
> ECL (A Common-Lisp implementation hosted at SourceForge,
> http://ecls.sf.net). I am almost there, but in comparison to other
> implementations, I have currently chosen to signal an error when the
> type specifier is not known to be a type to the system.
> [...]
> To myself, that SUBTYPEP may signal an error has been useful in the
> last week, as it has pointed out a few errors in other parts of the
> code.

From my point of view, I don't like the idea of subtypep signalling an
error [except in the case of something which can never be a valid type
specifier, such as #.(make-array 5)].  The reasoning goes that
subtypep is likely to be used in the implementation.

CLHS 3.2.2.3 specifically says that an unknown type can be used in a
type declation.  This means that the following code is valid:

(defun foo (x)
  (declare (type bar x))
  (+ x 1))
[ ... some time later ... ]
(deftype bar () '(integer 4 6))

So, how should the compiler interpret the type declaration in FOO?
Internally, it's going to want to do something like 
  (subtypep 'bar 'fixnum)
to see if the addition can be compiled to something more efficient
than the generic addition.  Of course, in this case, the compiler
can't know, because BAR is an unknown type, but neither should it blow
up with an error.  This isn't a solid argument (as an implementation
would be allowed to have an internal function for its own use with the
right semantics), but I don't see that there's a good reason for
hiding this behaviour from the user.

Of course, I quite agree that evaluating
  (typep 1 'bar)
before BAR has been defined should signal an error.  But I think that
subtypep is asking a question about the compiler's current state of
knowledge, and I don't think that the compiler should _know_ that
there will never be a type of a given name.

Good luck,

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Rob Warnock
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <CeWcnWdxwbQN8R2jXTWc-g@speakeasy.net>
Juanjo <····@arrakis.es> wrote:
+---------------
| 4) The ANSI specification says nothing about exceptional conditions in
| SUBTYPEP.
+---------------

Not quite -- it says:

	Exceptional Situations: None. 

To me, that suggests "never throws an exception". In particular, given
the definition of SUBTYPEP, I should think that this should be fairly
reliable:

	(defun valid-subtype-spec-p (x)
	  (multiple-value-bind (subtype-p valid-p)
	      (subtypep x t)
	    (and subtype-p valid-p)))


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kent M Pitman
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sfwd6kf5v3y.fsf@shell01.TheWorld.com>
····@rpw3.org (Rob Warnock) writes:

> Juanjo <····@arrakis.es> wrote:
> +---------------
> | 4) The ANSI specification says nothing about exceptional conditions in
> | SUBTYPEP.
> +---------------
> 
> Not quite -- it says:
> 
> 	Exceptional Situations: None. 
> 
> To me, that suggests "never throws an exception".

Not to me. :)

I think you will will get in a LOT of trouble if you read it that way... 
(I certainly never intended it to be read that way when I wrote it.)

First, exceptions are not thrown.  Exception is not even terminology in the 
language standard.  Exceptional situations are part of the real world, not
of programs, and they are represented by conditions.  Signaling, not throwing,
is an operation on conditions, not exceptions nor exceptional situations.
The term exceptional situation exists because there are some such situations
that are never detected, and is intended to be a superset of the set of
detected situations.  Throwing is already something that is a low-level
stack communication mechanism that goes well beyond the condition system.
Restarting uses throwing as a means of implementing the transfer of control
portion of the restart process.  Signaling is not restarting, though; 
signaling has an additional element, handling, which unlike in most other
languages, is separate from restarting.  (Dylan actually does the same 
separation, but then unifies the concepts, blurring two unrelated phases
of the signaling process.)  Abstractly, signaling is a request for advice,
not a decision to take that advice.  Handling is the decision to use a
particular piece of advice (for reasons of  history, taken by the handler
instead of offered back as data to the signaler to use).

Anyway, second, beyond the issue of terminology, CL is not like Java on
another point: functions do not have type signatures which tell you what
they can signal.  For example, a valid implementation of + could signal
network error, if the way that the + function worked was to consult a friend
at another host and if the other host were down.  CL does not preclude you
from signaling ANY errors.    Unlike Java, too, it is fine to handle 
conditions that are not apparently signaled in what you are calling.
This can be important not only in the scenario I just talked about, but also
if you get into a recursive error breakpoint where conditions might be
signaled, or if your process is interrupted with code you didn't expect.
e.g., (process-interrupt process  #'(lambda (x) (error 'file-error ...)))
could interrupt a call to EQL, which you might think never signals an error.

Third, beyond the issues of terminology and interrupts and other things
reserved to implementations, there is the fact that the Exceptional Situations
is just a place to put stuff that didn't make sense in the description.
I definitely did NOT redundantly list things in there that are in the
Description, and I definitely DID often make arbitrary decisions about
where something when when there was a choice.  e.g., the FOO function might
say "Checks that its argument is a frob; otherwise, signals an error."
in the Description and nothing in the Exceptional Situations, or it might
say nothing about the argument other than that it's a frob in the argument
signature, and the Exceptional Situations might say "Signals type-error if
the-frob is not a frob."

> In particular, given
> the definition of SUBTYPEP, I should think that this should be fairly
> reliable:
> 
> 	(defun valid-subtype-spec-p (x)
> 	  (multiple-value-bind (subtype-p valid-p)
> 	      (subtypep x t)
> 	    (and subtype-p valid-p)))

I don't think this at all.  It seems to me that 
 (valid-subtype-spec-p 'foo)
could signal an error.

I prefer to assume that 
 (deftype foo () (error "You lose."))
 (subtypep 'foo t)
signals an error.  I also prefer to assume that
 (subtypep '(foo . 17))
signals an error. I could imagine an implementation taking another
point of view, and I wouldn't claim it was non-conforming.  But I think
it's a big (and inappropriate) step to go from "there's a possible reading
that says SUBTYPEP will do an implicit IGNORE-ERRORS around attempts to
do type expansion" to "the only possible reading says..."
From: Rob Warnock
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sh6cnQV2QNXrDB2jXTWc-g@speakeasy.net>
Kent M Pitman  <······@world.std.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > Not quite -- it says:
| > 	Exceptional Situations: None. 
| > To me, that suggests "never throws an exception".
| 
| Not to me. :)
| 
| I think you will will get in a LOT of trouble if you read it that way... 
| (I certainly never intended it to be read that way when I wrote it.)
+---------------

See my other response (to Christophe Rhodes). You're right; I'm wrong.

+---------------
| First, exceptions are not thrown.  Exception is not even terminology
| in the language standard.
+---------------

Oops! Sorry for dragging in a "trigger" word with bad connotations.
I didn't mean "throw" as in Lisp's "throw/catch", I meant a much more
colloquial, general meaning, as in to "toss your cookies" or "barf
an error". So no argument: "signal a condition" is reallt what I meant.
Again, apologies for the confusion.

+---------------
| Third, beyond the issues of terminology and interrupts and other things
| reserved to implementations, there is the fact that the Exceptional
| Situations is just a place to put stuff that didn't make sense in the
| description.
+---------------

Yeah, I began to gather that from a re-reading of CLHS 1.4.4.10
"The ``Exceptional Situations'' Section of a Dictionary Entry".

+---------------
| I definitely did NOT redundantly list things in there that are in the
| Description, and I definitely DID often make arbitrary decisions about
| where something when when there was a choice.  e.g., the FOO function might
| say "Checks that its argument is a frob; otherwise, signals an error."
| in the Description and nothing in the Exceptional Situations, or it might
| say nothing about the argument other than that it's a frob in the argument
| signature, and the Exceptional Situations might say "Signals type-error if
| the-frob is not a frob."
+---------------

Or maybe nothing at all in the Description *or* the Exceptional Situations
sections, since [as I noted in my other reply, referenced above] the
global statement in CLHS 1.4.4.3 "The ``Arguments and Values'' Section
of a Dictionary Entry" says [which I had overlooked]:

	Except as explicitly specified otherwise, the consequences
	are undefined if these type restrictions are violated. 

So if a type is given in Arguments and Values (and for SUBTYPEP
one *is* -- the args must be "type specifiers") then it is not
*necessary* (however useful the reminder might be in some cases)
to say anything at all in the Description or the Exceptional Situations
sections, unless the behavior is *different* from the default.

And since "undefined" can mean *anything* (perhaps signalling a condition,
but also perhaps doing nothing at all, hanging, or self-destructing),
saying "signals type-error if the-frob is not a frob" in Description
or Exceptional Situations that is actually a *tighter* specification
of the behavior than the default (which is one of the reasons one
might want to say it, when applicable).

+---------------
| I don't think this at all. It seems to me that (valid-subtype-spec-p 'foo)
| could signal an error.
+---------------

Having re-read those sections of the CLHS more carefully, I now
completely agree. Mea culpa. I really put my foot into it with
this one. Apologies to all.


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kent M Pitman
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sfw1y0vp1h0.fsf@shell01.TheWorld.com>
····@rpw3.org (Rob Warnock) writes:

> +---------------
> | First, exceptions are not thrown.  Exception is not even terminology
> | in the language standard.
> +---------------
> 
> Oops! Sorry for dragging in a "trigger" word with bad connotations.
> I didn't mean "throw" as in Lisp's "throw/catch", I meant a much more
> colloquial, general meaning, as in to "toss your cookies" or "barf
> an error". So no argument: "signal a condition" is reallt what I meant.
> Again, apologies for the confusion.

It's fine.  I figured it was good to have a periodic lecture on
terminology just for good measure.  It's been a while.

> Yeah, I began to gather that from a re-reading of CLHS 1.4.4.10
> "The ``Exceptional Situations'' Section of a Dictionary Entry".

Yay.

> 
> +---------------
> | I definitely did NOT redundantly list things in there that are in the
> | Description, and I definitely DID often make arbitrary decisions about
> | where something when when there was a choice.  e.g., the FOO function might
> | say "Checks that its argument is a frob; otherwise, signals an error."
> | in the Description and nothing in the Exceptional Situations, or it might
> | say nothing about the argument other than that it's a frob in the argument
> | signature, and the Exceptional Situations might say "Signals type-error if
> | the-frob is not a frob."
> +---------------
> 
> Or maybe nothing at all in the Description *or* the Exceptional Situations
> sections, since [as I noted in my other reply, referenced above] the
> global statement in CLHS 1.4.4.3 "The ``Arguments and Values'' Section
> of a Dictionary Entry" says [which I had overlooked]:
> 
> 	Except as explicitly specified otherwise, the consequences
> 	are undefined if these type restrictions are violated. 
> 
> So if a type is given in Arguments and Values (and for SUBTYPEP
> one *is* -- the args must be "type specifiers") then it is not
> *necessary* (however useful the reminder might be in some cases)
> to say anything at all in the Description or the Exceptional Situations
> sections, unless the behavior is *different* from the default.

Yep.
 
> And since "undefined" can mean *anything* (perhaps signalling a condition,
> but also perhaps doing nothing at all, hanging, or self-destructing),
> saying "signals type-error if the-frob is not a frob" in Description
> or Exceptional Situations that is actually a *tighter* specification
> of the behavior than the default (which is one of the reasons one
> might want to say it, when applicable).

Yeah, there's a passage that covers this, too.
See


  1.5.1.4.1 Resolution of Apparent Conflicts in Exceptional Situations

  If more than one passage in this specification appears to apply to
  the same situation but in conflicting ways, the passage that appears
  to describe the situation in the most specific way (not necessarily 
  the passage that provides the most constrained kind of error detection) 
  takes precedence.

  1.5.1.4.1.1 Examples of Resolution of Apparent Conflicts 
              in Exceptional Situations

  Suppose that function foo is a member of a set S of functions that
  operate on numbers. Suppose that one passage states that an error
  must be signaled if any function in S is ever given an argument of
  17. Suppose that an apparently conflicting passage states that the
  consequences are undefined if foo receives an argument of 17. Then
  the second passage (the one specifically about foo) would dominate
  because the description of the situational context is the most
  specific, and it would not be required that foo signal an error on
  an argument of 17 even though other functions in the set S would be
  required to do so.

> +---------------
> | I don't think this at all. It seems to me that (valid-subtype-spec-p 'foo)
> | could signal an error.
> +---------------
> 
> Having re-read those sections of the CLHS more carefully, I now
> completely agree. Mea culpa. I really put my foot into it with
> this one. Apologies to all.

It's good to get questions periodically out in the open, I think.
From: Christophe Rhodes
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <sqisu7jwxk.fsf@lambda.jcn.srcf.net>
[ with apologies to Rob: I failed to drive my Gnus properly on this
  occasion :-/ ]

····@rpw3.org (Rob Warnock) writes:

> Juanjo <····@arrakis.es> wrote:
> +---------------
> | 4) The ANSI specification says nothing about exceptional conditions in
> | SUBTYPEP.
> +---------------
>
> Not quite -- it says:
>
> 	Exceptional Situations: None. 
>
> To me, that suggests "never throws an exception". 

Really?  There are an awful lot of functions described in the CLHS as
having no /specified/ Exceptional Situations, which is what I take
that to mean.

> In particular, given
> the definition of SUBTYPEP, I should think that this should be fairly
> reliable:
>
> 	(defun valid-subtype-spec-p (x)
> 	  (multiple-value-bind (subtype-p valid-p)
> 	      (subtypep x t)
> 	    (and subtype-p valid-p)))

Since T is the universal supertype, I think an implementation would be
perfectly justified in always returning T, T for (subtypep x t), for X
being of type (OR CONS SYMBOL).

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Rob Warnock
Subject: Re: Can SUBTYPEP fail?
Date: 
Message-ID: <XR-cnckuWOZfFh2jXTWc-g@speakeasy.net>
Christophe Rhodes  <·····@cam.ac.uk> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > Not quite -- it says:
| > 	Exceptional Situations: None. 
| > To me, that suggests "never throws an exception". 
| 
| Really?  There are an awful lot of functions described in the CLHS as
| having no /specified/ Exceptional Situations, which is what I take
| that to mean.
+---------------

Looking through the description I saw nothing that could provoke an
exception:

        If type-1 is a recognizable subtype of type-2, the first value
        is true. Otherwise, the first value is false...

Are you suggesting that determining "a recognizable subtype" could
have some value other than "true" or "false"?

Hmmm... I think spoke too soon!! (Oops!) If one of the args isn't in
(OR CONS CLASS SYMBOL), both CMUCL & CLISP error out. And indeed, CLHS
1.4.4.3 "The ``Arguments and Values'' Section of a Dictionary Entry" says:

	Except as explicitly specified otherwise, the consequences
	are undefined if these type restrictions are violated.

And the args of SUBTYPEP are definitely described as "type specifiers",
so if they do not name a defined type (defined either by the language
or by the programmer), then "the consequences are undefined", and
*anything* could happen.

+---------------
| > In particular, given the definition of SUBTYPEP, I should think
| > that this should be fairly reliable:
| >
| > 	(defun valid-subtype-spec-p (x)
| > 	  (multiple-value-bind (subtype-p valid-p)
| > 	      (subtypep x t)
| > 	    (and subtype-p valid-p)))
| 
| Since T is the universal supertype, I think an implementation would be
| perfectly justified in always returning T, T for (subtypep x t), for X
| being of type (OR CONS SYMBOL).
+---------------

Yeah, good point [except it should be (OR CONS SYMBOL CLASS)]. And indeed,
when presented with these forms:

	(valid-subtype-spec-p 'no-such-type)
	(valid-subtype-spec-p '(some weird form))

CMUCL returns NIL for both while CLISP returns T for both.

O.k., I screwed up. I'll crawl back into my hole now...


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607