Component parts and paths

The latest Kawa in CVS has new experimental syntax for generalized access to named parts of objects. The basic form is:

expression:name
This generalizes the : (colon) character use for namespace prefixes, and keywords. However, conflicts are unlikely, because ???? Also, no spaces are allowed on either side of the : character.

The expression is evaluated to yield an object, and then the operation extracts the part of the object with the given name, yielding the value of the part. The character : is similar to the Java . (dot) operator; the following will explains the kinds of objects and parts supported.

This notation generalizes Kawa's colon/namespace notation for field/method accesses, is more compact, and lends itself better to chaining.

The notation is new, but implemented reasonably solidly, The compiler will usually generate good code, if it has sufficient information.

Compound values implementing HasNamedParts

If the expression evaluates to an object implementing HasNamedParts, then the getNamedPart method is used to extract the component. (Not implemented yet; no examples yet.)

Field parts

If the result of expression does not implement HasNamedParts, then we look for an instance field or bean property with the given name, as in the slot-get method. For example, currently cons pairs are implemented using the Pair, which has public car and cdr field. (This may change to handle lazy conses.) Thus:

(list 3 4 5):car ⇒ 3
(list 3 4 5):cdr:car ⇒ 4

If there is no accessible instance method with the given name, then we look for a nullary method named getName or isName:

(define (fun x) x)
fun:name ⇒ fun

Method parts

If there is one or more accessible methods with the given name in the class or a base class of the result of expression, then the result is function. Specifically, this case:

expression:name
is equivalent to:
(lambda args (apply invoke expression 'name args))
For example:
(#xff:toString) ⇒ 255
(255:equals #xff) ⇒ #t

Static class parts

Static fields and methods are viewed as components of the class itself.

<java.lang.Integer>:MAX_VALUE ⇒ 2147483647
;; Call the listTail method of gnu.lists.LList:
(<list>:listTail '(3 4 5 6) 2) ⇒ (5 6)
(define-alias Long <java.lang.Long>)
Long:MIN_VALUE ⇒ -9223372036854775808
(Long:decode "01234") ⇒ 668

Assignent

Use set! to assign to a part:

(define L3 (list 2 3 4))
(set! L3:cdr:car 5)
L3 ⇒ (2 5 4)

It also works for static fields:

(define-simple-class <MyClass> ()
  (fld allocation: 'static init: 1))
(set! <MyClass>:fld 3)
<MyClass>:fld ⇒ 3

If there is no accessible name field, we look for a setName setter method.

Multiple values

If the expression evaluates to multiple values (or zero values) then the result is that of combining the result for each value. I.e. the expression:

(values val1 ...):name
is the same as:
(values-append val1:name ...)

Issue: What to do when name is resolved to a method?

XML support (unimplemented)

The following is contemplated, but not yet implemented. Extracting a named component of an XML element node would return the value of the correspondingly named attribute. (Not the actual attribute node, but its value.)

Child nodes are not selected by name, but by index, conceptually similar to array indexing (but that is a different note). We can extend the syntax with a selection operator, perhaps : followed by some other character such as /:

expression:/predicate

This returns those children of expression that satisfy the predicate. The latter will often be a node type/constructor [More documentation needed.]

Namespaces

Namespace prefixes are now names in the regular namespace:

(define-namespace gnu "www.gnu.org")
gnu ⇒ #,(namespace "www.gnu.org")
(define gnu:kawa "Kawa")
gnu:kawa ⇒ "Kawa"
'gnu:kawa ⇒ {www.gnu.org}kawa
(The latter is the non-readable print format for a compound symbol.)

Implementation

The reader turns a:b into ($lookup$ a 'b) and a:b:c into ($lookup$ ($lookup$ a 'b) 'c).

Existing colon-notation

(*:.field-name instance)
(class-name:.field-name)