Subject: Re: bug#51383: noobie way of incorrectly using (guix records)

From: Joshua Branson <[email-masked]>
Date: Mon, 25 Oct 2021 05:36:39 -0400

zimoun <[email-masked]> writes:

> Hi,
>
> On Mon, 25 Oct 2021 at 02:15, Joshua Branson via Bug reports for GNU Guix <[email-masked]> wrote:
>
>> So I made a pretty noobie-like mistake a few minutes ago.  When one
>> tries to make a (record-configuration), he invariably create an
>> infinite number of records.  The guile compiler eventually runs out
>> of memory and stops compiling.
>>
>> (use-modules (guix records))
>>
>> (define-record-type* <record-configuration>
>>   record-configuration make-record-configuration
>>   record-configuration?
>>   (command record-configuration-command
>>            ;; the error is here is on the next line
>>            (default (record-configuration))))  
>>
>> (record-configuration)
>
> This <record-configuration> is defined by creating recursively another
> instance.  Thus, It is expected that it does not work, no?

Yes that is correct.  I am only slightly annoyed at the lack of a
helpful error message.  Thanks for helping me clarify my point.  I was
working on a rather large collection of guix records for an opensmtpd
service configuration.  The file is about 1,000 lines long.  Trying to
find that error without a helpful error message was slightly annoying.

I agree that the fault was mine and I do not believe the bug can be
fixed.  Rather it would be nice to have a more helpful error message.

It could be possible that guile offers such flexibility in general that
the compiler is unable to provide good error messages in all situations.
I am just hoping for a better error message somewhere, ether in the
compiler or something in the (define-syntax-record* macro.  Is it
possible to get a better error message?  Is that a thing worth pursuing?
Or is the fix worse than the present condition?

> Reading the doc,
>
>   1. what do you want to achieve?
>   2. what does it appear to you buggy?  Or what do you think the
>      “correct” behaviour should be?
>
> (define-syntax define-record-type*
>   (lambda (s)
>     "Define the given record type such that an additional \"syntactic
> constructor\" is defined, which allows instances to be constructed with named
> field initializers, à la SRFI-35, as well as default values.  An example use
> may look like this:
>
>   (define-record-type* <thing> thing make-thing
>     thing?
>     this-thing
>     (name  thing-name (default \"chbouib\"))
>     (port  thing-port
>            (default (current-output-port)) (thunked))
>     (loc   thing-location (innate) (default (current-source-location))))
>
> This example defines a macro 'thing' that can be used to instantiate records
> of this type:
>
>   (thing
>     (name \"foo\")
>     (port (current-error-port)))
>
> The value of 'name' or 'port' could as well be omitted, in which case the
> default value specified in the 'define-record-type*' form is used:
>
>   (thing)
>
> The 'port' field is \"thunked\", meaning that calls like '(thing-port x)' 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 'this-thing' identifier.
>
> A field can also be marked as \"delayed\" instead of \"thunked\", in which
> case its value is effectively wrapped in a (delay …) form.
>
> A field can also have an associated \"sanitizer\", which is a procedure that
> takes a user-supplied field value and returns a \"sanitized\" value for the
> field:
>
>   (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)))))))
>
> It is possible to copy an object 'x' created with 'thing' like this:
>
>   (thing (inherit x) (name \"bar\"))
>
> This expression returns a new object equal to 'x' except for its 'name'
> field and its 'loc' field---the latter is marked as \"innate\", so it is not
> inherited."
>
>
> (Argh, I do not know how to read/display the docstring from the REPL,
> another annoying* story. :-))

Do you know if the above guix records are in the guix manual?  If not,
I'll probably add them.

>
>> This is not possible with (srfi sfri-9)
>>
>> (use-modules (srfi srfi-9))
>>
>> (define-record-type <employee>
>>   (make-employee name age (make-employeee 5 5 5))
>>   employee?
>>   (name    employee-name)
>>   (age     employee-age    set-employee-age!)
>>   (salary  employee-salary set-employee-salary!))
>
> Well, ’(guix records)’ allows to do more than ’(srfi srfi-9)’.

Amen for that!  (guix records) are awesome!

> Aside, I
> am not convinced that this latter snippet is similar than the former
> previous one.

I was just trying to see if I could produce a similar issue for the
guile compiler via only using (srfi srfi-9).  Apparently I cannot.

> Cheers,
> simon
>
> *annoying REPL, I get:
>
> scheme@(guix-user)> ,describe define-record-type*
> While executing meta-command:
> Syntax error:
> unknown file:79:10: source expression failed to match any pattern in form define-record-type*

try

(use-modules (guix records))...though you probably already did that.

What about

,m (guix records)  ?

-- 
Joshua Branson (jab in #guix)
Sent from Emacs and Gnus
  https://gnucode.me
  https://video.hardlimit.com/accounts/joshua_branson/video-channels
  https://propernaming.org
  "You can have whatever you want, as long as you help
enough other people get what they want." - Zig Ziglar