emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scratch/object-type 77351fa6dee 2/2: Add object-type and preserve behavi


From: Stefan Monnier
Subject: scratch/object-type 77351fa6dee 2/2: Add object-type and preserve behavior of type-of
Date: Wed, 13 Mar 2024 19:16:26 -0400 (EDT)

branch: scratch/object-type
commit 77351fa6dee7155f781193f7204ca33e783e6d98
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>

    Add object-type and preserve behavior of type-of
---
 doc/lispref/objects.texi          | 32 ++++++++++++++++++++++++++------
 etc/NEWS                          | 10 +++++-----
 lisp/emacs-lisp/cl-generic.el     |  5 ++---
 lisp/emacs-lisp/cl-preloaded.el   |  2 --
 lisp/emacs-lisp/eieio-core.el     |  2 +-
 lisp/emacs-lisp/seq.el            |  3 +--
 lisp/subr.el                      | 17 +++++++++++++++++
 src/comp.c                        |  2 +-
 src/data.c                        | 18 ++++++++++++------
 src/emacs-module.c                |  7 ++++++-
 src/lisp.h                        |  6 ++----
 src/puresize.h                    |  2 +-
 src/sqlite.c                      | 17 ++++++-----------
 test/lisp/emacs-lisp/ert-tests.el |  8 ++++----
 14 files changed, 84 insertions(+), 47 deletions(-)

diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi
index 00581814825..093a1718937 100644
--- a/doc/lispref/objects.texi
+++ b/doc/lispref/objects.texi
@@ -2175,7 +2175,7 @@ with references to further information.
 function @code{type-of}.  Recall that each object belongs to one and
 only one primitive type; @code{type-of} tells you which one (@pxref{Lisp
 Data Types}).  But @code{type-of} knows nothing about non-primitive
-types.  In most cases, it is more convenient to use type predicates than
+types.  In most cases, it is preferable to use type predicates than
 @code{type-of}.
 
 @defun type-of object
@@ -2186,9 +2186,8 @@ This function returns a symbol naming the primitive type 
of
 @code{float}, @code{font-entity}, @code{font-object},
 @code{font-spec}, @code{frame}, @code{hash-table}, @code{integer},
 @code{marker}, @code{mutex}, @code{obarray}, @code{overlay}, @code{process},
-@code{string}, @code{subr-primitive}, @code{subr-native-elisp},
-@code{special-form}, @code{symbol}, @code{null}, @code{boolean},
-@code{thread}, @code{vector}, @code{window}, or @code{window-configuration}.
+@code{string}, @code{subr}, @code{symbol}, @code{thread},
+@code{vector}, @code{window}, or @code{window-configuration}.
 However, if @var{object} is a record, the type specified by its first
 slot is returned; @ref{Records}.
 
@@ -2197,9 +2196,9 @@ slot is returned; @ref{Records}.
      @result{} integer
 @group
 (type-of 'nil)
-     @result{} null
+     @result{} symbol
 (type-of '())    ; @r{@code{()} is @code{nil}.}
-     @result{} null
+     @result{} symbol
 (type-of '(x))
      @result{} cons
 (type-of (record 'foo))
@@ -2208,6 +2207,27 @@ slot is returned; @ref{Records}.
 @end example
 @end defun
 
+@defun object-type object
+This function returns a symbol naming @emph{the} type of
+@var{object}.  It usually behaves like @code{type-of}, except
+that it guarantees to return the most precise type possible, which means
+that the specific type it returns may change depending on the
+Emacs version.  For this reason, as a rule you should never compare its
+return value against some fixed set of types.
+
+@example
+(object-type 1)
+     @result{} fixnum
+@group
+(object-type 'nil)
+     @result{} null
+(object-type (record 'foo))
+     @result{} foo
+@end group
+@end example
+@end defun
+
+
 @node Equality Predicates
 @section Equality Predicates
 @cindex equality
diff --git a/etc/NEWS b/etc/NEWS
index d06b3f9c06d..9c4c050ae15 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -62,11 +62,6 @@ more details.
 
 * Incompatible Changes in Emacs 30.1
 
-** 'type-of' sometimes returns more precise types.
-More specifically, for nil and t it returns 'null' and 'boolean'
-instead of just 'symbol' and for "subrs", it now returns one of
-'special-form', 'subr-primitive', or 'subr-native-elisp'.
-
 ** Tree-Sitter modes are now declared as submodes of the non-TS modes.
 In order to help the use of those Tree-Sitter modes, they are now
 declared to have the corresponding non-Tree-Sitter mode as an
@@ -1627,6 +1622,11 @@ values.
 
 * Lisp Changes in Emacs 30.1
 
+** New function 'object-type'.
+This function is like 'type-of' except that it sometimes returns
+a more precise type.  For example, for nil and t it returns 'null'
+and 'boolean' respectively, instead of just 'symbol'.
+
 ** Built-in types have now corresponding classes.
 At the Lisp level, this means that things like (cl-find-class 'integer)
 will now return a class object, and at the UI level it means that
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index b79ef126ed1..22a5f47ace4 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -1334,8 +1334,7 @@ These match if the argument is `eql' to VAL."
 
 (defconst cl--generic--unreachable-types
   ;; FIXME: Try to make that list empty?
-  '(fixnum bignum boolean keyword
-    special-form subr-primitive subr-native-elisp)
+  '(keyword)
   "Built-in classes on which we cannot dispatch for technical reasons.")
 
 (defun cl--generic-type-specializers (tag &rest _)
@@ -1345,7 +1344,7 @@ These match if the argument is `eql' to VAL."
            (cl--class-allparents class)))))
 
 (cl-generic-define-generalizer cl--generic-typeof-generalizer
-  10 (lambda (name &rest _) `(type-of ,name))
+  10 (lambda (name &rest _) `(object-type ,name))
   #'cl--generic-type-specializers)
 
 (cl-defmethod cl-generic-generalizers :extra "typeof" (type)
diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el
index 5cf4ba422df..0e8704a93c1 100644
--- a/lisp/emacs-lisp/cl-preloaded.el
+++ b/lisp/emacs-lisp/cl-preloaded.el
@@ -339,8 +339,6 @@
                                           ',parents))))))
 
 ;; FIXME: Our type DAG has various quirks:
-;; - `subr' says it's a `compiled-function' but that's not true
-;;   for those subrs that are special forms!
 ;; - Some `keyword's are also `symbol-with-pos' but that's not reflected
 ;;   in the DAG.
 ;; - An OClosure can be an interpreted function or a `byte-code-function',
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el
index 8221625d885..2a16f129de9 100644
--- a/lisp/emacs-lisp/eieio-core.el
+++ b/lisp/emacs-lisp/eieio-core.el
@@ -1046,7 +1046,7 @@ method invocation orders of the involved classes."
 
 (defun cl--generic-struct-tag (name &rest _)
   ;; Use exactly the same code as for `typeof'.
-  `(type-of ,name))
+  `(object-type ,name))
 
 (cl-generic-define-generalizer eieio--generic-generalizer
   ;; Use the exact same tagcode as for cl-struct, so that methods
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index cd6f26abdb3..a20cff16982 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -362,8 +362,7 @@ the result.
 
 The result is a sequence of the same type as SEQUENCE."
   (seq-concatenate
-   (let ((type (type-of sequence)))
-     (if (memq type '(null cons)) 'list type))
+   (if (listp sequence) 'list (type-of sequence))
    (seq-subseq sequence 0 n)
    (seq-subseq sequence (1+ n))))
 
diff --git a/lisp/subr.el b/lisp/subr.el
index 38a3f6edb34..c329750f9dc 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -575,6 +575,23 @@ treatment of negative COUNT provided by this function."
   (ash value count))
 
 
+(defun type-of (object)
+  "Return a symbol representing the type of OBJECT.
+The symbol returned names the object's basic type;
+for example, (type-of 1) returns `integer'.
+Contrary to `object-type' the returned type is not always the most
+precise type possible, because instead this function tries to preserve
+compatibility with the return value of previous Emacs versions."
+  (let ((type (object-type object)))
+    (or (cdr (assq type '((bignum . integer)
+                          (fixnum . integer)
+                          (special-form . subr)
+                          (subr-primitive . subr)
+                          (subr-native-elisp . subr)
+                          (null . symbol)
+                          (boolean . symbol))))
+        type)))
+
 ;;;; List functions.
 
 ;; Note: `internal--compiler-macro-cXXr' was copied from
diff --git a/src/comp.c b/src/comp.c
index 3f989c722d4..ed9a62ce857 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -2442,7 +2442,7 @@ emit_limple_insn (Lisp_Object insn)
     {
       Lisp_Object arg1 = arg[1];
 
-      if (EQ (Ftype_of (arg1), Qcomp_mvar))
+      if (EQ (Fobject_type (arg1), Qcomp_mvar))
        res = emit_mvar_rval (arg1);
       else if (EQ (FIRST (arg1), Qcall))
        res = emit_limple_call (XCDR (arg1));
diff --git a/src/data.c b/src/data.c
index 35bd3b19e45..a035a7112c6 100644
--- a/src/data.c
+++ b/src/data.c
@@ -190,16 +190,20 @@ DEFUN ("null", Fnull, Snull, 1, 1, 0,
   return Qnil;
 }
 
-DEFUN ("type-of", Ftype_of, Stype_of, 1, 1, 0,
+DEFUN ("object-type", Fobject_type, Sobject_type, 1, 1, 0,
        doc: /* Return a symbol representing the type of OBJECT.
-The symbol returned names the object's basic type;
-for example, (type-of 1) returns `integer'.  */)
+The symbol returned names the most specific possible type of the object.
+for example, (object-type nil) returns `null'.
+The specific type returned may change depending on Emacs versions,
+so we recommend you use `cl-typep', `cl-typecase', or other predicates
+rather than compare the return value of this function against
+a fixed set of types.  */)
   (Lisp_Object object)
 {
   switch (XTYPE (object))
     {
     case_Lisp_Int:
-      return Qinteger;
+      return Qfixnum;
 
     case Lisp_Symbol:
       return NILP (object) ? Qnull
@@ -217,7 +221,7 @@ for example, (type-of 1) returns `integer'.  */)
       switch (PSEUDOVECTOR_TYPE (XVECTOR (object)))
         {
         case PVEC_NORMAL_VECTOR: return Qvector;
-       case PVEC_BIGNUM: return Qinteger;
+       case PVEC_BIGNUM: return Qbignum;
        case PVEC_MARKER: return Qmarker;
        case PVEC_SYMBOL_WITH_POS: return Qsymbol_with_pos;
        case PVEC_OVERLAY: return Qoverlay;
@@ -4209,6 +4213,7 @@ syms_of_data (void)
   /* Types that type-of returns.  */
   DEFSYM (Qboolean, "boolean");
   DEFSYM (Qinteger, "integer");
+  DEFSYM (Qbignum, "bignum");
   DEFSYM (Qsymbol, "symbol");
   DEFSYM (Qstring, "string");
   DEFSYM (Qcons, "cons");
@@ -4223,6 +4228,7 @@ syms_of_data (void)
   DEFSYM (Qwindow_configuration, "window-configuration");
   DEFSYM (Qprocess, "process");
   DEFSYM (Qwindow, "window");
+  DEFSYM (Qsubr, "subr");
   DEFSYM (Qspecial_form, "special-form");
   DEFSYM (Qsubr_primitive, "subr-primitive");
   DEFSYM (Qsubr_native_elisp, "subr-native-elisp");
@@ -4262,7 +4268,7 @@ syms_of_data (void)
   defsubr (&Scommand_modes);
   defsubr (&Seq);
   defsubr (&Snull);
-  defsubr (&Stype_of);
+  defsubr (&Sobject_type);
   defsubr (&Slistp);
   defsubr (&Snlistp);
   defsubr (&Sconsp);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 08db39b0b0d..91f2315540a 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -702,7 +702,12 @@ module_type_of (emacs_env *env, emacs_value arg)
   emacs_value tem;
 
   MODULE_FUNCTION_BEGIN (NULL);
-  tem = lisp_to_value (env, Ftype_of (value_to_lisp (arg)));
+  Lisp_Object lisp = value_to_lisp (arg);
+  Lisp_Object type = SYMBOLP (lisp) ? Qsymbol
+                     : INTEGERP (lisp) ? Qinteger
+                     : SUBRP (lisp) ? Qsubr
+                     : Fobject_type (lisp);
+  tem = lisp_to_value (env, type);
   MODULE_INTERNAL_CLEANUP ();
   return tem;
 }
diff --git a/src/lisp.h b/src/lisp.h
index f353e4956eb..cdd5f1bf647 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -569,10 +569,8 @@ enum Lisp_Fwd_Type
    your object -- this way, the same object could be used to represent
    several disparate C structures.
 
-   In addition, you need to add switch branches in data.c for Ftype_of.
-
-   You also need to add the new type to the constant
-   `cl--typeof-types' in lisp/emacs-lisp/cl-preloaded.el.  */
+   In addition, you need to add switch branches in data.c for Fobject_type
+   and `cl--define-builtin-type` in lisp/emacs-lisp/cl-preloaded.el.  */
 
 
 /* A Lisp_Object is a tagged pointer or integer.  Ordinarily it is a
diff --git a/src/puresize.h b/src/puresize.h
index ac5d2da30dc..2a716872832 100644
--- a/src/puresize.h
+++ b/src/puresize.h
@@ -47,7 +47,7 @@ INLINE_HEADER_BEGIN
 #endif
 
 #ifndef BASE_PURESIZE
-#define BASE_PURESIZE (2750000 + SYSTEM_PURESIZE_EXTRA + 
SITELOAD_PURESIZE_EXTRA)
+#define BASE_PURESIZE (3000000 + SYSTEM_PURESIZE_EXTRA + 
SITELOAD_PURESIZE_EXTRA)
 #endif
 
 /* Increase BASE_PURESIZE by a ratio depending on the machine's word size.  */
diff --git a/src/sqlite.c b/src/sqlite.c
index 7a018b28aa4..261080da673 100644
--- a/src/sqlite.c
+++ b/src/sqlite.c
@@ -349,9 +349,7 @@ bind_values (sqlite3 *db, sqlite3_stmt *stmt, Lisp_Object 
values)
          value = XCAR (values);
          values = XCDR (values);
        }
-      Lisp_Object type = Ftype_of (value);
-
-      if (EQ (type, Qstring))
+      if (STRINGP (value))
        {
          Lisp_Object encoded;
          bool blob = false;
@@ -385,14 +383,11 @@ bind_values (sqlite3 *db, sqlite3_stmt *stmt, Lisp_Object 
values)
                                       SSDATA (encoded), SBYTES (encoded),
                                       NULL);
        }
-      else if (EQ (type, Qinteger))
-       {
-         if (BIGNUMP (value))
-           ret = sqlite3_bind_int64 (stmt, i + 1, bignum_to_intmax (value));
-         else
-           ret = sqlite3_bind_int64 (stmt, i + 1, XFIXNUM (value));
-       }
-      else if (EQ (type, Qfloat))
+      else if (FIXNUMP (value))
+       ret = sqlite3_bind_int64 (stmt, i + 1, XFIXNUM (value));
+      else if (BIGNUMP (value))
+       ret = sqlite3_bind_int64 (stmt, i + 1, bignum_to_intmax (value));
+      else if (FLOATP (value))
        ret = sqlite3_bind_double (stmt, i + 1, XFLOAT_DATA (value));
       else if (NILP (value))
        ret = sqlite3_bind_null (stmt, i + 1);
diff --git a/test/lisp/emacs-lisp/ert-tests.el 
b/test/lisp/emacs-lisp/ert-tests.el
index 289069362b3..1aff73d66f6 100644
--- a/test/lisp/emacs-lisp/ert-tests.el
+++ b/test/lisp/emacs-lisp/ert-tests.el
@@ -674,7 +674,7 @@ This macro is used to test if macroexpansion in `should' 
works."
 
 (ert-deftest ert-test-explain-equal ()
   (should (equal (ert--explain-equal nil 'foo)
-                 '(different-types nil foo)))
+                 '(different-atoms nil foo)))
   (should (equal (ert--explain-equal '(a a) '(a b))
                  '(list-elt 1 (different-atoms a b))))
   (should (equal (ert--explain-equal '(1 48) '(1 49))
@@ -732,10 +732,10 @@ This macro is used to test if macroexpansion in `should' 
works."
                  nil))
   (should (equal (ert--plist-difference-explanation
                   '(a b c t) '(a b))
-                 '(different-properties-for-key c (different-types t nil))))
+                 '(different-properties-for-key c (different-atoms t nil))))
   (should (equal (ert--plist-difference-explanation
                   '(a b c t) '(c nil a b))
-                 '(different-properties-for-key c (different-types t nil))))
+                 '(different-properties-for-key c (different-atoms t nil))))
   (should (equal (ert--plist-difference-explanation
                   '(a b c (foo . bar)) '(c (foo . baz) a b))
                  '(different-properties-for-key c
@@ -778,7 +778,7 @@ This macro is used to test if macroexpansion in `should' 
works."
                   #("foo" 0 1 (a b))
                   "foo")
                  '(char 0 "f"
-                        (different-properties-for-key a (different-types b 
nil))
+                        (different-properties-for-key a (different-atoms b 
nil))
                         context-before ""
                         context-after "oo")))
   (should (equal (ert--explain-equal-including-properties-rec



reply via email to

[Prev in Thread] Current Thread [Next in Thread]