Protection levels for record types

Posted on Fri Jul 29, 2016

More work in the master branch of Vicare. Record–types now support protection levels public, protected, private for fields and methods. I have not implemented protection levels for the parent clause: it makes the rules for virtual methods too complex for me.

Everything I discuss here is relative to code in the head of the master branch.

Protection levels

Here a copy and paste from the documentation…

When the typed language is enabled, record–type definitions support protection levels for fields and methods. Protection levels limit the way fields and methods can be used both from other types in the record–type hierarchy and from outside a record–type’s definition.

Three protection levels are supported: public, protected and private; they are loosely modeled after the ones defined in the C++ language.

The following syntactic bindings are exported by the library (vicare).

Auxiliary Syntax: public

Select the public protection level for the associated fields and methods. When a member of record–type <T> is given the public protection level: sub–types of <T> can access it; instances of <T> can access it from outside methods.

When no protection level is specified for a member in a record–type definition: the protection level defaults to public.

Auxiliary Syntax: protected

Select the protected protection level for the associated fields and methods. When a member of record–type <T> is given the protected protection level: sub–types of <T> can access it; instances of <T> cannot access it from outside methods.

Auxiliary Syntax: private

Select the private protection level for the associated fields and methods. When a member of record–type <T> is given the private protection level: sub–types of <T> cannot access it; instances of <T> cannot access it from outside methods.

The protection level keywords can be used both as “wrapping syntaxes” as in:

(define-record-type <duo>
  (public
    (fields one two)
    (method (add)
      (+ (.one this) (.two this)))))

or as “attribute syntaxes” as in:

(define-record-type <duo>
  (fields public one two)
  (method public (add)
    (+ (.one this) (.two this))))

The only clauses that can be put in a wrapping syntax and that accept an attribute syntax are: fields, method, virtual-method, seal-method.

Usage and limitations by examples

The protection levels limit the access to members from outside a method’s body:

(define-record-type <blue>
  (method public    (pub)  1)
  (method protected (pro)  2)
  (method private   (pri)  3))

(define O
  (new <blue>))

(.pub O)        ⇒ 1
(.pro O)        error→ not a public method
(.pri O)        error→ not a public method

When super–type’s members are public, everything works as usual:

(define-record-type <blue>
  (fields public light))

(define-record-type <dark-blue>
  (parent <blue>)
  (method public (doit)
    (.light this)))

(define O
  (new <dark-blue> 1))

(define {X <blue>}
  O)

(.doit  O)      ⇒ 1
(.light X)      ⇒ 1

When super–type’s members are protected, we can access them from the super–type’s methods and from the sub–type’s methods:

(define-record-type <blue>
  (fields protected light)
  (method public (doit)
    (.light this)))

(define-record-type <dark-blue>
  (parent <blue>)
  (method public (doit)
    (.light this)))

(define O
  (new <dark-blue> 1))

(.doit O)       ⇒ 1

(define {X <blue>}
  O)

(.light X)      error→ not a public method
(.doit  X)      ⇒ 1

When super–type’s members are private, we can access them from the super–type’s methods only:

(define-record-type <blue>
  (fields private light)
  (method public (doit)
    (.light this)))

(define X
  (new <blue> 1))

(.light X)      error→ not a public method
(.doit  X)      ⇒ 1

(define-record-type <dark-blue>
  (parent <blue>)
  (method public (doit)
    (.light this)))     error→ not a public or protected method

It is not an error to define a private virtual method, but such method cannot be overridden by the sub–types:

(define-record-type <blue>
  (virtual-method private (doit) 1))

(define-record-type <dark-blue>
  (parent <blue>)
  (method (doit) 2))    error→ cannot override private method

Virtual methods overriding and sealing is possible only among methods of the same protection level:

(define-record-type <blue>
  (protected
    (virtual-method (over)
      'over-blue))
  (method (doit)
    (.over this)))

(define-record-type <dark-blue>
  (parent <blue>)
  (protected
    (method (over)
      'over-dark-blue)))

(define O
  (new <dark-blue>))

(define (fun {X <blue>})
  (.doit X))

(fun O)         ⇒ over-dark-blue