[plt-scheme] prefab structure types (3.99.0.18)

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Thu Mar 13 17:08:41 EDT 2008

Version 3.99.0.18 adds "prefab" (i.e., "previously fabricated")
structure types for non-abstract, easily serialized structures.

A prefab structure type is a built-in type that is distinct from all
other types, but that `read' and `write' know about. So, you can write
a prefab structure as a literal:

 > '#s(sprout bean #t 17)
 #s(sprout bean #t 17)

The "#s" notation means "prefab structure", `sprout' is the name of the
structure type, and 'bean, #t, and 17 are the values of the structure's
fields.

A prefab structure datum is self-quoting:

 > #s(sprout bean #t 17)
 #s(sprout bean #t 17)


A prefab structure type is keyed mainly on its symbolic name and field
count. So,

  #s(sprout bean)

is an instance of a different prefab structure type --- also named
'sprout, but with a single field instead of three fields.


If you use `define-struct' with the new #:prefab keyword, then instead
of generating a new type, it binds to the prefab structure type with
the same name and field count:

  > (define s1 #s(sprout bean))
  > (define-struct sprout (kind) #:prefab)
  > (sprout? s1)
  #t
  > (sprout-kind s1)
  bean
  > (sprout-kind #s(sprout alfalfa))
  alfalfa
  > (make-sprout 'alfalfa)
  #s(sprout alfalfa))
  > (sprout? #s(cat "Garfield"))
  #f
  > (sprout? #s(sprout bean #t 17)) ; three fields instead of one
  #f


A prefab structure type is similar to an R6RS nongenerative record
type. One difference is that a generative record type might be defined
multiple times in incompatible ways, in which case something has to
notice and signal an error. By keying a prefab structure type on all of
its attributes, there is no possibility for incompatible definitions,
and so no question of when/how an error might be signaled. There's also
no need to declare a prefab structure type before it can be recognized
by the reader or printer.


If a prefab structure type has a supertype (which must also be a prefab
type) or if it has mutable or automatic fields, then the prefab key
gets more complex:

  > (define-struct cat (name) #:prefab)
  > (define-struct (cute-cat cat) ([shipping-dest #:mutable]) #:prefab)
  > (make-cute-cat "Nermel" "Abu Dahbi")
  #s((cute-cat #(0) cat 1) "Nermel" "Abu Dahbi")

The reference manual documents the prefab key format. It's designed to
be easy to read and write in simple cases, but complete enough to cover
more complicated structure types.

You're not allowed to write a literal that is mutable, so

  #s((cute-cat #(0) cat 1) "Nermel" "Abu Dahbi")

is not a valid expression. Nevertheless, `read' can parse it and
create a mutable instance, in much the same way that `read' can
produce a mutable vector.


Every prefab structure type is transparent --- but even less abstract
than a transparent type, because instances can be created without any
access to a particular structure-type declaration or existing examples.
Overall, the different options for structure types offer a spectrum of
possibilities from more abstract to more convenient:

  * Opaque (the default) : Instances cannot be inspected or forged
       without access to the structure-type declaration. Constructor
       guards and properties can be attached to the structure type to
       further protect or to specialize the behavior of its instances.

  * Transparent : Anyone can inspect or create an instance without
       access to the structure-type declaration, which means that the
       value printer can show the content of an instance. All instance
       creation passes through a constructor guard, however, so that
       the content of an instance can be controlled, and the behavior
       of instances can be specialized through properties. Since the
       structure type is generated by its definition, instances cannot
       be manufactured simply through the name of the structure type,
       and therefore cannot be generated automatically by the
       expression reader.

 * Prefab : Anyone can inspect or create an instance at any time,
       without prior access to a structure-type declaration or an
       example instance. Consequently, the expression reader can
       manufacture instances directly. The instance cannot have a
       constructor guard or properties.

Since the expression reader can generate prefab instances, they are
useful when convenient serialization is more important than
abstraction. The `define-serializable-struct' form is still available
to support serialization of opaque and transparent structures.


Assuming that prefab structures turn out to be a good idea, it will
probably take a little while for us to get prefab support everywhere
you'd like, such as in `match'. The `quasiquote' form, syntax patterns,
and syntax templates already support them.


After next build, you can find more information here:

 http://docs.plt-scheme.org/guide/define-struct.html
 http://docs.plt-scheme.org/reference/structures.html

but I've copied or paraphrased above much of the guide material.


Matthew



Posted on the users mailing list.