On Thu, 2009-09-03 at 23:42 +0300, Abdulaziz Ghuloum wrote:
> On Sep 3, 2009, at 9:30 AM, Derick Eddington wrote:
> 
> > My wording in my last post below was hurried.  Let me elaborate  
> > better.
> >
> > If you think "record type" is distinct from "record type descriptor",
> > and "record type definition" is only via define-record-type and not  
> > via
> > make-record-type-descriptor, then some of the wording/design in R6RS
> > might be more clear to you.
> 
> Yes, I do see them as different things. [I'm just elaborating here
> for the general benefit; you might know all of this already.]
> 
> When you do (define-record-type foo), foo is not bound as a variable
> nor as a macro, which may seem strange since R6RS does not say what
> it really is.  

It does seem strange, both because R6RS doesn't really say what it is or
if it can be exported/imported like define and define-syntax bindings,
and because I think I want record types to be first-class.

> There, foo is bound to a record type: an expand-time
> bindings identifying foo as a record type, and providing the expander
> with information about the record type, most importantly: it's rtd
> and rcd.  You can obtain these two using (record-type-descriptor foo)
> and (record-constructor-descriptor foo).  If there is ever a need to
> attach any more information to foo, the implementation can easily
> attach it without needing to expose it in a separate name.

Couldn't a define-record-type macro, which binds the type name as a
run-time variable to an RTD, attach the expand-time info to the
identifier bound to the RTD, and then the expand-time info would be
attached to an identifier the same as it is now, but record types would
also be first-class run-time. ?  I believe Clinger suggests this [1].  I
think mutability of the RTD variable is an issue, but for most cases the
variable can be known to be immutable.

> > But, the beginning of R6RS Libraries
> > Chapter 6 definitely gives the impression "record type" and "record
> > type descriptor" are the same.
> 
> I just reread the intro to Chapter 6 and did not get that
> impression.  :-)  It's obvious to me that a record *type* and
> an rtd *object* are two different things and live at different
> times (but then, this is precisely what you're complaining
> about).

This, from that intro to Chapter 6, is what makes me think it definitely
gives the impression "record type" and "record type descriptor" are the
same:

        The record mechanism spans three libraries:
        
              * [... point about syntactic layer ...]
                
              * the (rnrs records procedural (6)) library, a procedural
                layer for creating and manipulating record types and
                creating constructors, predicates, accessors, and
                mutators;
                
              * [... point about inspection facilities ...]

It says the procedural layer is for creating record types, which implies
make-record-type-descriptor creates types.

And:

        The procedural layer is particularly useful for writing
        interpreters that construct host-compatible record types. It may
        also serve as a target for expansion of the syntactic layers.

It says the procedural layer is for constructing record types.

> > Regardless of word-twisting, I think Will Clinger's main point is that
> > record types should always be record type descriptors so that it's not
> > necessary to determine whether a "record type" thing is a first-class
> > run-time descriptor or an expand-time handle.  With R6RS, it's  
> > necessary
> > to know if you need to use record-type-descriptor or not and whether  
> > you
> > need to use parent-rtd or parent.  I think the argument is that this
> > breaks the abstraction of "record type" in an unacceptable way.
> 
> [Probably you should not be talking on Clinger's behalf unless
> you provide citation and quote what he says, but anyways ...]

Sorry for not citing him.  His essay at [1] says what I said his main
point is and it says other things and it is quite convincing to me.

> I personally don't care about R6RS's procedural layer much.  In
> Ikarus before R6RS, it had simple records (now renamed structs to
> avoid confusion) and they did have a syntactic and procedural
> layers.  The thing is: I never ever used the procedural layer in
> all these years.  (seems like I only added it for good measure)
> So, there was never any confusion about what foo really is: it
> can only be one thing: a record type; and the rtd object was
> always hidden in the constructor, predicates, etc.
> 
> So, it might be that the source of confusion in R6RS is that,
> again, two different groups of people had two different ideas
> about what the record facility should look like, and being an
> all-inclusive standard, we got both facilities.  And while
> both facilities work ok (i.e., can definitely be improved),
> understanding that they're two separate things is not as
> simple as understanding only one of them.

According to Clinger [1], they don't have to be two separate things.
According to Sperber [2], Dybvig is/was for Clinger's changes.
  
> > For example, my matcher matches records, and to support "record type"
> > things made with either define-record-type or
> > make-record-type-descriptor, I have to have special syntax to
> > distinguish whether the given record type is an expand-time handle or
> > evaluates to a run-time descriptor:
> >
> >> (define A (make-record-type-descriptor 'A #F #F #F #F '#()))
> >> (match 1
> >    ((:record A) 'record)
> >    (_ 'nope))
> > Unhandled exception
> > Condition components:
> >   1. &who: record-type-descriptor
> >   2. &message: "not a record type"
> >   3. &syntax:
> >       form: (record-type-descriptor A)
> >       subform: #f
> >   4. &trace: #<syntax (record-type-descriptor A)>
> >   5. &trace: #<syntax (match-lambda ((:record A) 'record) (_ 'nope))>
> >   6. &trace: #<syntax (match 1 ((:record A) 'record) (_ 'nope))>
> >> (match 1
> >    ((:record (RTD A)) 'record)
> >    (_ 'nope))
> > nope
> 
> Ideally, the match macro should ask the system about the binding
> of A and extract some more information in order to at least do
> more checking at expansion time instead of deferring it to
> runtime (e.g., you should be able to check at expansion time if
> "A" has the right number of fields listed in the match clause
> instead of generating erroneous code that bombs at runtime).

That would be great.

> If you insist that record types are ordinary variables bound to
> values that may happen to hold rtds at run time, then you've just
> given up on the ability to do anything with them at expansion
> time.

According to Clinger [1], that's not true.  If, as I mentioned above,
identifiers bound to an RTD had the same expand-time info attached to
them, then they could be queried at expand-time for the info exactly the
same as what (I think) you're suggesting.  I don't see why first-class
types should be sacrificed.

> > I somewhat arbitrarily chose to make expand-time handles the default  
> > and
> > automatically wrap them in record-type-descriptor in the match
> > expression expansion, because I assumed most users will use
> > define-record-type and I didn't want adding record-type-descriptor  
> > to be
> > needed.
> 
> I think this is the correct assumption.  As a matter of fact,
> you can be safe ignoring the other layer completely.  I cannot
> believe anybody is using the procedural layer and making the
> rtds manually and then wanting to use pattern matching (a
> syntactic facility) to match on those.

I think some people have real uses for run-time creation of types.  It
sure seems interesting to me, and if there's not a convincing reason not
to have first-class types, then I'm all for them.

Pattern matching is a syntactic facility, but it's just sugar for doing
the type- and shape-checking and destructuring and binding.  We use
pattern matching on all sorts of first-class run-time things.  I'd love
to optimize my matcher's checking to expand-time where possible, and for
record fields that seems possible without sacrificing first-class record
types.

> > But I could also justify making descriptor expressions the
> > default and require adding record-type-descriptor for expand-time
> > handles.
> 
> No you can't. :-)

If people want to create types at run-time, then I can justify needing
to support RTDs.  I don't know if a particular user will prefer
expand-time handles or RTDs to be the default.  I prefer the issue not
exist -- unify the two.

> Just in case it's not obvious, I do dislike the procedural
> layer in R6RS and think it's too complicated (actually, the
> whole R6RS records are too complicated).  

I used to think that more, but now I understand the desire for more of
its various facilities like: protocol / constructor descriptors,
generative-ness, sealed-ness, and opaque-ness.  Though, I'm not sure if
protocols / constructor descriptors need to be part of the record
standard, because maybe they can be done the same independently.

> I can never put the
> whole thing in my head at once.  Like, I can never remember
> what arguments make-record-type-descriptor takes and what
> they should be, 

But that's usually abstracted over.  I didn't remember either, but it
took me only a few minutes to look it up.

> especially the vectors listing field names
> (come on!), 

I agree that's weird.  I told Clinger so [3].

> inheritance protocols, 

They can be confusing, but I appreciate the rationale for them.  Clinger
convinced me [4] they make sense but they should be designed
differently.  His [1] also talks about preferred constructor
descriptors.

> and how you cannot do
> anything with a record without first creating a procedure
> (predicate, accessor, mutator, etc) to do it for you.

I'm not sure I follow.  How would you like this to be different?

> [side remark: Ikarus's current implementation of R6RS records
> sucks.  Originally, I was going to adapt the same strategy
> of implementing structs which would've made at least the
> syntactic layer of R6RS records very robust and efficient.
> Unfortunately, Will Clinger's formal comment that resulted
> in adding "parent-rtd" to the syntactic layer made that
> implementation strategy far more difficult.  

What formal comment was that? (I wasn't able to find it, but could have
missed it.)  In [1], Clinger says parent-rtd was pilled on and makes it
clear he doesn't like it, but I think he doesn't like it because it's a
symptom of the split between RTDs and expand-time record type handles.

> In the long
> term, this should not be a problem since ikarus's syntactic
> define-record-type now only expands to the procedural layer
> and thus optimizing the procedural layer should automatically
> benefit the syntactic layer, 

I believe this is how Clinger thinks it should be done (because of
Larceny's and SRFI 99's records design).  But he also says the easier
expand-time info technique can still be done [1].

> but this is an additional burden
> on the implementor that (I believe) should not have been
> there since the syntactic layer, by itself, is trivial to
> optimize, while the procedural layer requires data-flow
> analysis (across libraries to be most effective).  As far as
> I know, only Chez Scheme does some of that.]

If the expand-time info technique can still be done, then that burden
doesn't exist.  Even if that burden still exists, I don't find it a
persuasive reason to break the abstraction of "record type" and to
sacrifice first-class run-time abilities.  I want technological
advancement.  The flow analysis required to optimize the procedural
layer is known (I think), so it should be used.  R6RS stepped-it-up with
cyclic-safe equal?, and Scheme stepped-it-up with first-class
continuations -- both of which require non-trivial techniques for
efficiency.

For an optimizing compiler guy like yourself, requiring more non-trivial
techniques increases demand for you :)  And a more capable records
system attracts more users and increases their happiness.

[1] http://www.r6rs.org/ratification/results.html#X101
[2] http://lists.r6rs.org/pipermail/r6rs-discuss/2009-February/003839.html
[3] http://srfi.schemers.org/srfi-99/mail-archive/msg00007.html
[4] http://groups.google.com/group/comp.lang.scheme/msg/e10cd3ab3f90c5be

P.S.  I've had a few stints as a salesman.

-- 
: Derick
----------------------------------------------------------------

Reply via email to