From: Eric Eide
Subject: Mutually Referential DEFSTRUCT Slot Types: How?
Date: 
Message-ID: <EEIDE.92Aug12120727@asylum.cs.utah.edu>
I would like to write something like the following in Common Lisp:

  (defstruct a
    (slot nil :type b))

  (defstruct b
    (slot nil :type a))

How can I do this?  From my reading of CLtL2, B does not become a valid type
specifier until the (DEFSTRUCT B ...) form is evaluated, so I can't say that
an A's slot is of type B.  I suppose I might change the first DEFTSTRUCT to

  (defstruct a
    (slot nil :type (satisfies b-p)))

but I think that this type specifier would not give my compiler enough
information to allow it to opencode my structure accessors.  Speed is important
in my application, but probably not critically so.

Second, how can I create an instance of either of these objects, while keeping
the declared types accurate?

My current plan is to forgo the type declaration of A's SLOT, unless somebody
can tell me how to do write mutually recursive structure slot type declarations
and then instantiate those structures correctly.

Thanks for any pointers!

--
-------------------------------------------------------------------------------
Eric Eide          |          University of Utah Department of Computer Science
·····@cs.utah.edu  | Buddhist to hot dog vendor: "Make me one with everything."

From: Barry Margolin
Subject: Re: Mutually Referential DEFSTRUCT Slot Types: How?
Date: 
Message-ID: <16d8rrINNm7q@early-bird.think.com>
In article <···················@asylum.cs.utah.edu> ························@cs.utah.edu (Eric Eide) writes:
>I would like to write something like the following in Common Lisp:
>
>  (defstruct a
>    (slot nil :type b))
>
>  (defstruct b
>    (slot nil :type a))

(defstruct a
  slot)

(defstruct b
  (slot nil :type a))

(declaim (ftype a-slot (a) b))

Except that this doesn't permit you to declare that the type of the new
value when SETFing A-SLOT must be B.

>but I think that this type specifier would not give my compiler enough
>information to allow it to opencode my structure accessors.  Speed is important
>in my application, but probably not critically so.

I'm not sure that this particular set of declarations is likely to be used
by most implementations.  What kind of open coding do you expect it to
enable?

>Second, how can I create an instance of either of these objects, while keeping
>the declared types accurate?

My type declaration allows this, since it doesn't require that A-SLOT be
initialized to a B.  It only requires that it be assigned a B before being
read.
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Rob MacLachlan
Subject: Re: Mutually Referential DEFSTRUCT Slot Types: How?
Date: 
Message-ID: <Bt6yHy.7ru.1@cs.cmu.edu>
In article <············@early-bird.think.com> ······@think.com (Barry Margolin) writes:
>In article <···················@asylum.cs.utah.edu> ························@cs.utah.edu (Eric Eide) writes:
>>I would like to write something like the following in Common Lisp:
>>
>>  (defstruct a
>>    (slot nil :type b))
>>
>>  (defstruct b
>>    (slot nil :type a))
>

The ANSI draft says that:
    "it is permissable for an unknown type to appear in a declaration
    at compile time, though a warning might be signalled in this
    case."

The rationale (which didn't make it into the standard) for this
decision was to support constructs such as the above.

Barmar suggests:
>(defstruct a
>  slot)
>
[...]
>
>(declaim (ftype a-slot (a) b))
>

Nit: the syntax for the FTYPE declaration should be:
    (declaim (ftype (function (a) b) a-slot))

>Except that this doesn't permit you to declare that the type of the new
>value when SETFing A-SLOT must be B.

You could:
    (declaim (ftype (function (b a) b) (setf a-slot)))

but the standard doesn't seem to require structure slot setters to be
SETF functions (though the integration of structures and CLOS would
suggest this approach.)
 
>>but I think that this type specifier would not give my compiler
>>enough information to allow it to opencode my structure accessors.
>>Speed is important in my application, but probably not critically
>>so.
>
>I'm not sure that this particular set of declarations is likely to be used
>by most implementations.  What kind of open coding do you expect it to
>enable?

Any Common Lisp implementation should open-code uses of slot
accessors as long as the structure definition has been seen by the
compiler.  It won't matter what the slot types are or what is known
about the types of the actual operands to the accessors (which are
required to be of the correct type.)

CMU Common Lisp does respect to these declarations, but the main
advantage of specifying the types of structure-valued slots is better
run-time error detection and reduced cost for run-time type checking.
In other words, it is more of a robustness advantage than an
efficency advantage.  

There can be a significant efficency advantage for slot type
declarations such as FIXNUM, SIMPLE-BASE-STRING, SIMPLE-VECTOR, etc.,
since a good compiler will be able to automatically use the appropriate
type-specific operations on values of those slots.

>>Second, how can I create an instance of either of these objects,
>>while keeping the declared types accurate?

You can't.  Our coding practice for CMU Common Lisp is to
explicitly specify how we are going to "ground out" the recursion:
  (defstruct a
    (slot nil :type (or b null)))

  (defstruct b
    (slot (error "Slot must be supplied.") :type a))

You make the A first with a null SLOT, then make the B, then
back-patch the A.

  Robert A. MacLachlan