Ludovic Courtès <[email protected]> writes:

> Hello!
>
> Tomas Volf <[email protected]> skribis:
>
>> after a pull, seeing the news, and subsequent rollback I went on
>> exploring how the new feature of the record system works.  It seems to
>> work just for some fields (e.g., I can use it with inputs, but not with
>> version), which is quite confusing.  Additionally, it does not seem to
>> allow cross-references (e.g., I cannot use inputs in propagated-inputs).
>
> It works for thunked fields only, just like self references such as
> ‘this-package’.  (For reference, this was discussed at
> <https://codeberg.org/guix/guix/pulls/6955>.)

I see, I did not understood this from the news entry.  That decreases
blast radius significantly, but it still is somewhat frustrating, since
thunk-ness of fields does not even seem to be documented?  So one has to
always check the define-record-type to see what identifier are safe to
use when inheriting.  That is not a great UX.

Hm, and when I stop/start inhering, the set of safe identifiers changes,
because this binding is injected only when inheriting, correct?

>
>> However the reason I am writing this email is this part from the news:
>>
>>> the newly introduced bindings could shadow same-named bindings
>>
>> which sounds quite annoying to deal with.  Does this basically mean that
>> adding new field to any record in Guix can break arbitrary user code?
>
> The only risk is if you were doing:
>
>   (define (foo inputs)
>     (package
>       (inherit xyz)
>       ;; …
>       (inputs (do-something inputs))))
>
> Previously the ‘inputs’ in the ‘inputs’ field body would refer to the
> outer ‘inputs’; now it refers to the inherited field value.
>
> It’s a very narrow case.  In the entire code base, I found two
> occurrences of this.

I inspected my configurations and my channel, and I *think* I have no
occurrences, but hard to say, lot of define-record-type's to look
through.  ¯\_(ツ)_/¯

It seems I mostly have "conflict" with `version', which is not a problem
(at least for now).

>
>> For now, I will spend the weekend checking that all my code does not
>> have any naming conflict, but I am not sure what to do next.  Especially
>> given the fact that there is no warning when the shadowing occurs.
>>
>> I assume committers will ensure that no record will have fields that are
>> named the same way as any built-in procedure (and possibly some
>> hand-picked SRFIs and ICE-9s?), but in what matter shall I write my own
>> code?  Is there some reserved prefix, I can be sure no record will ever
>> used for its fields?  How should I future-proof my code?
>
> You’re raising good points.  I think name clashes today are unlikely (in
> Guix itself we’d discover them not with warnings but with tests and CI
> for packages).
>
> Also, shadowing builtins is not a completely new thing.  When you do:
>
>   (package
>     ;; …
>     (version "1.2.3")
>     (source (… (string-append … version ".tar.gz"))))
>
> … the ‘version’ in the body of ‘source’ is the one just above, not
> Guile’s builtin ‘version’ procedure.  The extra shadowing (only when
> inheriting, only in thunked fields) doesn’t fundamentally change this.

True, and I am not fan even of this part of Guix's records.  Though
until now, all shadowing was happening explicitly on the screen.  Now,
whether something is shadowed changes whenever the thunk-ness changes,
without it being visible in my code.  I fully admit I do not like that.

>
> Could you try your config/channels/code with this new feature and see if
> you stumble upon any issue?

I am building right now, and will see whether everything works.

>
> Thanks for your feedback!

I admit I do not like this feature, it feels way too magical and way too
unpredictable.

  (let ((version "1"))
    (package
      (inherit foo)
      (version version)))

What will package-version give me?  "1" or (package-version foo)?  There
is no way to know, based on the source code nor the documentation.  I
have to dig into guix/packages.scm and consult the record definition.
And hope no one will change it in the future. ¯\_(ツ)_/¯

And I have to do this for every single record type I am using.  Quick,
is guix-configuration-guix thunked or not?  Well, I assume you do know
the answer, but I had to check.  And I will have to check again after
next pull. :(

Tomas

PS:

Out of curiosity, was it ever considered to do away with the whole
(thunked) concept, and instead switch to explicit procedures taking the
record instance?  I admit that

    (package
      ...
      (inputs (const (list ...))))

    (package
      ...
      (inputs (λ (pkg) (list ...))))

    (package
      ...
      (inputs (modify-inputs-lambda (delete "foo"))))

is slightly more verbose, but also significantly less magical.

-- 
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.

Reply via email to