GNU bug report logs - #67786
[PATCH] doc: Add documentation for define-record-type*

Previous Next

Package: guix-patches;

Reported by: Skyler Ferris <skyvine <at> protonmail.com>

Date: Mon, 11 Dec 2023 20:18:02 UTC

Severity: minor

Tags: patch

Merged with 67787

To reply to this bug, email your comments to 67786 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Mon, 11 Dec 2023 20:18:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Skyler Ferris <skyvine <at> protonmail.com>:
New bug report received and forwarded. Copy sent to guix-patches <at> gnu.org. (Mon, 11 Dec 2023 20:18:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Skyler Ferris <skyvine <at> protonmail.com>
To: guix-patches <at> gnu.org
Cc: Skyler Ferris <skyvine <at> protonmail.com>
Subject: [PATCH] doc: Add documentation for define-record-type*
Date: Mon, 11 Dec 2023 12:16:40 -0800
* doc/guix.texi: Add sections describing the typical usage and API
reference for define-record-type*

Change-Id: I19e7220553d10652c794e6e0172b2c9ee961f54f
---
 doc/contributing.texi |   1 -
 doc/guix.texi         | 274 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 274 insertions(+), 1 deletion(-)

diff --git a/doc/contributing.texi b/doc/contributing.texi
index 9e9b89782c..60fcf95b77 100644
--- a/doc/contributing.texi
+++ b/doc/contributing.texi
@@ -1311,7 +1311,6 @@ Data Types and Pattern Matching
 notably the fact that it is hard to read, error-prone, and a hindrance
 to proper type error reports.
 
-@findex define-record-type*
 @findex match-record
 @cindex pattern matching
 Guix code should define appropriate data types (for instance, using
diff --git a/doc/guix.texi b/doc/guix.texi
index 1fd2e21608..e9d0fd1466 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -12561,6 +12561,280 @@ G-Expressions
 @code{(*approximate*)}, but this may change.
 @end deffn
 
+@node Records in Guix
+@section Records in Guix
+Guix uses @code{define-record-type*} to define structures with a lispy 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 '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)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+A user could then define their preferences like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (background-color "222222")
+    (emulation-mode   '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 @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 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 creating
+new ones. Continuing with the editor example, someone might want to base their
+preferences on their friend's preferences but customize a value:
+
+@lisp
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (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} to
+be @code{'emacs} instead of @code{'vim}.
+
+Sometimes it does not make sense for a field to be inherited. Suppose that the
+@code{<editor-preferences>} 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)
+  (unless (string? value)
+    (throw 'bad-username
+           (format #f "Usernames must be strings! Got: ~s" value)))
+  value)
+
+(define (sanitize-emulation-mode value)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (username         editor-preferences-username
+                    (innate)
+                    (sanitize sanitize-username))
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+There are a couple of differences in the new @code{username} field compared to
+the fields we looked at earlier. It is marked as @code{innate}, which means
+that it will not be inherited. For example, consider what would happen if we
+tried to define new instances like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (emulation-mode 'emacs)))
+@end lisp
+
+While the @code{friends-preferences} instance still inherits the values for
+@code{background-color} and @code{text-color}, it will not inherit the value
+for @code{username}. Furthermore, as the @code{username} field does not 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
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit        my-preferences)
+    (username       "friends-username")
+    (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 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{<package>}.
+
+@item syntactic-constructor
+A symbol that will be used to define the user-facing constructor. For example,
+the symbol @code{package} is the syntactic constructor for the @code{<package>}
+structure.
+
+@item constructor
+A symbol that will be used to define the traditional constructor. It is used in
+the implementation of the syntactic constructor, but will not typically be used
+elsewhere. The traditional @code{make-name} (for example, @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 record.
+For example, @code{package?}.
+
+@item this-identifier
+This symbol can be used when defining fields that need to refer to the 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 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 stored
+in the object. For example, consider this struct definition:
+
+@lisp
+(define-record-type* <thing> thing make-thing
+  thing?
+  this-thing
+  (name  thing-name
+         (sanitize (lambda (value)
+                     (cond ((string? value) value)
+                           ((symbol? value) (symbol->string value))
+                           (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 in the
+current dynamic extent which is useful when referring to fluids in a 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> rectangle make-rectangle
+  rectangle?
+  this-rectangle
+  (width  rectangle-width)
+  (height rectangle-height)
+  (area rectangle-area (thunked)
+                       (default (* (rectangle-width  this-rectangle)
+                                   (rectangle-height this-rectangle)))))
+
+(define base-rectangle
+  (rectangle
+    (width  2)
+    (height 4)))
+
+(define derived-rectangle
+  (rectangle
+    (inherit base)
+    (width   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, except
+that they are effectively wrapped in a @code{(delay @dots{})} form. Note that
+delayed fields cannot use @code{this-identifier}.
+@end table
+@end table
+@end defmac
+
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 

base-commit: 2b782f67266b42bb40015bd23ce2443be2f9b01f
-- 
2.41.0





Merged 67786 67787. Request was from Mathieu Othacehe <mathieu <at> meije.mail-host-address-is-not-set> to control <at> debbugs.gnu.org. (Mon, 25 Dec 2023 17:39:02 GMT) Full text and rfc822 format available.

Information forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Thu, 28 Dec 2023 00:31:02 GMT) Full text and rfc822 format available.

Message #10 received at 67786 <at> debbugs.gnu.org (full text, mbox):

From: Skyler Ferris <skyvine <at> protonmail.com>
To: 67786 <at> debbugs.gnu.org
Subject: Re: doc: Add documentation for define-record-type*
Date: Thu, 28 Dec 2023 00:29:43 +0000
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
---
# 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
# thunked. 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.
  doc/contributing.texi |   1 -
  doc/guix.texi         | 274 ++++++++++++++++++++++++++++++++++++++++++
  2 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
  notably the fact that it is hard to read, error-prone, and a hindrance
  to proper type error reports.

-@findex define-record-type*
  @findex match-record
  @cindex pattern matching
  Guix 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
  @code{(*approximate*)}, but this may change.
  @end deffn

+@node Records in Guix
+@section Records in Guix
+Guix uses @code{define-record-type*} to define structures with a lispy 
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 
'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)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+A user could then define their preferences like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (background-color "222222")
+    (emulation-mode   '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 
@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 
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 
creating
+new ones. Continuing with the editor example, someone might want to 
base their
+preferences on their friend's preferences but customize a value:
+
+@lisp
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (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} to
+be @code{'emacs} instead of @code{'vim}.
+
+Sometimes it does not make sense for a field to be inherited. Suppose 
that the
+@code{<editor-preferences>} 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)
+  (unless (string? value)
+    (throw 'bad-username
+           (format #f "Usernames must be strings! Got: ~s" value)))
+  value)
+
+(define (sanitize-emulation-mode value)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (username         editor-preferences-username
+                    (innate)
+                    (sanitize sanitize-username))
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+There are a couple of differences in the new @code{username} field 
compared to
+the fields we looked at earlier. It is marked as @code{innate}, which means
+that it will not be inherited. For example, consider what would happen 
if we
+tried to define new instances like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (emulation-mode 'emacs)))
+@end lisp
+
+While the @code{friends-preferences} instance still inherits the values for
+@code{background-color} and @code{text-color}, it will not inherit the 
value
+for @code{username}. Furthermore, as the @code{username} field does not 
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
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit        my-preferences)
+    (username       "friends-username")
+    (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 
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{<package>}.
+
+@item syntactic-constructor
+A symbol that will be used to define the user-facing constructor. For 
example,
+the symbol @code{package} is the syntactic constructor for the 
@code{<package>}
+structure.
+
+@item constructor
+A symbol that will be used to define the traditional constructor. It is 
used in
+the implementation of the syntactic constructor, but will not typically 
be used
+elsewhere. The traditional @code{make-name} (for example, 
@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 
record.
+For example, @code{package?}.
+
+@item this-identifier
+This symbol can be used when defining fields that need to refer to the 
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 
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 
stored
+in the object. For example, consider this struct definition:
+
+@lisp
+(define-record-type* <thing> thing make-thing
+  thing?
+  this-thing
+  (name  thing-name
+         (sanitize (lambda (value)
+                     (cond ((string? value) value)
+                           ((symbol? value) (symbol->string value))
+                           (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 
in the
+current dynamic extent which is useful when referring to fluids in a 
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> rectangle make-rectangle
+  rectangle?
+  this-rectangle
+  (width  rectangle-width)
+  (height rectangle-height)
+  (area rectangle-area (thunked)
+                       (default (* (rectangle-width this-rectangle)
+                                   (rectangle-height this-rectangle)))))
+
+(define base-rectangle
+  (rectangle
+    (width  2)
+    (height 4)))
+
+(define derived-rectangle
+  (rectangle
+    (inherit base)
+    (width   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, 
except
+that they are effectively wrapped in a @code{(delay @dots{})} form. 
Note that
+delayed fields cannot use @code{this-identifier}.
+@end table
+@end table
+@end defmac
+
  @node Invoking guix repl
  @section Invoking @command{guix repl}

-- 
2.41.0






Information forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Thu, 28 Dec 2023 01:24:02 GMT) Full text and rfc822 format available.

Message #13 received at 67786 <at> debbugs.gnu.org (full text, mbox):

From: Skyler Ferris <skyvine <at> protonmail.com>
To: 67786 <at> debbugs.gnu.org
Subject: Re: doc: Add documentation for define-record-type*
Date: Thu, 28 Dec 2023 01:23:21 +0000
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.
  doc/contributing.texi |   1 -
  doc/guix.texi         | 274 ++++++++++++++++++++++++++++++++++++++++++
  2 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
  notably the fact that it is hard to read, error-prone, and a hindrance
  to proper type error reports.

-@findex define-record-type*
  @findex match-record
  @cindex pattern matching
  Guix 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
  @code{(*approximate*)}, but this may change.
  @end deffn

+@node Records in Guix
+@section Records in Guix
+Guix uses @code{define-record-type*} to define structures with a lispy 
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 
'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)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+A user could then define their preferences like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (background-color "222222")
+    (emulation-mode   '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 
@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 
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 
creating
+new ones. Continuing with the editor example, someone might want to 
base their
+preferences on their friend's preferences but customize a value:
+
+@lisp
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (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} to
+be @code{'emacs} instead of @code{'vim}.
+
+Sometimes it does not make sense for a field to be inherited. Suppose 
that the
+@code{<editor-preferences>} 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)
+  (unless (string? value)
+    (throw 'bad-username
+           (format #f "Usernames must be strings! Got: ~s" value)))
+  value)
+
+(define (sanitize-emulation-mode value)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (username         editor-preferences-username
+                    (innate)
+                    (sanitize sanitize-username))
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+There are a couple of differences in the new @code{username} field 
compared to
+the fields we looked at earlier. It is marked as @code{innate}, which means
+that it will not be inherited. For example, consider what would happen 
if we
+tried to define new instances like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (emulation-mode 'emacs)))
+@end lisp
+
+While the @code{friends-preferences} instance still inherits the values for
+@code{background-color} and @code{text-color}, it will not inherit the 
value
+for @code{username}. Furthermore, as the @code{username} field does not 
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
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit        my-preferences)
+    (username       "friends-username")
+    (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 
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{<package>}.
+
+@item syntactic-constructor
+A symbol that will be used to define the user-facing constructor. For 
example,
+the symbol @code{package} is the syntactic constructor for the 
@code{<package>}
+structure.
+
+@item constructor
+A symbol that will be used to define the traditional constructor. It is 
used in
+the implementation of the syntactic constructor, but will not typically 
be used
+elsewhere. The traditional @code{make-name} (for example, 
@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 
record.
+For example, @code{package?}.
+
+@item this-identifier
+This symbol can be used when defining fields that need to refer to the 
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 
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 
stored
+in the object. For example, consider this struct definition:
+
+@lisp
+(define-record-type* <thing> thing make-thing
+  thing?
+  this-thing
+  (name  thing-name
+         (sanitize (lambda (value)
+                     (cond ((string? value) value)
+                           ((symbol? value) (symbol->string value))
+                           (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 
in the
+current dynamic extent which is useful when referring to fluids in a 
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> rectangle make-rectangle
+  rectangle?
+  this-rectangle
+  (width  rectangle-width)
+  (height rectangle-height)
+  (area rectangle-area (thunked)
+                       (default (* (rectangle-width this-rectangle)
+                                   (rectangle-height this-rectangle)))))
+
+(define base-rectangle
+  (rectangle
+    (width  2)
+    (height 4)))
+
+(define derived-rectangle
+  (rectangle
+    (inherit base)
+    (width   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, 
except
+that they are effectively wrapped in a @code{(delay @dots{})} form. 
Note that
+delayed fields cannot use @code{this-identifier}.
+@end table
+@end table
+@end defmac
+
  @node Invoking guix repl
  @section Invoking @command{guix repl}

-- 
2.41.0





Information forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Thu, 28 Dec 2023 02:05:02 GMT) Full text and rfc822 format available.

Message #16 received at 67786 <at> debbugs.gnu.org (full text, mbox):

From: Skyler Ferris <skyvine <at> protonmail.com>
To: 67786 <at> debbugs.gnu.org
Subject: Re: doc: Add documentation for define-record-type*
Date: Thu, 28 Dec 2023 02:03:56 +0000
It looks like the non-breaking space issue is still not resolved, and 
I'm not immediately seeing how to fix it. I'll look at it more later. My 
`git send-email` usage has been failing to deliver even though it worked 
for previous patches, so I tried pasting the email into Thuderbird to 
send it manually, but it seems like Thunderbird is stubborn about about 
modifying the contents of my email automatically. It will probably work 
best to fix the problem with `git send-email`.






Information forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Fri, 29 Dec 2023 00:13:02 GMT) Full text and rfc822 format available.

Message #19 received at 67786 <at> debbugs.gnu.org (full text, mbox):

From: Skyler Ferris <skyvine <at> protonmail.com>
To: 67786 <at> debbugs.gnu.org
Subject: Re: doc: Add documentation for define-record-type*
Date: Fri, 29 Dec 2023 00:12:01 +0000
Hello again,

I'm not sure if the problem is on my end. I reviewed the logs for the 
initial message I sent on December 11 and for the one I tried to send 
yesterday. In both cases, exim indicates that it connected to the 
appropriate endpoint, wrote a chunked message (BDAT), concluded with a 
line like "SMTP<< 250 2.0.0 Ok: <number> bytes queued as <id>", then 
closed the connection. The only difference is that when sending to 
guix-patches <at> gnu.org exim ended up talking to eggs.gnu.org, but when 
sending to this bug's email address it talked to debbugs.gnu.org. Is 
there someone I can talk to in order to help diagnose this issue?

Thanks,
Skyler





Information forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Fri, 29 Dec 2023 00:18:01 GMT) Full text and rfc822 format available.

Message #22 received at 67786 <at> debbugs.gnu.org (full text, mbox):

From: Skyler Ferris <skyvine <at> protonmail.com>
To: 67786 <at> debbugs.gnu.org
Subject: Re: doc: Add documentation for define-record-type*
Date: Fri, 29 Dec 2023 00:17:30 +0000
Oh, I see that there is a help-debbugs mailing list. I'll reach out there.





Information forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Sat, 13 Jan 2024 18:53:02 GMT) Full text and rfc822 format available.

Message #25 received at 67786 <at> debbugs.gnu.org (full text, mbox):

From: skyvine <at> protonmail.com
To: 67786 <at> debbugs.gnu.org
Cc: Skyler Ferris <skyvine <at> protonmail.com>
Subject: Re: doc: Add documentation for define-record-type*
Date: Sat, 13 Jan 2024 18:52:42 +0000
From: Skyler Ferris <skyvine <at> protonmail.com>

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
---
# 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.
 doc/contributing.texi |   1 -
 doc/guix.texi         | 274 ++++++++++++++++++++++++++++++++++++++++++
 2 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
 notably the fact that it is hard to read, error-prone, and a hindrance
 to proper type error reports.
 
-@findex define-record-type*
 @findex match-record
 @cindex pattern matching
 Guix 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
 @code{(*approximate*)}, but this may change.
 @end deffn
 
+@node Records in Guix
+@section Records in Guix
+Guix uses @code{define-record-type*} to define structures with a lispy 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 '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)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+A user could then define their preferences like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (background-color "222222")
+    (emulation-mode   '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 @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 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 creating
+new ones. Continuing with the editor example, someone might want to base their
+preferences on their friend's preferences but customize a value:
+
+@lisp
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (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} to
+be @code{'emacs} instead of @code{'vim}.
+
+Sometimes it does not make sense for a field to be inherited. Suppose that the
+@code{<editor-preferences>} 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)
+  (unless (string? value)
+    (throw 'bad-username
+           (format #f "Usernames must be strings! Got: ~s" value)))
+  value)
+
+(define (sanitize-emulation-mode value)
+  (let ((symbolized-value (cond ((not value)     #f)
+                                ((string? value) (string->symbol value))
+                                (#t              value))))
+    (unless (or (not symbolized-value)
+                (eq? symbolized-value 'emacs)
+                (eq? symbolized-value 'vim))
+      (throw 'bad-emulation-made
+             (format #f "Unrecognized emulation mode: ~s" value)))
+    symbolized-value))
+
+(define-record-type*
+  <editor-preferences> editor-preferences make-editor-preferences
+  editor-preferences? this-editor-preferences
+  (username         editor-preferences-username
+                    (innate)
+                    (sanitize sanitize-username))
+  (background-color editor-preferences-background-color
+                    (default "000000"))
+  (text-color       editor-preferences-text-color
+                    (default "FFFFFF"))
+  (emulation-mode   editor-preferences-emulation-mode
+                    (default #f)
+                    (sanitize sanitize-emulation-mode)))
+@end lisp
+
+There are a couple of differences in the new @code{username} field compared to
+the fields we looked at earlier. It is marked as @code{innate}, which means
+that it will not be inherited. For example, consider what would happen if we
+tried to define new instances like this:
+
+@lisp
+(define my-preferences
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit my-preferences)
+    (emulation-mode 'emacs)))
+@end lisp
+
+While the @code{friends-preferences} instance still inherits the values for
+@code{background-color} and @code{text-color}, it will not inherit the value
+for @code{username}. Furthermore, as the @code{username} field does not 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
+  (editor-preferences
+    (username         "my-username")
+    (background-color "222222")
+    (emulation-mode   'vim)))
+
+(define friends-preferences
+  (editor-preferences
+    (inherit        my-preferences)
+    (username       "friends-username")
+    (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 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{<package>}.
+
+@item syntactic-constructor
+A symbol that will be used to define the user-facing constructor. For example,
+the symbol @code{package} is the syntactic constructor for the @code{<package>}
+structure.
+
+@item constructor
+A symbol that will be used to define the traditional constructor. It is used in
+the implementation of the syntactic constructor, but will not typically be used
+elsewhere. The traditional @code{make-name} (for example, @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 record.
+For example, @code{package?}.
+
+@item this-identifier
+This symbol can be used when defining fields that need to refer to the 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 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 stored
+in the object. For example, consider this struct definition:
+
+@lisp
+(define-record-type* <thing> thing make-thing
+  thing?
+  this-thing
+  (name  thing-name
+         (sanitize (lambda (value)
+                     (cond ((string? value) value)
+                           ((symbol? value) (symbol->string value))
+                           (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 in the
+current dynamic extent which is useful when referring to fluids in a 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> rectangle make-rectangle
+  rectangle?
+  this-rectangle
+  (width  rectangle-width)
+  (height rectangle-height)
+  (area rectangle-area (thunked)
+                       (default (* (rectangle-width  this-rectangle)
+                                   (rectangle-height this-rectangle)))))
+
+(define base-rectangle
+  (rectangle
+    (width  2)
+    (height 4)))
+
+(define derived-rectangle
+  (rectangle
+    (inherit base)
+    (width   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, except
+that they are effectively wrapped in a @code{(delay @dots{})} form. Note that
+delayed fields cannot use @code{this-identifier}.
+@end table
+@end table
+@end defmac
+
 @node Invoking guix repl
 @section Invoking @command{guix repl}
 
-- 
2.41.0






Information forwarded to guix-patches <at> gnu.org:
bug#67786; Package guix-patches. (Sat, 13 Jan 2024 18:58:01 GMT) Full text and rfc822 format available.

Message #28 received at 67786 <at> debbugs.gnu.org (full text, mbox):

From: Skyler Ferris <skyvine <at> protonmail.com>
To: 67786 <at> debbugs.gnu.org
Subject: Re: doc: Add documentation for define-record-type*
Date: Sat, 13 Jan 2024 18:57:30 +0000
Looks like it worked this time! I updated my configuration to send the 
mail through my provider's servers instead of running exim locally.





This bug report was last modified 1 year and 158 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.