From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "alin.s" Newsgroups: gmane.emacs.devel Subject: Re: Why isn't the string returned by symbol-name read-only? Date: Sat, 23 Jan 2010 16:33:18 -0800 (PST) Message-ID: <27291323.post@talk.nabble.com> References: <4B5B6250.1080108@censorshipresearch.org> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Trace: ger.gmane.org 1264293221 3720 80.91.229.12 (24 Jan 2010 00:33:41 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 24 Jan 2010 00:33:41 +0000 (UTC) To: Emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Jan 24 01:33:34 2010 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1NYqPz-0001LJ-6w for ged-emacs-devel@m.gmane.org; Sun, 24 Jan 2010 01:33:31 +0100 Original-Received: from localhost ([127.0.0.1]:57553 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NYqQ0-0005yi-7J for ged-emacs-devel@m.gmane.org; Sat, 23 Jan 2010 19:33:32 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NYqPt-0005wF-Qg for emacs-devel@gnu.org; Sat, 23 Jan 2010 19:33:25 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NYqPp-0005rX-Kq for Emacs-devel@gnu.org; Sat, 23 Jan 2010 19:33:25 -0500 Original-Received: from [199.232.76.173] (port=39366 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NYqPp-0005rO-F9 for Emacs-devel@gnu.org; Sat, 23 Jan 2010 19:33:21 -0500 Original-Received: from kuber.nabble.com ([216.139.236.158]:50810) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NYqPp-0003jy-49 for Emacs-devel@gnu.org; Sat, 23 Jan 2010 19:33:21 -0500 Original-Received: from isper.nabble.com ([192.168.236.156]) by kuber.nabble.com with esmtp (Exim 4.63) (envelope-from ) id 1NYqPm-0004ll-QI for Emacs-devel@gnu.org; Sat, 23 Jan 2010 16:33:18 -0800 In-Reply-To: <4B5B6250.1080108@censorshipresearch.org> X-Nabble-From: alinsoar@voila.fr X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 3) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:120316 Archived-At: This is an interesting question, and this is why I answer you. In order to understand and use emacs at its real power you must learn lisp. I recommend you to read and solve all the exercises from a book like the original LISP Manual of McCarthy, or more recent course. Emacs is a beautiful implementation of a Lisp system, and this is why we love him. To answer your question, first of all, try to compile thsese simple programs: main(){unix[(const char *)"emacs"]++;} main(){unix[(const char[]){[0]=3D"emacs"}]++;} In the first case the constant "emacs" is put into .data, and in the second into .rodata. You will see that you get the same error. Now let us see what happens when you declare a function CAR: (extracted from data.c) =0C /* Extract and set components of lists */ DEFUN ("car", Fcar, Scar, 1, 1, 0, doc: /* Return the car of LIST. If arg is nil, return nil. Error if arg is not nil and not a cons cell. See also `car-safe'. See Info node `(elisp)Cons Cells' for a discussion of related basic Lisp concepts such as car, cdr, cons cell and list. */) (list) register Lisp_Object list; { return CAR (list); } To see in detail what that does, you can expand it using gcc -E: you do (rm data.o && VERBOSE=3D1; make): gcc -E -D_BSD_SOURCE -Demacs -DHAVE_CONFIG_H -I. -I/emacs/src ..........= =20 data.c You will get: Lisp_Object Fcar (Lisp_Object) ; struct Lisp_Subr __attribute__ ((__aligned__ (1 << 3))) Scar =3D { PVEC_SUBR | (sizeof (struct Lisp_Subr) = / sizeof (int)), Fcar, 1, 1, "car", 0, 0}; Lisp_Object Fcar (list) register Lisp_Object list; { } You see that before to define the function Fcar, it defines the structure Scar: Lisp_Object Fcar (Lisp_Object) ; struct Lisp_Subr __attribute__ ((__aligned__ (1 << 3))) Scar =3D { PVEC_SUBR | (sizeof (struct Lisp_Subr) = / sizeof (int)), Fcar, 1, 1, "car", 0, 0};=20 Now let us see how this structure looks like: struct Lisp_Subr { EMACS_UINT size; Lisp_Object (*function) (); short min_args, max_args; const char *symbol_name; char *intspec; char *doc; }; You see that the 4th parameter is const char *symbol_name =3D "car". So emacs tries to define the names of the symbols defined with DEFUN into a zone of memory that the compiler marks as read-only. That means that the lisp evaluator must know that it is not allowed to change that zone. Let us see further what happens: By definition of emacs lisp system , the lisp symbols have to be interned into the function syms_of_. In this case, inside syms_of_data (), defsubr (&Scar); Inside this function, void defsubr (sname) struct Lisp_Subr *sname; { Lisp_Object sym; sym =3D intern_c_string (sname->symbol_name); XSETPVECTYPE (sname, PVEC_SUBR); XSETSUBR (XSYMBOL (sym)->function, sname); } Inside intern_c_string (const char *str), it is checked whether the symbol with the name STR is already interned inside the main obarray, and if not, it is internet using the final call. The first call of intern_c_string happens exactly from defsubr statement, and this call forces the symbol to be interned using make_pure_c_string. Next calls of intern_c_string(the same string) happens from READ lisp function (see read1()), and they already find the symbol interned. Lisp_Object intern_c_string (const char *str) { ............ return Fintern (make_pure_c_string (str), obarray); } return Fintern (make_pure_c_string (str), obarray); Here it is the point: make_pure_c_string (str) Lisp_Object make_pure_c_string (const char *data) { Lisp_Object string; struct Lisp_String *s; int nchars =3D strlen (data); s =3D (struct Lisp_String *) pure_alloc (sizeof *s, Lisp_String); s->size =3D nchars; s->size_byte =3D -1; s->data =3D (unsigned char *) data; s->intervals =3D NULL_INTERVAL; XSETSTRING (string, s); return string; } Now the function pure_alloc: /* Allocate room for SIZE bytes from pure Lisp storage and return a pointer to it. TYPE is the Lisp type for which the memory is allocated. TYPE < 0 means it's not used for a Lisp object. */ Now we see the second function that you use : aset. We look at its definition, and see: DEFUN ("aset", Faset, Saset, 3, 3, 0, doc: /* Store into the element of ARRAY at index IDX the value NEWELT. Return NEWELT. ARRAY may be a vector, a string, a char-table or a bool-vector. IDX starts at 0. */) (array, idx, newelt) register Lisp_Object array; Lisp_Object idx, newelt; { .... CHECK_IMPURE (array); } The definition of CHECK_IMPURE is : /* Signal an error if OBJ is pure. */ #define CHECK_IMPURE(obj) \ { if (PURE_P (obj))=09 \ pure_write_error (); } and finally we get the result of the problem: void pure_write_error () { error ("Attempt to modify read-only object"); } Here it is why the error is generated in the second case and not in the first case. In the first case, the symbol 'FOO is interned inside obarray during the reading operation, while in the second case the symbol is interned during the initialization of emacs, and this is different. Note hoever in , that inside read1(), a symbol is interned inside pure space if you set the variable Vpurify_flag accordingly. You can set this variable using the evaluator (its name is pure, but its value is not in pure storage, so the value can be changed ;) ). I do not know why the idea of pure storage was introduced in emacs; maybe in order to connect it to the idea of constant of C code, but I am not absolutely sure. I have not met the idea of pure storage into a standard course of Lisp. I do not know why Richard did want to insert this concept. I hope that my long message be useful. Sorry for any king of error that mingled around. Daniel Colascione-3 wrote: >=20 > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 >=20 > Consider >=20 > (let ((name (symbol-name 'foo))) > (aset name 0 ?x) > (cons name (symbol-name 'foo))) >=20 > That yields ("xoo" . " xoo") >=20 > Now try >=20 >=20 > (let ((name (symbol-name 'car))) > (aset name 0 ?x) > (cons name (symbol-name 'car))) >=20 > That returns in an error when you try to evaluate it. The object > returned by (symbol-name 'car) must have some read-only bit set. >=20 > Why isn't that bit set for *all* symbol names? > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.10 (Darwin) >=20 > iEYEARECAAYFAktbYlAACgkQ17c2LVA10VsTLQCcCjDdAU9NSvOAVEMmVHfyhXxp > PRMAmgPmovQuhwTUwKGIFvd5giGQyXy4 > =3D6FHg > -----END PGP SIGNATURE----- >=20 >=20 >=20 >=20 --=20 View this message in context: http://old.nabble.com/Why-isn%27t-the-string-= returned-by-symbol-name-read-only--tp27289855p27291323.html Sent from the Emacs - Dev mailing list archive at Nabble.com.