unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Guile Emacs: Elisp nil/t and Guile #nil/#t
@ 2013-08-01  2:03 Taylan Ulrich B.
  2013-08-03 16:23 ` Neil Jerram
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Taylan Ulrich B. @ 2013-08-01  2:03 UTC (permalink / raw)
  To: bt; +Cc: guile-devel

[-- Attachment #1: Type: text/plain, Size: 3541 bytes --]

Hi,

It occurred to me that nil and t are basically just symbols in Elisp,
just with some magical properties.  Like any symbol, they respond to
symbolp, have a plist, value and symbol slot (although the value slot is
immutable), etc.  They're self-quoting, so 'nil and 't also just return
nil and t.  Nasty stuff.  Given all that, the #nil and #t values of
Guile are obviously not nearly interchangeable.  Did anyone already have
a solution in mind?  If not, I have thought of and implemented a
solution, which is dirty but seems to work well, except for perhaps
incorporating overhead in Elisp code (but not Scheme).  Explanation
follows.

* Qnil and Qt are simply SCM_ELISP_NIL and SCM_BOOL_T.

* NILP is simply scm_is_lisp_false, naturally.

* SYMBOLP handles Qnil and Qt specially:

  (SMOB_TYPEP (x, lisp_symbol_tag) || EQ (x, Qnil) || EQ (x, Qt))

  This has some overhead.  Maybe a more efficient solution exists.

* XSYMBOL handles Qnil and Qt specially, returning SMOB pointers for
  Qnil_ and Qt_ instead (explanation will follow):

  ((struct Lisp_Symbol *)                               \
   (EQ (a, Qnil) ? SMOB_PTR (Qnil_)                     \
    : EQ (a, Qt) ? SMOB_PTR (Qt_)                       \
    : (eassert (SMOB_TYPEP (a, lisp_symbol_tag)),       \
       SMOB_PTR (a))))

  Again, overhead.

* Last part is fancy: Qnil_ and Qt_ are basically the old Qnil and Qt,
  and are initialized with intern("nil") and intern("t"), however the
  implementation of intern has a twist: on subsequent calls with "nil"
  and "t" it actually returns Qnil and Qt instead of Qnil_ and Qt_, this
  works well because as per the previous points we assured that Qnil and
  Qt (SCM_ELISP_NIL and SCM_BOOL_T) are interchangeable with the symbols
  Qnil_ and Qt_ in the Elisp C API.  This incorporates overhead in
  intern, when returning and already-interned symbol: it is first tested
  against Qnil_ and Qt_, before being returned.

Note that `read' uses intern, too, so that's how we get Qnil and Qt when
reading source code or other data.

(Tell me if I missed a way in which one can accidentally access the
underlying nil and t symbols instead of the "delegating" Qnil and Qt
values, or something that could expose the non-symbol nature of the Qnil
and Qt values, for they must appear to be symbols.)

The result is that "everything works fine", except that I don't know how
much I slowed down SYMBOLP, XSYMBOL, and intern:

(The following examples use the Elisp macro `guile-ref' which works like
Guile's @, and they pass Guile procedures to funcall; I implemented
these locally.)

(funcall (guile-ref (guile) null?) nil) => t
(funcall (guile-ref (guile) not) nil) => t
(eq (eval-scheme "#nil") nil) => t
(eq (eval-scheme "#t") t) => t
(symbolp nil) => t
(symbolp t) => t
(symbol-value nil) => nil
(symbol-value t) => t
(null (eval-scheme "#nil")) => t
(null (eval-scheme "#f")) => t
(null (eval-scheme "'()")) => t

Patches follow.  The first one is the one relevant to the topic.  The
second allows Scheme procedures in `funcall' (thus also `apply') and
function-slots of symbols; the third implements guile-ref (@) and
guile-private-ref (@@), and fixes eval-scheme to not print excessively
(git insisted on putting the two changes in the same hunk, I gave up).
I'm providing the latter two for completion's sake and in case you want
to test this yoursel, since there's otherwise no way to pass Elisp data
to Scheme procedures (eval-scheme takes a string).  The problems they
solve will probably be solved better in the future.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Reconcile Elisp nil and t with Guile --]
[-- Type: text/x-patch, Size: 5663 bytes --]

From f926a808e98e9ace24d07ee9ca7c1137f4670a62 Mon Sep 17 00:00:00 2001
From: Taylan Ulrich B <taylanbayirli@gmail.com>
Date: Thu, 1 Aug 2013 03:45:09 +0300
Subject: [PATCH 1/3] Reconcile Elisp nil and t with Guile #nil and #t.

---
 src/data.c  |  6 +++---
 src/lisp.h  | 16 +++++++++++-----
 src/lread.c | 47 +++++++++++++++++++++++++----------------------
 3 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/src/data.c b/src/data.c
index 347c3f9..6d7c95d 100644
--- a/src/data.c
+++ b/src/data.c
@@ -34,7 +34,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "font.h"
 #include "keymap.h"
 
-Lisp_Object Qnil, Qt, Qquote, Qlambda, Qunbound;
+Lisp_Object Qnil, Qnil_, Qt, Qt_, Qquote, Qlambda, Qunbound;
 static Lisp_Object Qsubr;
 Lisp_Object Qerror_conditions, Qerror_message, Qtop_level;
 Lisp_Object Qerror, Quser_error, Qquit, Qargs_out_of_range;
@@ -3081,8 +3081,8 @@ syms_of_data (void)
   PUT_ERROR (Qunderflow_error, Fcons (Qdomain_error, arith_tail),
 	     "Arithmetic underflow error");
 
-  staticpro (&Qnil);
-  staticpro (&Qt);
+  staticpro (&Qnil_);
+  staticpro (&Qt_);
   staticpro (&Qunbound);
 
   /* Types that type-of returns.  */
diff --git a/src/lisp.h b/src/lisp.h
index 438affb..2afac48 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -209,19 +209,24 @@ enum enum_USE_LSB_TAG { USE_LSB_TAG = 1 };
 #define lisp_h_INTEGERP(x) (SCM_I_INUMP (x))
 #define lisp_h_MARKERP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Marker)
 #define lisp_h_MISCP(x) (SMOB_TYPEP (x, lisp_misc_tag))
-#define lisp_h_NILP(x) EQ (x, Qnil)
+#define lisp_h_NILP(x) (scm_is_lisp_false (x))
 #define lisp_h_SET_SYMBOL_VAL(sym, v) \
    (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value = (v))
 #define lisp_h_SYMBOL_CONSTANT_P(sym) (XSYMBOL (sym)->constant)
 #define lisp_h_SYMBOL_VAL(sym) \
    (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value)
-#define lisp_h_SYMBOLP(x) (SMOB_TYPEP (x, lisp_symbol_tag))
+#define lisp_h_SYMBOLP(x) \
+   (SMOB_TYPEP (x, lisp_symbol_tag) || EQ (x, Qnil) || EQ (x, Qt))
 #define lisp_h_VECTORLIKEP(x) (SMOB_TYPEP (x, lisp_vectorlike_tag))
 #define lisp_h_XCAR(c) (scm_car (c))
 #define lisp_h_XCDR(c) (scm_cdr (c))
 #define lisp_h_XHASH(a) (SCM_UNPACK (a))
-#define lisp_h_XSYMBOL(a) \
-   (eassert (SYMBOLP (a)), (struct Lisp_Symbol *) SMOB_PTR (a))
+#define lisp_h_XSYMBOL(a)                               \
+  ((struct Lisp_Symbol *)                               \
+   (EQ (a, Qnil) ? SMOB_PTR (Qnil_)                     \
+    : EQ (a, Qt) ? SMOB_PTR (Qt_)                       \
+    : (eassert (SMOB_TYPEP (a, lisp_symbol_tag)),       \
+       SMOB_PTR (a))))
 
 /* When compiling via gcc -O0, define the key operations as macros, as
    Emacs is too slow otherwise.  To disable this optimization, compile
@@ -529,7 +534,8 @@ extern int char_table_translate (Lisp_Object, int);
 
 /* Defined in data.c.  */
 extern Lisp_Object Qarrayp, Qbufferp, Qbuffer_or_string_p, Qchar_table_p;
-extern Lisp_Object Qconsp, Qfloatp, Qintegerp, Qlambda, Qlistp, Qmarkerp, Qnil;
+extern Lisp_Object Qconsp, Qfloatp, Qintegerp, Qlambda, Qlistp, Qmarkerp;
+extern Lisp_Object Qnil, Qnil_, Qt, Qt_;
 extern Lisp_Object Qnumberp, Qstringp, Qsymbolp, Qvectorp;
 extern Lisp_Object Qvector_or_char_table_p, Qwholenump;
 extern Lisp_Object Ffboundp (Lisp_Object);
diff --git a/src/lread.c b/src/lread.c
index 859725d..06f6e14 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3737,7 +3737,16 @@ it defaults to the value of `obarray'.  */)
 		  SCHARS (string),
 		  SBYTES (string));
   if (!INTEGERP (tem))
-    return tem;
+    {
+      /* The symbols `nil' and `t' are only returned the first time
+       * they're created, to initialize Qnil_ and Qt_.  On subsequent
+       * calls, we return Qnil and Qt instead. */
+      if (EQ (tem, Qnil_))
+        return Qnil;
+      if (EQ (tem, Qt_))
+        return Qt;
+      return tem;
+    }
 
   if (!NILP (Vpurify_flag))
     string = Fpurecopy (string);
@@ -3955,31 +3964,25 @@ init_obarray (void)
   initial_obarray = Vobarray;
   staticpro (&initial_obarray);
 
-  Qunbound = Fmake_symbol (build_pure_c_string ("unbound"));
-  /* Set temporary dummy values to Qnil and Vpurify_flag to satisfy the
-     NILP (Vpurify_flag) check in intern_c_string.  */
-  Qnil = make_number (-1); Vpurify_flag = make_number (1);
-  Qnil = intern_c_string ("nil");
-
-  /* Fmake_symbol inits fields of new symbols with Qunbound and Qnil,
-     so those two need to be fixed manually.  */
-  SET_SYMBOL_VAL (XSYMBOL (Qunbound), Qunbound);
-  set_symbol_function (Qunbound, Qnil);
-  set_symbol_plist (Qunbound, Qnil);
-  SET_SYMBOL_VAL (XSYMBOL (Qnil), Qnil);
-  XSYMBOL (Qnil)->constant = 1;
-  XSYMBOL (Qnil)->declared_special = 1;
-  set_symbol_plist (Qnil, Qnil);
-  set_symbol_function (Qnil, Qnil);
-
-  Qt = intern_c_string ("t");
-  SET_SYMBOL_VAL (XSYMBOL (Qt), Qt);
-  XSYMBOL (Qnil)->declared_special = 1;
-  XSYMBOL (Qt)->constant = 1;
+  Qnil = SCM_ELISP_NIL;
+  Qt = SCM_BOOL_T;
 
   /* Qt is correct even if CANNOT_DUMP.  loadup.el will set to nil at end.  */
   Vpurify_flag = Qt;
 
+  Qnil_ = intern_c_string ("nil");
+  SET_SYMBOL_VAL (XSYMBOL (Qnil_), Qnil);
+  XSYMBOL (Qnil_)->constant = 1;
+  XSYMBOL (Qnil_)->declared_special = 1;
+
+  Qt_ = intern_c_string ("t");
+  SET_SYMBOL_VAL (XSYMBOL (Qt_), Qt);
+  XSYMBOL (Qt_)->constant = 1;
+  XSYMBOL (Qt_)->declared_special = 1;
+
+  Qunbound = Fmake_symbol (build_pure_c_string ("unbound"));
+  SET_SYMBOL_VAL (XSYMBOL (Qunbound), Qunbound);
+
   DEFSYM (Qvariable_documentation, "variable-documentation");
 
   read_buffer = xmalloc_atomic (size);
-- 
1.8.1.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: Allow Scheme procedures as Elisp functions --]
[-- Type: text/x-patch, Size: 1246 bytes --]

From 5b951edbb9710ccbd0178bfea5e0fee4ecbcc40f Mon Sep 17 00:00:00 2001
From: Taylan Ulrich B <taylanbayirli@gmail.com>
Date: Thu, 1 Aug 2013 04:02:40 +0300
Subject: [PATCH 2/3] Allow Scheme procedures as Elisp functions.

* src/eval.c (eval_sub, Ffuncall, funcall_lambda): Allow Scheme
  procedures.
---
 src/eval.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/eval.c b/src/eval.c
index 7911397..b2094e9 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2349,7 +2349,7 @@ eval_sub (Lisp_Object form)
 	    }
 	}
     }
-  else if (COMPILEDP (fun))
+  else if (COMPILEDP (fun) || scm_is_true (scm_procedure_p (fun)))
     val = apply_lambda (fun, original_args);
   else
     {
@@ -2984,7 +2984,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS)  */)
 	    }
 	}
     }
-  else if (COMPILEDP (fun))
+  else if (COMPILEDP (fun) || scm_is_true (scm_procedure_p (fun)))
     val = funcall_lambda (fun, numargs, args + 1);
   else
     {
@@ -3110,6 +3110,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
 	}
       lexenv = Qnil;
     }
+  else if (scm_is_true (scm_procedure_p (fun)))
+    {
+      dynwind_end();
+      return scm_call_n (fun, arg_vector, nargs);
+    }
   else
     emacs_abort ();
 
-- 
1.8.1.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: Add guile-ref and guile-private ref, fix eval-scheme --]
[-- Type: text/x-patch, Size: 2855 bytes --]

From 103a2a2348a3abfd9a2f8f967ba146a856210d7e Mon Sep 17 00:00:00 2001
From: Taylan Ulrich B <taylanbayirli@gmail.com>
Date: Thu, 1 Aug 2013 04:08:14 +0300
Subject: [PATCH 3/3] src/fns.c: Add `guile-ref' and `guile-private-ref'.
 (Feval_scheme): Don't print, it's done automatically.

---
 src/fns.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 4 deletions(-)

diff --git a/src/fns.c b/src/fns.c
index cb89437..79a50ad 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -48,6 +48,8 @@ Lisp_Object Qcursor_in_echo_area;
 static Lisp_Object Qwidget_type;
 static Lisp_Object Qcodeset, Qdays, Qmonths, Qpaper;
 
+static Lisp_Object Qguile_ref, Qguile_private_ref;
+
 static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512;
 \f
 DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
@@ -4502,12 +4504,56 @@ DEFUN ("eval-scheme", Feval_scheme, Seval_scheme, 1, 1,
        doc: /* Evaluate a string containing a Scheme expression.  */)
   (Lisp_Object string)
 {
-  Lisp_Object tem;
-
   CHECK_STRING (string);
+  return scm_c_eval_string (SSDATA (string));
+}
+\f
+static SCM
+elisp_symbol_or_string_to_scm (Lisp_Object obj)
+{
+  return scm_from_locale_symbol (SSDATA (SYMBOLP (obj)
+                                         ? (Fsymbol_name (obj))
+                                         : obj));
+}
+\f
+static SCM
+guile_ref (Lisp_Object args, int privatep)
+{
+  Lisp_Object module, binding;
+
+  if (XINT (Flength (args)) != 2)
+    xsignal2 (Qwrong_number_of_arguments,
+              (privatep ? Qguile_private_ref : Qguile_ref),
+              Flength (args));
 
-  tem = scm_c_eval_string (SSDATA (string));
-  return (INTERACTIVE ? Fprin1 (tem, Qt) : tem);
+  module = Fcar (args);
+  binding = Fcar (Fcdr (args));
+
+  CHECK_LIST (module);
+  CHECK_SYMBOL (binding);
+
+  for (Lisp_Object mod = module; !NILP (mod); mod = XCDR (mod))
+    XSETCAR (mod, elisp_symbol_or_string_to_scm (XCAR (mod)));
+
+  binding = elisp_symbol_or_string_to_scm (binding);
+
+  return ((privatep ? scm_private_ref : scm_public_ref)
+          (module, binding));
+}
+\f
+DEFUN ("guile-ref", Fguile_ref, Sguile_ref, 2, UNEVALLED, 0,
+       doc: /* Reference a binding in a Guile module. */)
+  (Lisp_Object args)
+{
+  return guile_ref (args, 0);
+}
+\f
+DEFUN ("guile-private-ref", Fguile_private_ref, Sguile_private_ref,
+       2, UNEVALLED, 0,
+       doc: /* Reference a private binding in a Guile module. */)
+  (Lisp_Object args)
+{
+  return guile_ref (args, 1);
 }
 \f
 void
@@ -4554,6 +4600,9 @@ syms_of_fns (void)
   DEFSYM (Qcursor_in_echo_area, "cursor-in-echo-area");
   DEFSYM (Qwidget_type, "widget-type");
 
+  DEFSYM (Qguile_ref, "guile-ref");
+  DEFSYM (Qguile_private_ref, "guile-private-ref");
+
   staticpro (&string_char_byte_cache_string);
   string_char_byte_cache_string = Qnil;
 
-- 
1.8.1.2


[-- Attachment #5: Type: text/plain, Size: 8 bytes --]


Taylan

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: Guile Emacs: Elisp nil/t and Guile #nil/#t
  2013-08-01  2:03 Guile Emacs: Elisp nil/t and Guile #nil/#t Taylan Ulrich B.
@ 2013-08-03 16:23 ` Neil Jerram
  2013-08-03 23:13   ` Taylan Ulrich B.
  2013-08-05 12:07 ` Taylan Ulrich B.
  2013-08-17 12:34 ` Ludovic Courtès
  2 siblings, 1 reply; 7+ messages in thread
From: Neil Jerram @ 2013-08-03 16:23 UTC (permalink / raw)
  To: Taylan Ulrich B.; +Cc: bt, guile-devel

taylanbayirli@gmail.com (Taylan Ulrich B.) writes:

> Hi,
>
> It occurred to me that nil and t are basically just symbols in Elisp,
> just with some magical properties.  Like any symbol, they respond to
> symbolp, have a plist, value and symbol slot (although the value slot is
> immutable), etc.  They're self-quoting, so 'nil and 't also just return
> nil and t.  Nasty stuff.  Given all that, the #nil and #t values of
> Guile are obviously not nearly interchangeable.  Did anyone already have
> a solution in mind?

Solution for what problem?

I'm mostly just lurking on the Guile lists these days, but I did work a
while back on the Scheme/Elisp area, so I'm interested to understand the
problem.

Regards,
        Neil



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Guile Emacs: Elisp nil/t and Guile #nil/#t
  2013-08-03 16:23 ` Neil Jerram
@ 2013-08-03 23:13   ` Taylan Ulrich B.
  0 siblings, 0 replies; 7+ messages in thread
From: Taylan Ulrich B. @ 2013-08-03 23:13 UTC (permalink / raw)
  To: Neil Jerram; +Cc: bt, guile-devel

Neil Jerram <neil@ossau.homelinux.net> writes:

> Solution for what problem?

A from-scratch explanation, just so I'm sure I'm clear:

For different languages running on Guile to integrate seamlessly, we
want them to share as many data-types as possible.  E.g. it would be
inacceptable if a JavaScript function returned `true' and a Scheme
procedure receiving this value didn't just see it as #t but instead as
some weird `js-true' value which it needs to handle specially; we want
both JS's true and Scheme's #t to be the same internal value on the
Guile platform.

We use SCM_BOOL_T for said true value.  And for Elisp integration we
invented SCM_ELISP_NIL, which can be used both in place of the global
false value, SCM_BOOL_F, and as the null (aka end-of-list) value for
Lispy languages, SCM_EOL.

Problem is, Elisp isn't really satisfied with *either* of those.  It
expects that its true value and its nil (false and null) value are both
also *symbols*, as if its abuse of nil for two purposes weren't enough.
So, how do we implement a `symbolp', `symbol-value', `symbol-function',
etc. which all work with SCM_BOOL_T and SCM_ELISP_NIL?  (Also, reading
those symbols even in quoted form must yield the same objects, so we
need to make Elisp's `intern' and `read' act accordingly.)



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Guile Emacs: Elisp nil/t and Guile #nil/#t
  2013-08-01  2:03 Guile Emacs: Elisp nil/t and Guile #nil/#t Taylan Ulrich B.
  2013-08-03 16:23 ` Neil Jerram
@ 2013-08-05 12:07 ` Taylan Ulrich B.
  2013-08-17 12:34 ` Ludovic Courtès
  2 siblings, 0 replies; 7+ messages in thread
From: Taylan Ulrich B. @ 2013-08-05 12:07 UTC (permalink / raw)
  To: guile-devel

FYI, the CC'd address of BT Templeton is wrong (.net not .org), sorry
about that.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Guile Emacs: Elisp nil/t and Guile #nil/#t
  2013-08-01  2:03 Guile Emacs: Elisp nil/t and Guile #nil/#t Taylan Ulrich B.
  2013-08-03 16:23 ` Neil Jerram
  2013-08-05 12:07 ` Taylan Ulrich B.
@ 2013-08-17 12:34 ` Ludovic Courtès
  2013-08-19 11:41   ` Taylan Ulrich B.
  2 siblings, 1 reply; 7+ messages in thread
From: Ludovic Courtès @ 2013-08-17 12:34 UTC (permalink / raw)
  To: guile-devel

taylanbayirli@gmail.com (Taylan Ulrich B.) skribis:

> It occurred to me that nil and t are basically just symbols in Elisp,
> just with some magical properties.  Like any symbol, they respond to
> symbolp, have a plist, value and symbol slot (although the value slot is
> immutable), etc.  They're self-quoting, so 'nil and 't also just return
> nil and t.  Nasty stuff.

Perhaps I’m overlooking something.

To me, it looks like it’s just a matter of binding ‘t’ to #t and ‘nil’
to #nil in the elisp run-time.  This is currently not the case:

--8<---------------cut here---------------start------------->8---
elisp@(guile-user)> nil
$3 = #nil
elisp@(guile-user)> 'nil
$4 = nil
elisp@(guile-user)> t
$5 = #t
elisp@(guile-user)> 't
$6 = t
--8<---------------cut here---------------end--------------->8---

In Scheme, 'nil and 't must remain symbols, though.

In terms of language interoperability, the only thing to have in mind is
that elisp adds the #nil value, which Scheme must be able to interpret
correctly and seamlessly:

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (not #nil)
$7 = #t
scheme@(guile-user)> (null? #nil)
$8 = #t
--8<---------------cut here---------------end--------------->8---

HTH,
Ludo’.




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Guile Emacs: Elisp nil/t and Guile #nil/#t
  2013-08-17 12:34 ` Ludovic Courtès
@ 2013-08-19 11:41   ` Taylan Ulrich B.
  2013-08-23 10:12     ` Ludovic Courtès
  0 siblings, 1 reply; 7+ messages in thread
From: Taylan Ulrich B. @ 2013-08-19 11:41 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

ludo@gnu.org (Ludovic Courtès) writes:

> taylanbayirli@gmail.com (Taylan Ulrich B.) skribis:
>
>> It occurred to me that nil and t are basically just symbols in Elisp,
>> just with some magical properties.  Like any symbol, they respond to
>> symbolp, have a plist, value and symbol slot (although the value slot
>> is immutable), etc.  They're self-quoting, so 'nil and 't also just
>> return nil and t.  Nasty stuff.
>
> Perhaps I’m overlooking something.
>
> To me, it looks like it’s just a matter of binding ‘t’ to #t and ‘nil’
> to #nil in the elisp run-time.  This is currently not the case:
>
> elisp@(guile-user)> nil
> $3 = #nil
> elisp@(guile-user)> 'nil
> $4 = nil
> elisp@(guile-user)> t
> $5 = #t
> elisp@(guile-user)> 't
> $6 = t

You mean we should make the Elisp reader return #nil and #t for the
symbols nil and t even when quoted?  The problem with that is that this
would simply make them not be symbols:

(symbolp nil) => nil
(symbolp 'nil) => nil
(symbolp t) => nil
(symbolp 't) => nil
(symbol-value 'nil) => error
(symbol-function 'nil) => error
...

That is, unless we make changes to all the relevant functions that work
on symbols, and make them handle #nil and #t specially.  That is more or
less what my patches do in the Emacs Elisp implementation (by altering
some low-level functions that all others use to work with symbols).


By the way, if I got it right, we intend to scrap most of the Emacs
Elisp implementation once Guile's is done.  That would mean my patches
are in the wrong place, although I suppose the strategy can be ported
over.  That might however add some complexity to the C API, most notably
having both `scm_symbol_p' and some `elisp_symbol_p', forcing the user
to be constantly conscious about the difference between Scheme and Elisp
symbols, and then there's the question whether all Scheme procedures
other than `symbol?' should share the same low-level functions from the
C API with their Elisp equivalents, and thus also work with #nil and #t
when used from Scheme (e.g. `(symbol->string #t) => "t"' in Scheme), or
also have separate Scheme and Elisp variants in the C API such that the
Scheme world is not further confused by the issue.

Another question that raises is how the symbols `nil' and `t', when
generated by Scheme code, should behave in Elisp and the C API.  I guess
we would just have them look like uninterned symbols in Elisp?  As far
as my imagination goes at the moment that seems to be the cleanest
solution.

Taylan



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Guile Emacs: Elisp nil/t and Guile #nil/#t
  2013-08-19 11:41   ` Taylan Ulrich B.
@ 2013-08-23 10:12     ` Ludovic Courtès
  0 siblings, 0 replies; 7+ messages in thread
From: Ludovic Courtès @ 2013-08-23 10:12 UTC (permalink / raw)
  To: Taylan Ulrich B.; +Cc: guile-devel

taylanbayirli@gmail.com (Taylan Ulrich B.) skribis:

> ludo@gnu.org (Ludovic Courtès) writes:
>
>> taylanbayirli@gmail.com (Taylan Ulrich B.) skribis:
>>
>>> It occurred to me that nil and t are basically just symbols in Elisp,
>>> just with some magical properties.  Like any symbol, they respond to
>>> symbolp, have a plist, value and symbol slot (although the value slot
>>> is immutable), etc.  They're self-quoting, so 'nil and 't also just
>>> return nil and t.  Nasty stuff.
>>
>> Perhaps I’m overlooking something.
>>
>> To me, it looks like it’s just a matter of binding ‘t’ to #t and ‘nil’
>> to #nil in the elisp run-time.  This is currently not the case:
>>
>> elisp@(guile-user)> nil
>> $3 = #nil
>> elisp@(guile-user)> 'nil
>> $4 = nil
>> elisp@(guile-user)> t
>> $5 = #t
>> elisp@(guile-user)> 't
>> $6 = t
>
> You mean we should make the Elisp reader return #nil and #t for the
> symbols nil and t even when quoted?

Something like that (probably better than binding ‘nil’ and ‘t’
globally.)

> The problem with that is that this would simply make them not be
> symbols:
>
> (symbolp nil) => nil
> (symbolp 'nil) => nil
> (symbolp t) => nil
> (symbolp 't) => nil
> (symbol-value 'nil) => error
> (symbol-function 'nil) => error
> ...
>
> That is, unless we make changes to all the relevant functions that work
> on symbols, and make them handle #nil and #t specially.

Yeah, that’s what I would do: patch ‘symbolp’ to DTRT.

> That is more or less what my patches do in the Emacs Elisp
> implementation (by altering some low-level functions that all others
> use to work with symbols).

OK.

I think I’d rather let BT answer the rest of your message (I had been
hoping ey would magically chime in ;-)).

Ludo’.



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2013-08-23 10:12 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-01  2:03 Guile Emacs: Elisp nil/t and Guile #nil/#t Taylan Ulrich B.
2013-08-03 16:23 ` Neil Jerram
2013-08-03 23:13   ` Taylan Ulrich B.
2013-08-05 12:07 ` Taylan Ulrich B.
2013-08-17 12:34 ` Ludovic Courtès
2013-08-19 11:41   ` Taylan Ulrich B.
2013-08-23 10:12     ` Ludovic Courtès

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).