ctype
ctype copied to clipboard
ctype= Returns nil with Keyword Parameters
(assert
(ctype:ctype=
(ctype:cfunction (make-instance
'ctype:lambda-list
:required ()
:optional ()
:rest (ctype:bot)
:keyp t
:keys (list (cons 'var (ctype:specifier-ctype 'integer)))
:aokp nil)
(ctype:values-specifier-ctype '(values integer &rest t)))
(ctype:specifier-ctype
'(function (&key (var integer)) integer))))
The assertion
(ctype:ctype=
#<ctype:cfunction (function (&key (var integer))
(values integer &rest t))>
#<ctype:cfunction (function (&key (var integer))
(values integer &rest t))>)
That looks a bit funky to me. Similar experiments work for required, optional, and rest style parameters. Is there something I'm missing when it comes to the keyword parameters?
You have the rest type as bottom, which is probably not correct. Since the function takes keywords, any type of argument can be validly provided in the rest list (if only through :allow-other-keys). That might not be the problem here though. Did your paste cut off?
I thought rest type should be bottom to indicate that there is not rest parameter (no &rest in lambda-list). Are you saying that it should not be the bottom since &key comes after &rest? These functions I'm talking about don't have &allow-other-keys.
a rest type of bottom indicates that that the function is not passed arguments other than required and optional. so if the rest type is bottom, keyword arguments, which are not required or optional, cannot be accepted. if the function accepts keywords the rest type should be top.
function types are not strictly related to the lambda list of the function: they just describe what calls are valid. It is also permissible to declare local function types that describe calls without bothering with what the function actually accepts. For example you could have (defun mylist (&rest elems) elems); it would then be permissible to declare in some scope that (ftype (function (float float) list) mylist) to indicate that within that scope, mylist is only ever passed two floats.
I was referring to :allow-other-keys, which is a distinct mechanism from the &allow-other-keys lambda list keyword. The short version is that if you pass :allow-other-keys t, any function that accepts keywords can be made to accept any keywords even if the function lambda list does not have &allow-other-keys. See CLHS 3.4.1.4.1 for details.
That is all really interesting and makes perfect sense now. Except when I inspect (ctype:specifier-ctype '(function (&key (var integer)))) I get:
All Slots:
[ ] %required = nil
[ ] %optional = nil
[ ] %rest = #<ctype:disjunction nil>
[ ] %keyp = t
[ ] %keys = ((var . #<ctype:range integer>))
[ ] %aokp = nil
It looks to me like the rest is (ctype:bot).
It's quite possible keyword parameter types are in fact broken. I have not used this library as thoroughly as I had hoped. I might be able to take a look tomorrow.
okay, yeah, somewhat more fundamental problem is that I did not implement function type subtypep in the presence of keyword types: https://github.com/s-expressionists/ctype/blob/main/cfunction.lisp#L42-L44