The latest Kawa in CVS has new experimental syntax for generalized access to named parts of objects. The basic form is:
expression:nameThis 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.
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.)
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
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:nameis equivalent to:
(lambda args (apply invoke expression 'name args))For example:
(#xff:toString) ⇒ 255 (255:equals #xff) ⇒ #t
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
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.
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 ...):nameis the same as:
(values-append val1:name ...)
Issue: What to do when name
is resolved
to a method?
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.]
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.)
a:b
into ($lookup$ a 'b)
and
a:b:c
into ($lookup$ ($lookup$ a 'b) 'c)
.
(*:.field-name instance)
(class-name:.field-name)