Record methods and dot notation

Posted on September 12, 2015

More Vicare’s expander development for the internal representation of r6rs record types (see On records). All the changes discussed here are in the master branch.

Methods for records

As experimental (and still undocumented) feature, I have started support for methods in the definitions of r6rs record types. Three new keyword syntactic bindings are now exported by the library (vicare): method, case-method and method-call.

The clause method can be put multiple times in the body of a define-record-type use, to define a method for the record–type:

(define-record-type duo
  (fields one two)
  (method (sum-them self)
    (+ (duo-one self)
       (duo-two self)))
  (method (mul-them self)
    (* (duo-one self)
       (duo-two self)))
  (method (display self port)
    (display self port)))

we can think of method as acting like define with regard to the syntax of arguments to function; the first argument to a method is the record itself. The syntax method-call is then used to call a record’s methods:

(define {O duo}
  (make-duo 3 4))

(method-call sum-them O)        ⇒ 7
(method-call mul-them O)        ⇒ 12

(method-call display O (current-error-port))
(newline (current-error-port))  -| #[record duo one=3 two=4]

The clause case-method is similar, we can think of it as acting like case-define:

(define-record-type alpha
  (fields a)
  (case-method on-a
    ((self)
     (alpha-a self))
    ((self new-val)
     (alpha-a-set! self new-val))))

(define {O alpha}
  (make-alpha 1))

(method-call on-a O)            ⇒ 1
(method-call on-a O 2)
(method-call on-a O)            ⇒ 2

The syntax method-call searches for a record–type’s methods by comparing the symbols with eq? (not the syntactic identifiers with free-identifier=?).

If a method with the given name is not found: the syntax searches for a field with the given name, but only if the number of arguments is right. The syntax of method-call is:

(method-call ?name ?subject-expr ?arg ...)

The clauses method and case-method are accepted by define-record-type only when the language is non–strict r6rs. The syntax method-call is able to retrieve the type of its second argument only when the tagged language is enabled (at present, only with a few expressions given that the tagged language is only half–written).

Dot notation

Some time ago I reconsidered dot notation to call a type’s methods (see Reconsidering dot quoting). I do not know the language Clojure, but I read stuff through Reddit; recently a post made me skim through the syntax table of this language and I found that they use the dot notation I have in mind to call Java methods (see Clojure — java_interop1): I am not completely crazy!

Encouraged by this, I have implemented the reader syntax transformation:

(.?symbol ?arg ...) → (method-call ?symbol ?arg ...)

that is, when the reader’s textual input port is configured in ‘#!vicare’ mode: if a list starts with a symbol; the name of the symbol is a string of length at least 2; the first character of the string is a dot; the second character of the string is not a dot, then a method-call symbol is inserted and the symbol stripped of the dot.

We can try it at the repl:

vicare> '(.ciao)
$1 = (method-call ciao)

Notice that r6rs forbids symbols starting with a dot, with the exception of the ellipsis; so everything that was possible before, with the reader, is still possible now.

So we can use this syntax to call a record’s methods as in the following program:

#!vicare
(program (demo)
  (options tagged-language)
  (import (vicare))

  (define-record-type duo
    (fields one two)
    (method (sum-them O)
      (+ (duo-one O)
         (duo-two O)))
    (method (mul-them O)
      (* (duo-one O)
         (duo-two O)))
    (method (display O port)
      (display O port)))

  (define {O duo}
    (make-duo 3 4))

  (pretty-print (.sum-them O)
                (current-error-port))

  (pretty-print (.mul-them O)
                (current-error-port))

  (.display O (current-error-port))
  (newline (current-error-port))

  #| end of program |# )

which compiled and run will print:

$ vicare --compile-program demo.sps --output demo
$ vicare --binary-program ./demo
7
12
#[record duo one=3 two=4]

This dot notation still looks weird to my eyes, will I get used to it?

This feature of the reader is still undocumented: it is experimental.


Footnotes

(1)

By the way: Clojure has some very weird syntax, weirder than the ones I have imagined!