Opened 8 years ago

Closed 5 years ago

#45 closed enhancement (wontfix)

Record-let syntax and semantics

Reported by: medernac Owned by: alexshinn
Priority: major Milestone:
Component: WG1 - Core Keywords:
Cc:

Description

(record-let <record-data>

((<variable> <field>)

...)

<body>)

Where each <variable> is filled with the corresponding data <field> from <record-data> as in a <let> expression, then the <body> is evaluated with these bindinds added and last expressions is returned. It is an error if the <record-data> does not contain corresponding <fields>.

Notice that this works directly on the data itself and that the data may contain more fields than the one cited in the record-let expression allowing code to be reused for inherited records.

  • Do we need to be able to check at runtime if a given record data has a given field ?

Change History (12)

comment:1 follow-up: Changed 8 years ago by cowan

This will only work if the field names are available at run time, unless the type is also available at compile time.

comment:2 follow-up: Changed 8 years ago by arcfide

An alternate implementation that uses (<record-data> <record-type-descriptor>) instead of <record-data> above will enable record-let to work entirely at compile-time.

I also think that let-record is maybe a more consistent name.

comment:3 in reply to: ↑ 1 Changed 8 years ago by medernac

Replying to cowan:

This will only work if the field names are available at run time, unless the type is also available at compile time.

Yes, It must keep track of fields name. Some kind of reflection is needed for that to work.

By the way, would it be better if fields are restricted to be symbols only ?

comment:4 in reply to: ↑ 2 ; follow-ups: Changed 8 years ago by medernac

Replying to arcfide:

An alternate implementation that uses (<record-data> <record-type-descriptor>) instead of <record-data> above will enable record-let to work entirely at compile-time.

I am a bit reluctant to this but I agree that could be done that way.

I also think that let-record is maybe a more consistent name.

I am Ok for whatever name.

By the way notice that if we have only single-inheritance (hierachy of types) it is easy by convention to always use the same index number as parent-type fields. So an interpreter/compiler just has to lookup from the fields name which is the corresponding index for fields.

comment:5 in reply to: ↑ 4 Changed 8 years ago by arcfide

Replying to medernac:

By the way notice that if we have only single-inheritance (hierachy of types) it is easy by convention to always use the same index number as parent-type fields. So an interpreter/compiler just has to lookup from the fields name which is the corresponding index for fields.

If we have to do lookups, I'm a little concerned. Lookups can be elided when dealing with a sufficiently smart compiler in many/most cases, but not all, and with interpreters that don't do such optimizations, you will end up having much slower access. Especially when dealing with parents that could come from other libraries, the speed issues become more obvious since it is very hard to do that sort of reasoning in general.

comment:6 in reply to: ↑ 4 ; follow-up: Changed 8 years ago by kumoyuki

Replying to medernac:

By the way notice that if we have only single-inheritance (hierachy of types)
it is easy by convention to always use the same index number as parent-type
fields. So an interpreter/compiler just has to lookup from the fields name
which is the corresponding index for fields.

It's worth noting that delegation techniques are strictly more expressive than inheritance based ones and they completely avoid the hair of multiple inheritance (this was shown in an OOPSLA paper somewhere around 1994-1996 but I've forgotten the title). I think it would be lovely to see a programmer-defined aggregate system that supported delegation as the core mechanism rather than any form of inheritance.

comment:7 in reply to: ↑ 6 ; follow-up: Changed 8 years ago by cowan

The only "methods" we have are getters, setters, and predicates. It's not clear to me what the difference is between delegation and inheritance in that context.

comment:8 in reply to: ↑ 7 ; follow-up: Changed 8 years ago by kumoyuki

Replying to cowan:

The only "methods" we have are getters, setters, and predicates. It's not clear to me what the difference is between delegation and inheritance in that context.

The reference to inheritance was the OP's. The difference could be trivial; the issue is what types does a new value become a member of (and expose the interfaces of). I do realize that the proposal we are commenting on contains no such information, and I wonder how OP got to inheritance in the first place. The lack of anything resembling a type algebra, even as simple a one as SI, has often been mentioned as one of SRFI-9's main drawbacks, so I expect that it *will* come up somewhere along the line. In fact it is one of the few areas where I'd be willing to see more complexity come into Thing1.

comment:9 in reply to: ↑ 8 Changed 8 years ago by medernac

Replying to kumoyuki:

To illustrate the idea, here is what I am personnaly using in association with let-record for record definition with types:

(record-constructor <Constructor name>
		    <Type checker name>
		    <Fields name>
		    (<Type> <data> <getter>) ...)

Where I view type mainly as predicates. I don't have setters, but I
see no problem in adding it. Here are some examples:

;; A flat record
(record-constructor make-job
		    job-type?
		    job-fields
		    (real?   release  job-release)
		    (real?   duration  job-duration)
		    (string? username  job-username))

(define (List-of type?)
  (lambda (data)
    (and (list? data)
         (let loop ((tmp data))
	    (or (null? tmp)
	        (and (type? (car tmp))
	             (loop (cdr tmp))))))))

;; A record with recursive type field
(record-constructor Tree-of-integer
		    Tree-of-integer-type?
		    Tree-of-integer-fields
		    (integer? element Tree-of-integer->element)
		    ((List-of Tree-of-integer-type?) subtrees Tree-of-integer->subtrees))

(Tree-of-integer 17 (list (Tree-of-integer 12 '())))


But I could also do type parameterization like this:

(record-constructor (<Constructor name> <Type parameter> ...)
		    <Type checker name>
		    <Fields name>
		    (<Type> <data> <getter>) ...)

For instance:

(record-constructor (Tree type?)
		    Tree-type?
		    Tree-fields
		    (type? element Tree->get-element)
		    ((List-of (Tree type?)) subtrees Tree->get-subtrees))

And then generate records like this:

(define make-integer-tree (Tree integer?))
(make-integer-tree 17 (list (make-integer-tree 12 '())))

(define make-string-tree (Tree string?))
(make-string-tree "foo" (list (make-string-tree "bar" '())))

Then let-record easily allows access to fields and I could reuse the same code for records sharing some fields.

comment:10 Changed 6 years ago by alexshinn

  • Resolution set to fixed
  • Status changed from new to closed

We voted no.

comment:11 Changed 5 years ago by cowan

  • Resolution fixed deleted
  • Status changed from closed to reopened

comment:12 Changed 5 years ago by cowan

  • Resolution set to wontfix
  • Status changed from reopened to closed
Note: See TracTickets for help on using tickets.