unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* srfi-9 vs make-record-type
@ 2019-07-21 10:20 Christopher Lam
  2019-07-21 19:21 ` John Cowan
  2019-08-05 18:18 ` Mark H Weaver
  0 siblings, 2 replies; 5+ messages in thread
From: Christopher Lam @ 2019-07-21 10:20 UTC (permalink / raw)
  To: guile-user

Hi All
In experiments converting legacy code to use srfi-9 records, I'm finding
the latter doesn't travel well across modules.

See simple code below -- m1.scm runs fine however m2.scm borks when
creating srfi-9 record object

Any clue why srfi-9 can't be exported?

For various reasons I must keep (load "module.scm") mechanism
----m1.scm follows----
(use-modules (srfi srfi-9))

(define-record-type <person>
  (make-person name age)
  person?
  (name person-name set-person-name!)
  (age person-age set-person-age!))

(define <pet> (make-record-type "pet" '(name age)))
(define make-pet (record-constructor <pet>))
(define pet? (record-predicate <pet>))
(define pet-name (record-accessor <pet> 'name))
(define pet-age (record-accessor <pet> 'age))
(define set-pet-name! (record-modifier <pet> 'name))
(define set-pet-age! (record-modifier <pet> 'age))
(export make-person)
(export make-pet)

(display "pet ")
(let ((pet2 (make-pet "milou" 7)))
  (display (pet-name pet2)))
(display ", person ")
(let ((person2 (make-person "james" 54)))
  (display (person-name person2)))
(newline)
----m2.scm follows----
(load "m1.scm")
(display "in m2:")
(newline)
(display "pet ")
(let ((pet2 (make-pet "milou" 7)))
  (display (pet-name pet2)))
(display ", person ")
(let ((person2 (make-person "james" 54)))
  (display (person-name person2)))
(newline)
--------------------------------
$guile m1.scm runs successfully

pet milou, person james

$guile m2.scm first runs m1.scm but fails to recognise the srfi-9
make-person exists:
pet milou, person james
in m2:
pet milou, person Backtrace:
           6 (apply-smob/1 #<catch-closure 5599248723e0>)
In ice-9/boot-9.scm:
    705:2  5 (call-with-prompt _ _ #<procedure default-prompt-handle…>)
In ice-9/eval.scm:
    619:8  4 (_ #(#(#<directory (guile-user) 559924904140>)))
In ice-9/boot-9.scm:
   2312:4  3 (save-module-excursion _)
  3831:12  2 (_)
In /home/chris/sources/caca/m2.scm:
     8:15  1 (_)
In unknown file:
           0 (_ "james" 54)

ERROR: Wrong type to apply: #<syntax-transformer make-person>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: srfi-9 vs make-record-type
  2019-07-21 10:20 srfi-9 vs make-record-type Christopher Lam
@ 2019-07-21 19:21 ` John Cowan
  2019-08-05 18:18 ` Mark H Weaver
  1 sibling, 0 replies; 5+ messages in thread
From: John Cowan @ 2019-07-21 19:21 UTC (permalink / raw)
  To: Christopher Lam; +Cc: guile-user

On Sun, Jul 21, 2019 at 6:21 AM Christopher Lam <christopher.lck@gmail.com>
wrote

In experiments converting legacy code to use srfi-9 records, I'm finding
> the latter doesn't travel well across modules.
>

In SRFI 9 you need to define a record type in exactly one module and then
export whatever subset of the constructor, predicate, accessors, and
mutators (not typically the record type name) that you want to make
visible.  Other modules can then import those names.  This is because calls
on define-record-type are generative (SRFI 9 doesn't say so, but in
practice they are), so a particular record type should be defined only once.

In my code, I often export the predicate and accessors, but not the
constructor or mutators.  Then I export a factory method that may or may
not call the constructor.

It may be convenient to define the record-type in its own module.


John Cowan          http://vrici.lojban.org/~cowan        cowan@ccil.org
Promises become binding when there is a meeting of the minds and
consideration
is exchanged. So it was at King's Bench in common law England; so it was
under the common law in the American colonies; so it was through more than
two centuries of jurisprudence in this country; and so it is today.
       --Specht v. Netscape


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: srfi-9 vs make-record-type
  2019-07-21 10:20 srfi-9 vs make-record-type Christopher Lam
  2019-07-21 19:21 ` John Cowan
@ 2019-08-05 18:18 ` Mark H Weaver
  2019-08-26 12:20   ` Christopher Lam
  1 sibling, 1 reply; 5+ messages in thread
From: Mark H Weaver @ 2019-08-05 18:18 UTC (permalink / raw)
  To: Christopher Lam; +Cc: guile-user

Hi Christopher,

Christopher Lam <christopher.lck@gmail.com> writes:

> Hi All
> In experiments converting legacy code to use srfi-9 records, I'm finding
> the latter doesn't travel well across modules.
>
> See simple code below -- m1.scm runs fine however m2.scm borks when
> creating srfi-9 record object
>
> Any clue why srfi-9 can't be exported?
>
> For various reasons I must keep (load "module.scm") mechanism
> ----m1.scm follows----
> (use-modules (srfi srfi-9))
>
> (define-record-type <person>
>   (make-person name age)
>   person?
>   (name person-name set-person-name!)
>   (age person-age set-person-age!))
>
> (define <pet> (make-record-type "pet" '(name age)))
> (define make-pet (record-constructor <pet>))
> (define pet? (record-predicate <pet>))
> (define pet-name (record-accessor <pet> 'name))
> (define pet-age (record-accessor <pet> 'age))
> (define set-pet-name! (record-modifier <pet> 'name))
> (define set-pet-age! (record-modifier <pet> 'age))
> (export make-person)
> (export make-pet)
>
> (display "pet ")
> (let ((pet2 (make-pet "milou" 7)))
>   (display (pet-name pet2)))
> (display ", person ")
> (let ((person2 (make-person "james" 54)))
>   (display (person-name person2)))
> (newline)
> ----m2.scm follows----
> (load "m1.scm")
> (display "in m2:")
> (newline)
> (display "pet ")
> (let ((pet2 (make-pet "milou" 7)))
>   (display (pet-name pet2)))
> (display ", person ")
> (let ((person2 (make-person "james" 54)))
>   (display (person-name person2)))
> (newline)
> --------------------------------
> $guile m1.scm runs successfully
>
> pet milou, person james
>
> $guile m2.scm first runs m1.scm but fails to recognise the srfi-9
> make-person exists:
> pet milou, person james
> in m2:
> pet milou, person Backtrace:
>            6 (apply-smob/1 #<catch-closure 5599248723e0>)
> In ice-9/boot-9.scm:
>     705:2  5 (call-with-prompt _ _ #<procedure default-prompt-handle…>)
> In ice-9/eval.scm:
>     619:8  4 (_ #(#(#<directory (guile-user) 559924904140>)))
> In ice-9/boot-9.scm:
>    2312:4  3 (save-module-excursion _)
>   3831:12  2 (_)
> In /home/chris/sources/caca/m2.scm:
>      8:15  1 (_)
> In unknown file:
>            0 (_ "james" 54)
>
> ERROR: Wrong type to apply: #<syntax-transformer make-person>

The problem here is that 'make-person' is a macro.  Macros are expanded
at compile time, and must therefore be available at compile time.

When you compile 'm2.scm', those macros are not available, because
'load' only has effects at run-time, by design.  Since there is no macro
definition for 'make-person' at compile-time, Guile's compiler generates
code that assumes it will be a procedure.

In summary, you cannot use 'load' to import macros from another module.

> For various reasons I must keep (load "module.scm") mechanism

If you can share those reasons, perhaps I can help you find another
solution.

      Regards,
        Mark



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: srfi-9 vs make-record-type
  2019-08-05 18:18 ` Mark H Weaver
@ 2019-08-26 12:20   ` Christopher Lam
  2020-07-13 13:07     ` Christopher Lam
  0 siblings, 1 reply; 5+ messages in thread
From: Christopher Lam @ 2019-08-26 12:20 UTC (permalink / raw)
  Cc: guile-user

Thank you Mark and John.

On Mon, 5 Aug 2019 at 18:18, Mark H Weaver <mhw@netris.org> wrote:

> The problem here is that 'make-person' is a macro.  Macros are expanded
> at compile time, and must therefore be available at compile time.
>
> When you compile 'm2.scm', those macros are not available, because
> 'load' only has effects at run-time, by design.  Since there is no macro
> definition for 'make-person' at compile-time, Guile's compiler generates
> code that assumes it will be a procedure.
>
> In summary, you cannot use 'load' to import macros from another module.
>
> > For various reasons I must keep (load "module.scm") mechanism
> If you can share those reasons, perhaps I can help you find another
> solution.
>

The only reason is that I've started cleaning up numerous modules in
GnuCash written about 20 years ago, and the hyper-modular approach is too
difficult to try unravel for now. So, I've converted records to srfi-9
wherever possible (i.e. used internally), and left the exported ones alone.
This one was a fun one to fix:
https://github.com/Gnucash/gnucash/commit/e3a695d0 ;-)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: srfi-9 vs make-record-type
  2019-08-26 12:20   ` Christopher Lam
@ 2020-07-13 13:07     ` Christopher Lam
  0 siblings, 0 replies; 5+ messages in thread
From: Christopher Lam @ 2020-07-13 13:07 UTC (permalink / raw)
  Cc: guile-user

Followup.
As part of preparation for compatibility with guile-3, we've changed
gnucash's use of make-record-type to define-record-type.
Since the record field getters and setters are not exportable across
modules, we've used the following forms.

(define-record-type :record
 (make-record field1 field2)
 record?
 (field1 field1-getter field1-setter)
 (field2 field2-getter field2-setter))
(define-public gnc:field1-getter field1-getter)
(define-public gnc:field1-setter field1-setter)
(define-public gnc:field2-getter field2-getter)
(define-public gnc:field2-setter field2-setter)

There may be a more elegant solution but for now it'll do. See the set of
related commits at
https://github.com/Gnucash/gnucash/commits?after=00bbd32677fba00ae0e709dce0bb35e06f90305c+4
onwards.

On Mon, 26 Aug 2019 at 12:20, Christopher Lam <christopher.lck@gmail.com>
wrote:

> Thank you Mark and John.
>
> On Mon, 5 Aug 2019 at 18:18, Mark H Weaver <mhw@netris.org> wrote:
>
>> The problem here is that 'make-person' is a macro.  Macros are expanded
>> at compile time, and must therefore be available at compile time.
>>
>> When you compile 'm2.scm', those macros are not available, because
>> 'load' only has effects at run-time, by design.  Since there is no macro
>> definition for 'make-person' at compile-time, Guile's compiler generates
>> code that assumes it will be a procedure.
>>
>> In summary, you cannot use 'load' to import macros from another module.
>>
>> > For various reasons I must keep (load "module.scm") mechanism
>> If you can share those reasons, perhaps I can help you find another
>> solution.
>>
>
> The only reason is that I've started cleaning up numerous modules in
> GnuCash written about 20 years ago, and the hyper-modular approach is too
> difficult to try unravel for now. So, I've converted records to srfi-9
> wherever possible (i.e. used internally), and left the exported ones alone.
> This one was a fun one to fix:
> https://github.com/Gnucash/gnucash/commit/e3a695d0 ;-)
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-07-13 13:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-21 10:20 srfi-9 vs make-record-type Christopher Lam
2019-07-21 19:21 ` John Cowan
2019-08-05 18:18 ` Mark H Weaver
2019-08-26 12:20   ` Christopher Lam
2020-07-13 13:07     ` Christopher Lam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).