From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1.migadu.com ([2001:41d0:1008:1e59::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms8.migadu.com with LMTPS id ALExJ0vOjGXfMwEAkFu2QA (envelope-from ) for ; Thu, 28 Dec 2023 02:24:27 +0100 Received: from aspmx1.migadu.com ([2001:41d0:303:e224::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1.migadu.com with LMTPS id SPHjI0vOjGW6kwAA62LTzQ (envelope-from ) for ; Thu, 28 Dec 2023 02:24:27 +0100 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=protonmail.com header.s=protonmail3 header.b=ruGcYyY1; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gnu.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1703726667; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=UMEEOINjtXbTms6xqpUqQ7rALvdBrrkjk6VuxipvhcA=; b=O0loglbXSnbk1+iEerq26ON1EW64hxkSi/zLcPYQr0fVeTvRJtqHo8CbX7Xygm36vwBY+5 izEqMaSqaZAaZa9pA6NivVA47JYaMt8982G0oG0eXwjwavJ56OpAw3AHeZSVuHtT+i8OsD iyRiRe0EiTHc5HMxdLxK3faWYUY8YiLobIlsOxiHoKGZKJdm7b9brp2RMplCVdzlDXtoht UqcVjhyY/qubA1tuv4n6z5PINESBFbztANqQytsG1z4Am38l7Xekc8D2kDkn/sq3/WtgiQ o2G0tHmykU3vTuhwUmC0P7iS9hqhIjdanzoJAh0hjUbjMbrrHP1vhmS/PLp40w== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1703726667; a=rsa-sha256; cv=none; b=Bxynkl2Pl+XpAdqKxwpxJpSJ7odjV/vg3FT/VolS1ZURhG4mIN2MpXJgJu75rTmY6R6zcl IjBN6l6vQmi88YZrVwKBR/ihD+/WfW3FFtqAcDBccOLIDpcXEqIjDQ3HHNXxFOmSBMIZqZ iNP1bTUm1CwevEu5GZs0pu0B3z0ZJAJbpcdk9bsXBgJmAQ0GQyYUMSmvF52fu/teWh1W6d GjDexkfgpxJYHX4J0aAEP5AaRnjGvjPhIJDseZ5t1jCQbpot+CxDCMHfXE0gTYkG9MHmhu T7IFQ8s9kO51NN29q05F0fuChjn1q6Z5bbO5IZYcZWnjp1NxhrGylwZyA626iQ== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=protonmail.com header.s=protonmail3 header.b=ruGcYyY1; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gnu.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 47F0B3204C for ; Thu, 28 Dec 2023 02:24:27 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rIf81-0008Ui-Nm; Wed, 27 Dec 2023 20:24:05 -0500 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 1rIf7z-0008Th-LS for guix-patches@gnu.org; Wed, 27 Dec 2023 20:24:03 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rIf7z-0002E2-D9 for guix-patches@gnu.org; Wed, 27 Dec 2023 20:24:03 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rIf7y-0007Q0-B2 for guix-patches@gnu.org; Wed, 27 Dec 2023 20:24:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#67786] doc: Add documentation for define-record-type* Resent-From: Skyler Ferris Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Thu, 28 Dec 2023 01:24:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 67786 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 67786@debbugs.gnu.org Received: via spool by 67786-submit@debbugs.gnu.org id=B67786.170372663528503 (code B ref 67786); Thu, 28 Dec 2023 01:24:02 +0000 Received: (at 67786) by debbugs.gnu.org; 28 Dec 2023 01:23:55 +0000 Received: from localhost ([127.0.0.1]:38132 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rIf7q-0007Pe-C5 for submit@debbugs.gnu.org; Wed, 27 Dec 2023 20:23:55 -0500 Received: from mail-40133.protonmail.ch ([185.70.40.133]:13889) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rIf7n-0007PG-7C for 67786@debbugs.gnu.org; Wed, 27 Dec 2023 20:23:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1703726625; x=1703985825; bh=UMEEOINjtXbTms6xqpUqQ7rALvdBrrkjk6VuxipvhcA=; h=Date:To:From:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=ruGcYyY1nDJhjQwOxEiUBlhfOsiwOhkXMVJjYH24KvW8T92nI+TylNR1RDwtuZzUq KM9mfLKcrcrSecCHIFiEaJVT9QpcTB0OVmnI7WGlt7kCFBD+/7tXVS70WwM7Vg/1SL HpyiMt7HYszogMaTEBsSts8DCUiZdIfGoIlaxUG9vdAks1ay0gadkuvHfJ/PQsAWU2 /1GCqaNbBeI0jP6o5sUxkyLCyn/DoouLYamZvo53GvD8PYIPaGQ8TxIeVvFPXbvWll rvI4N6z/W+jEtkGtwOKyTPQ5sO8XnND+x3UaddoLY6p9KxTgQ9vrkRxqF/f31C37+v 2XEZdzY4flqiA== Date: Thu, 28 Dec 2023 01:23:21 +0000 Message-ID: <58aa08f2-37c2-47ab-a16d-99d13e24e911@protonmail.com> In-Reply-To: <10d46484-1f83-4b5f-9cc7-3d9d68998b33@protonmail.com> References: <10d46484-1f83-4b5f-9cc7-3d9d68998b33@protonmail.com> Feedback-ID: 40635331:user:proton MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Skyler Ferris X-ACL-Warn: , Skyler Ferris via Guix-patches From: Skyler Ferris via Guix-patches via Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-Migadu-Spam-Score: -6.75 X-Spam-Score: -6.75 X-Migadu-Queue-Id: 47F0B3204C X-Migadu-Scanner: mx12.migadu.com X-TUID: uGHsk3VsdkPd I wrote this documentation by using the docstring in guix/record.scm as a starting point and expanding on it/reformatting on it to be appropriate for inclusion in a manual. * doc/guix.texi: Add sections describing the typical usage and API for define-record-type* Change-Id: I19e7220553d10652c794e6e0172b2c9ee961f54f --- # It looks like when I sent the last message the spaces in the diff got # converted to non-breaking spaces, which makes it difficult to read in # some clients. This version should be easier to read. The notes from # the previous message are preserved below: # # This version of the patch updates the commit message to explain that I # wrote the documentation by using the docstring in guix/records.scm as # a starting point. This process seemed appropriate to me because it is # being incorporated into the same project for the same purpose. Most of # the commit is new content, but some of it is shared with the docstring # - for example the "thing" struct definition and the explanation of # struct fields. I think that it is useful for the manual and the # docstrings to share content when appropriate to avoid accidentally # communicating contradictory ideas to different audiences, but the # relationship should still be acknowledged. If there is a more formal # manner in which I should indicate this please let me know and I will # be happy to update the commit. This version does not change anything # other than the commit message. =C2=A0doc/contributing.texi |=C2=A0=C2=A0 1 - =C2=A0doc/guix.texi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 | 274 = ++++++++++++++++++++++++++++++++++++++++++ =C2=A02 files changed, 274 insertions(+), 1 deletion(-) diff --git a/doc/contributing.texi b/doc/contributing.texi index 7337f4bd58..d920b2589a 100644 --- a/doc/contributing.texi +++ b/doc/contributing.texi @@ -1313,7 +1313,6 @@ Data Types and Pattern Matching =C2=A0notably the fact that it is hard to read, error-prone, and a hindran= ce =C2=A0to proper type error reports. -@findex define-record-type* =C2=A0@findex match-record =C2=A0@cindex pattern matching =C2=A0Guix code should define appropriate data types (for instance, using diff --git a/doc/guix.texi b/doc/guix.texi index e61a893af9..3cb15eeca3 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -12606,6 +12606,280 @@ G-Expressions =C2=A0@code{(*approximate*)}, but this may change. =C2=A0@end deffn +@node Records in Guix +@section Records in Guix +Guix uses @code{define-record-type*} to define structures with a lispy=20 format. +Packages, operating systems, etc are all defined with +@code{define-record-type*} facilities. If one was using this facility to +define preferences for a text editor, it might look like this: + +@lisp +;; The only valid emulation modes are the symbol 'emacs, the symbol=20 'vim, or +;; the boolean #f. As a convenience to the user, if they pass in a string +;; first convert it to a symbol and accept it if it is valid. +(define (sanitize-emulation-mode value) +=C2=A0 (let ((symbolized-value (cond ((not value)=C2=A0=C2=A0=C2=A0=C2= =A0 #f) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((string? value) (string->sym= bol value)) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (#t=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 value)))) +=C2=A0=C2=A0=C2=A0 (unless (or (not symbolized-value) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (eq? symbolized-value 'emacs) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (eq? symbolized-value 'vim)) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (throw 'bad-emulation-made +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (format #f "Unrecognized emulation mode: ~s" value))) +=C2=A0=C2=A0=C2=A0 symbolized-value)) + +(define-record-type* +=C2=A0 editor-preferences make-editor-preferences +=C2=A0 editor-preferences? this-editor-preferences +=C2=A0 (background-color editor-preferences-background-color +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (default "000000")) +=C2=A0 (text-color=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 editor-preferences-= text-color +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (default "FFFFFF")) +=C2=A0 (emulation-mode=C2=A0=C2=A0 editor-preferences-emulation-mode +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (default #f) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (sanitize sanitize-emulation-= mode))) +@end lisp + +A user could then define their preferences like this: + +@lisp +(define my-preferences +=C2=A0 (editor-preferences +=C2=A0=C2=A0=C2=A0 (background-color "222222") +=C2=A0=C2=A0=C2=A0 (emulation-mode=C2=A0=C2=A0 'vim))) +@end lisp + +The value contained in @code{my-preferences} contains a custom +@code{background-color} and @code{emulation-mode}, but keeps the default +@code{text-color} (@code{"FFFFFF"}). If an invalid=20 @code{emulation-mode} had +been specified, for example if the user passed in @code{"vi"} instead of +@code{"vim"}, @code{sanitize-emulation-mode} would immediately throw an=20 error. + +The program can access values like this: + +@lisp +(editor-preferences-background-color my-preferences) +@result{} "222222" +(editor-preferences-text-color my-preferences) +@result{} "FFFFFF" +(editor-preferences-emulation-mode my-preferences) +@result{} 'vim +@end lisp + +There is no way to define setters (all instances are immutable). + +@node Record Inheritance +@subsection Record Inheritance +It is also possible to inherit from previously defined instances when=20 creating +new ones. Continuing with the editor example, someone might want to=20 base their +preferences on their friend's preferences but customize a value: + +@lisp +(define friends-preferences +=C2=A0 (editor-preferences +=C2=A0=C2=A0=C2=A0 (inherit my-preferences) +=C2=A0=C2=A0=C2=A0 (emulation-mode 'emacs))) +@end lisp + +This keeps the same @code{background-color} and @code{text-color} that are +contained in @code{my-preferences} but changes the @code{emulation-mode} t= o +be @code{'emacs} instead of @code{'vim}. + +Sometimes it does not make sense for a field to be inherited. Suppose=20 that the +@code{} type is updated to contain a username so that = a +friendly greeting can be displayed when the program starts up: + +@lisp +;; Usernames must be strings. It would be strange to pass a username as a +;; symbol, so throw an error in case the user meant to pass in a variable'= s +;; value instead of a literal symbol. +(define (sanitize-username value) +=C2=A0 (unless (string? value) +=C2=A0=C2=A0=C2=A0 (throw 'bad-username +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (format #f "U= sernames must be strings! Got: ~s" value))) +=C2=A0 value) + +(define (sanitize-emulation-mode value) +=C2=A0 (let ((symbolized-value (cond ((not value)=C2=A0=C2=A0=C2=A0=C2= =A0 #f) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((string? value) (string->sym= bol value)) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (#t=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 value)))) +=C2=A0=C2=A0=C2=A0 (unless (or (not symbolized-value) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (eq? symbolized-value 'emacs) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 (eq? symbolized-value 'vim)) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (throw 'bad-emulation-made +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (format #f "Unrecognized emulation mode: ~s" value))) +=C2=A0=C2=A0=C2=A0 symbolized-value)) + +(define-record-type* +=C2=A0 editor-preferences make-editor-preferences +=C2=A0 editor-preferences? this-editor-preferences +=C2=A0 (username=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 editor-pr= eferences-username +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (innate) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (sanitize sanitize-username)) +=C2=A0 (background-color editor-preferences-background-color +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (default "000000")) +=C2=A0 (text-color=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 editor-preferences-= text-color +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (default "FFFFFF")) +=C2=A0 (emulation-mode=C2=A0=C2=A0 editor-preferences-emulation-mode +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (default #f) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (sanitize sanitize-emulation-= mode))) +@end lisp + +There are a couple of differences in the new @code{username} field=20 compared to +the fields we looked at earlier. It is marked as @code{innate}, which mean= s +that it will not be inherited. For example, consider what would happen=20 if we +tried to define new instances like this: + +@lisp +(define my-preferences +=C2=A0 (editor-preferences +=C2=A0=C2=A0=C2=A0 (username=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 "my-username") +=C2=A0=C2=A0=C2=A0 (background-color "222222") +=C2=A0=C2=A0=C2=A0 (emulation-mode=C2=A0=C2=A0 'vim))) + +(define friends-preferences +=C2=A0 (editor-preferences +=C2=A0=C2=A0=C2=A0 (inherit my-preferences) +=C2=A0=C2=A0=C2=A0 (emulation-mode 'emacs))) +@end lisp + +While the @code{friends-preferences} instance still inherits the values fo= r +@code{background-color} and @code{text-color}, it will not inherit the=20 value +for @code{username}. Furthermore, as the @code{username} field does not=20 define +a default value the attempted creation of @code{friends-preferences} will +actually throw an error. Instead, we could do this: + +@lisp +(define my-preferences +=C2=A0 (editor-preferences +=C2=A0=C2=A0=C2=A0 (username=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 "my-username") +=C2=A0=C2=A0=C2=A0 (background-color "222222") +=C2=A0=C2=A0=C2=A0 (emulation-mode=C2=A0=C2=A0 'vim))) + +(define friends-preferences +=C2=A0 (editor-preferences +=C2=A0=C2=A0=C2=A0 (inherit=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my-p= references) +=C2=A0=C2=A0=C2=A0 (username=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "friends-= username") +=C2=A0=C2=A0=C2=A0 (emulation-mode 'emacs))) +@end lisp + +@node @code{define-record-type*} Reference +@subsection @code{define-record-type*} Reference +@defmac define-record-type* name syntactic-constructor constructor=20 predicate this-identifier fields ... + +Define a new record type and associated helpers. + +@table @var +@item name +A symbol used to name the type, as would normally be provided to a plain +@code{define-record-type} form. For example, @code{}. + +@item syntactic-constructor +A symbol that will be used to define the user-facing constructor. For=20 example, +the symbol @code{package} is the syntactic constructor for the=20 @code{} +structure. + +@item constructor +A symbol that will be used to define the traditional constructor. It is=20 used in +the implementation of the syntactic constructor, but will not typically=20 be used +elsewhere. The traditional @code{make-name} (for example,=20 @code{make-package}) +is a fine value to use here. + +@item predicate +A symbol that will be used to test if a value is an instance of this=20 record. +For example, @code{package?}. + +@item this-identifier +This symbol can be used when defining fields that need to refer to the=20 struct +that contains them. For an example of this, see the @code{thunked} field +property, below. + +@item fields +A set of field specifiers which take the following form: + +@lisp +(field-name field-getter properties ...) +@end lisp + +Each of the properties must have one of the following forms: + +@table @code +@item (default @var{value}) +Defines the default value for the field, if the user does not specify=20 one using +the syntactic constructor. + +@item (innate) +Fields marked as innate will not be inherited from parent objects (see +Instantiating Records, below, for details of object inheritance). + +@item (sanitize @var{proc}) +The value given by the user will be passed into @var{proc} before being=20 stored +in the object. For example, consider this struct definition: + +@lisp +(define-record-type* thing make-thing +=C2=A0 thing? +=C2=A0 this-thing +=C2=A0 (name=C2=A0 thing-name +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (sanitize (lambda (value) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cond ((string? value) = value) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 ((symbol? value) (symbol->string value)) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 (else (throw 'bad! value))))))) +@end lisp + +When creating @code{thing} instances either a string or a symbol can be +supplied but it will always be stored as a string: + +@lisp +(string? (thing-name (thing (name "some-name")))) +@result{} #t +(string? (thing-name (thing (name 'some-name)))) +@result{} #t +(thing (name 1994)) +@result{} Throw to key `bad!' with args `(1994)'. +@end lisp + +@item (thunked) +Fields marked as @code{thunked} will actually compute the field's value=20 in the +current dynamic extent which is useful when referring to fluids in a=20 field's +value. Furthermore, that thunk can access the record it belongs to via the +@code{this-identifier}. For example: + +@lisp +(define-record-type* rectangle make-rectangle +=C2=A0 rectangle? +=C2=A0 this-rectangle +=C2=A0 (width=C2=A0 rectangle-width) +=C2=A0 (height rectangle-height) +=C2=A0 (area rectangle-area (thunked) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (default (*= (rectangle-width this-rectangle) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (rectangle-= height this-rectangle))))) + +(define base-rectangle +=C2=A0 (rectangle +=C2=A0=C2=A0=C2=A0 (width=C2=A0 2) +=C2=A0=C2=A0=C2=A0 (height 4))) + +(define derived-rectangle +=C2=A0 (rectangle +=C2=A0=C2=A0=C2=A0 (inherit base) +=C2=A0=C2=A0=C2=A0 (width=C2=A0=C2=A0 6))) + +(rectangle-area base-rectangle) +@result{} 8 + +(rectangle-area derived-rectangle +@result{} 24 +@end lisp + +@item (delayed) +Fields marked as @code{delayed} are similar to @code{thunked} fields,=20 except +that they are effectively wrapped in a @code{(delay @dots{})} form.=20 Note that +delayed fields cannot use @code{this-identifier}. +@end table +@end table +@end defmac + =C2=A0@node Invoking guix repl =C2=A0@section Invoking @command{guix repl} --=20 2.41.0