From: Tomohiro Matsuyama <tomo@cx...>  20120601 01:56:54

Hi, I have found some odd subtypep behavior on function type. CLUSER> (subtypep '(function (fixnum) fixnum) '(function (fixnum) integer)) T T CLUSER> (subtypep '(function (fixnum) fixnum) '(function (integer) integer)) T T CLUSER> (subtypep '(function (fixnum) fixnum) '(function (bit) integer)) NIL T As you may know, function parameters should be contravariant, meaning if we have a>b <: a'>b, then a' <: a must hold. So last two statement could be said wrong, or at least the second value should be false. CLHS says subtypep could return (values nil nil) if it sees `function' on the typespec.  Tomohiro Matsuyama <tomo@...> 
From: Nikodemus Siivola <nikodemus@ra...>  20120603 10:18:08

On 1 June 2012 04:20, Tomohiro Matsuyama <tomo@...> wrote: > I have found some odd subtypep behavior on function type. > > CLUSER> (subtypep '(function (fixnum) fixnum) '(function (fixnum) integer)) > T > T > CLUSER> (subtypep '(function (fixnum) fixnum) '(function (integer) integer)) > T > T > CLUSER> (subtypep '(function (fixnum) fixnum) '(function (bit) integer)) > NIL > T > > As you may know, function parameters should be contravariant, meaning if we have a>b <: a'>b, then a' <: a must hold. So last two statement could be said wrong, or at least the second value should be false. I don't follow. In CL, and SBCL specifically covariance seems exactly right to me. Can you unpack your reasoning a little? If I replace a (function (integer) integer) with (function (fixnum) fixnum) any callsite that relied on the previous definition is still safe: they may now get an error due to narrowing of the type, but any typebased reasoning the system did is still valid. Ie. "if F returns, the thing it returns must be an integer". Of course CLHS SUBTYPEP doesn't specify SUBTYPEP properly  so perhaps we should return NIL, NIL in case of both covariance and contravariance, and implement FSUBTYPEP (or possibly FTYPESCOVARIANTP and FTYPESCONTRAVARIANTP.) Cheers,  Nikodemus 
From: Tomohiro Matsuyama <tomo@cx...>  20120603 13:12:03

> > I have found some odd subtypep behavior on function type. > > > > CLUSER> (subtypep '(function (fixnum) fixnum) '(function (fixnum) integer)) > > T > > T > > CLUSER> (subtypep '(function (fixnum) fixnum) '(function (integer) integer)) > > T > > T > > CLUSER> (subtypep '(function (fixnum) fixnum) '(function (bit) integer)) > > NIL > > T > > > > As you may know, function parameters should be contravariant, meaning if we have a>b <: a'>b, then a' <: a must hold. So last two statement could be said wrong, or at least the second value should be false. > > I don't follow. In CL, and SBCL specifically covariance seems exactly > right to me. Can you unpack your reasoning a little? OK, let me explain my concern with a working example. Here, we have two functions: one takes an argument of type fixnum and another takes an argument of type bit. (declaim (type (function (fixnum) t) functionwithfixnumboundary)) (defparameter functionwithfixnumboundary (lambda (index) (declare (type fixnum index) (optimize (safety 0))) (format t "~D must be a type of fixnum~%" index))) (declaim (type (function (bit) t) functionwithbitboundary)) (defparameter functionwithbitboundary (lambda (index) (declare (type bit index) (optimize (safety 0))) (format t "~D must be a type of bit~%" index))) Both of functions are unsafe, meaning the type of the argument wouldn't be typechecked. Then, let's update the function reference carefully like: (defun variabletype (name) (cdr (assoc 'type (nthvalue 2 (sbcltl2:variableinformation name))))) (when (equal (multiplevaluelist (subtypep (variabletype 'functionwithbitboundary) (variabletype 'functionwithfixnumboundary))) '(t t)) (setq functionwithfixnumboundary functionwithbitboundary)) The above assignment will be evaluated because (function (bit) t) <: (function (fixnum) t) is valid in SBCL. Now, call the function like (note that this function call should be valid): (funcall functionwithfixnumboundary 10) Then, we will get the following message. 10 must be a type of bit In a real world program, such a illegal function call might cause the program SEGV. The problem is that the subtypep states (function (bit) t) is subtype of (function (fixnum) t), though actually (function (bit) t) is NOT subtype of (function (fixnum) t), in a meaning of that a value of the subtype can be used as a value of supertype. That's what I wanted to explain.  Tomohiro Matsuyama <tomo@...> 
From: Christophe Rhodes <csr21@ca...>  20120609 08:32:50

Tomohiro Matsuyama <tomo@...> writes: > Then, we will get the following message. > > 10 must be a type of bit > > In a real world program, such a illegal function call might cause the program SEGV. > > The problem is that the subtypep states (function (bit) t) is subtype of (function (fixnum) t), though actually (function (bit) t) is NOT subtype of (function (fixnum) t), in a meaning of that a value of the subtype can be used as a value of supertype. > > That's what I wanted to explain. But: in CL, FUNCTION declarations aren't attached to function objects themselves, but to call sites (names). In each of the following cases, the declaration does not affect the object itself, but the call sites: see <http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm#function>;. (let ((x (lambda (...) ...))) (declare (type (function (bit) t) x)) (funcall x 1)) (flet ((x (...) ...)) (declare (ftype (function (bit) t) x)) (x 1)) Christophe 