From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier via "Emacs development discussions." Newsgroups: gmane.emacs.devel Subject: Re: Declaring Lisp function types Date: Sat, 02 Mar 2024 16:19:02 -0500 Message-ID: References: Reply-To: Stefan Monnier Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="36600"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) To: emacs-devel@gnu.org Cancel-Lock: sha1:P2Ka+nVHCOblEeUMt2SnyHk/+XE= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sat Mar 02 22:19:56 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rgWlw-0009LK-Cr for ged-emacs-devel@m.gmane-mx.org; Sat, 02 Mar 2024 22:19:56 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rgWlJ-0003mq-Qw; Sat, 02 Mar 2024 16:19:17 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rgWlH-0003kq-L9 for emacs-devel@gnu.org; Sat, 02 Mar 2024 16:19:15 -0500 Original-Received: from ciao.gmane.io ([116.202.254.214]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rgWlG-0002YS-1w for emacs-devel@gnu.org; Sat, 02 Mar 2024 16:19:15 -0500 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1rgWlD-0008R0-87 for emacs-devel@gnu.org; Sat, 02 Mar 2024 22:19:11 +0100 X-Injected-Via-Gmane: http://gmane.org/ Received-SPF: pass client-ip=116.202.254.214; envelope-from=ged-emacs-devel@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.249, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:316708 Archived-At: > (declaim (ftype (function (integer integer) integer) sum)) > ;; ^^inputs ^^output [optional] > (defun sum (a b) > (declare (integer a b)) > (+ a b)) Non-starter for me: the separation into two steps makes it unclear what the declaration applies to (e.g. when re-running the above code, does the `declaim` apply to the old definition (the one active when the `declaim` is executed)® the the one that's about to be installed)? > ;;2 > (defun sum (a b) > (declare (integer a b)) > (+ a b)) None starter because of how we defined `declare`, where we'd have to define every existing type as a valid declaration idenitifer. > ;;3 through 'defstar' (a CL library not in the standard) > (defun* sum ((a integer) (b integer)) > (+ a b)) > ;;4 again through 'defstar' > (defun* (sum -> integer) ((a integer) (b integer)) > (+ a b)) Acceptable, with some tweaks to better fit my favorite bikeshed color. > (defun sum (a b) > (declare (ftype (function (integer integer) integer))) > (+ a b)) The `f` of `ftype` is redundant with the following `function`, so we could shorten that to: (defun sum (a b) (declare (ftype (integer integer) integer)) (+ a b)) > (defun sum (a b) > (declare (function (integer integer) integer)) > (+ a b)) It's cute, I guess. Whether to prefer `function`, `ftype`, or Adam's `type`, is largely a "bikeshed color" choice. I do prefer the latter two because we already know that this is a function, whereas we don't know that this is a *type* (and they're shorter, to boot). Later you said: > Fact is, we already use the form (function (ATYPES) RTYPE) as type > specifier for functions. So (ftype (function (ATYPES) RTYPE)) would be > the most correct form semantically, where `ftype` (or `type` or really > what we prefer) would be the declaration which takes the type specifier > as argument. Of course (declare (ftype (integer integer) integer)) would still end up generating something like (foo-declare-type 'sum '(function (integer integer) integer)) so I see no semantic issue with using `ftype` or `type` here, unless there are functions whose type could take another form than (function )? Are you thinking of types like (or (function (int) int) (function (float) float))? More important I think is to document what such annotations mean and what they should look like (currently, this is not super important, because the annotations live together with the code that uses them, but if we move them outside of `comp.el`, the "contract" needs to be made more explicit). - How they interact with `&optional` and `&rest` (or even `&key` for `c-defun`). - What will/could happen if one of the arguments does not have the specified type? - What will/could happen if the result does not have the specified type? - Do we have types to say "arg unused" or "no return value"? - Can we have higher-order function types, like (function (proc (function (proc string) void)) void) and if so, again, what does it mean in terms of what can happen if the runtime values don't actually match the announced types (e.g. what happens (and when) if we pass a function that has the "wrong type")? Stefan