I recently wrote something like the following buggy code:
(define-json-mapping <project-info> make-project-info project-info?
json->project-info
(license project-info-license
(lambda (x)
(if (string? x)
(spdx-string->license x)
#f))))
and was confused to find that project-info-license always produced *unspecified*.
Eventually, I worked out that I needed instead to write:
(define-json-mapping <project-info> make-project-info project-info?
json->project-info
(license project-info-license
"license" (lambda (x)
(if (string? x)
(spdx-string->license x)
#f))))
i.e. that writing "license" was required even though it matched license.
Originally, I had read the grammar at:
|
- *((field getter ...) ...)* : a series of field specifications. |
|
|
|
- *field* : the name of a JSON object field. |
|
|
|
- *getter* : the name of the procedure to get the value of this field |
|
given a record of this type. |
|
|
|
- *key* : a different name for the field of this JSON object. If given, this |
|
name will be used instead of the field name when serializing or |
|
deserializing. |
|
|
|
- *scm->value* : an optional procedure that will be used to convert native |
|
values supported by guile-json to the value contained in the record. Used |
|
when reading JSON. |
|
|
|
- *value->scm* : an optional procedure that will be used to convert the |
|
value contained in the record to a native value supported by guile-json |
|
Used when writing JSON. |
to mean the field and getter subforms were required, but the key, scm->value, and value->scm subforms were optional, so I thought I would only need to specify key if it were different than field. However, it seems like what I intended as a scm->value expression was being treated as a key, and of course there would never be a key equal? to that procedure, so I ended up with *unspecified* and no scm->value procedure to convert it.
I can see a few possible improvements, depending on what behavior is preferred:
-
If you want key to be optional in the way I originally imagined:
-
The expansion of define-json-mapping could check at run-time if the first of the optional sub-forms evaluates to a string and treat it as key if so; scm->value otherwise.
-
If key is restricted to a string literal, rather than an expression that evaluates to a string, define-json-mapping could perform such a check at compile-time.
-
If you want key to be required in order to provide scm->value, I think define-json-mapping should still check, either at run-time or compile-time, that key actually is/evaluates to a string, since supplying a procedure for key would never be a reasonable thing to do.
I recently wrote something like the following buggy code:
(define-json-mapping <project-info> make-project-info project-info? json->project-info (license project-info-license (lambda (x) (if (string? x) (spdx-string->license x) #f))))and was confused to find that
project-info-licensealways produced*unspecified*.Eventually, I worked out that I needed instead to write:
(define-json-mapping <project-info> make-project-info project-info? json->project-info (license project-info-license "license" (lambda (x) (if (string? x) (spdx-string->license x) #f))))i.e. that writing
"license"was required even though it matchedlicense.Originally, I had read the grammar at:
guile-json/README.md
Lines 331 to 348 in 81bc5da
to mean the
fieldandgettersubforms were required, but thekey,scm->value, andvalue->scmsubforms were optional, so I thought I would only need to specifykeyif it were different thanfield. However, it seems like what I intended as ascm->valueexpression was being treated as akey, and of course there would never be a keyequal?to that procedure, so I ended up with*unspecified*and noscm->valueprocedure to convert it.I can see a few possible improvements, depending on what behavior is preferred:
If you want
keyto be optional in the way I originally imagined:The expansion of
define-json-mappingcould check at run-time if the first of the optional sub-forms evaluates to a string and treat it askeyif so;scm->valueotherwise.If
keyis restricted to a string literal, rather than an expression that evaluates to a string,define-json-mappingcould perform such a check at compile-time.If you want
keyto be required in order to providescm->value, I thinkdefine-json-mappingshould still check, either at run-time or compile-time, thatkeyactually is/evaluates to a string, since supplying a procedure forkeywould never be a reasonable thing to do.