This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: annotations for Kawa


On Dec 4, 2010, at 11:08 AM, Per Bothner wrote:

Those of you who've been following Kawa CVS check-ins may have
noted that the low-level support for annotations is now mostly
there in gnu.bytecode.

Great news! Thanks, Per!


The next issue is the syntactic support.  As suggested before,
the most logical syntax for an individual annotation is probably:

(@AnnotationType keyword1: exp11 ... keywordN: exprN)

where AnnotationType is an annotation type name (identifier),
and exp1..exprN are compile-time-constant expressions.

As in Java, the shorthand:

(@AnnotationType expr)

is short for:

(@AnnotationType value: expr)

Annotations can be "attached" to declarations.  But we have a number
of choices.  For simple variable declarations we have these choices:

[v1] (define (@Deprecated) var ::type init-expr)
[v2] (define var (@Deprecated) ::type init-expr)
[v3] (define var ::type (@Deprecated) init-expr)

For a field declaration in a class we also have options.
(The examples use the object form that defines an anonymous
class, but define-class and define-simple-class are similar.)

[f1] (object () ((@Deprecated) var ::type option-pair...))
[f2] (object () (var (@Deprecated) ::type option-pair...))
[f3] (object () (var ::type (@Deprecated) option-pair...))
[f4] (object () (var ::type  option-pair... (@Deprecated)))

Java has the annotations before the new name, so would match [v1] and
[f1] best.  However note in the in Java the type and modifiers also
come before the name, while in Kawa-Scheme they come after.  So I
don't think [v1] or [f1] really make sense.  Personally, I don't
think [v3] or [f3]/[f4] look right.  So my preference would be:

[v2] (define var (@Deprecated) ::type init-expr)
[f2] (object () (var (@Deprecated) ::type option-pair...))

Works for me, though I would also be OK with [v3]/[f3] (which are close to the
mirror image of the Java ordering).


For a method declaration in a class, we have:

[m1] (object () ((meth (@Deprecated) arglist) ::rettype option- pair... body))
[m2] (object () ((meth arglist) (@Deprecated) ::rettype option- pair... body))


The advantage of [m1] is that it follows the rule that the annotations go
after the new name. The advantage of [m2] is that annotations are in the same
category as return-type specifier and option-pairs and should be in the same
area in the definition syntax. I'm leaning to [m2].

I much prefer [m2]. The method name and arguments should be undivided in order
to match how they will appear at call sites. The same thing goes for procedures
expressed in the defun style. If we have:


[p1] (define (foo (@Deprecated) x) ::rettype expr...)
[p2] (define (foo x) (@Deprecated) ::rettype expr...)

[p2] looks better to me than [p1] because it's easier to see what arguments the
function takes. Having the annotation in between the name and arglist seems too
intrusive to me.


For a class one of these:

[c1] (define-class MyClass (@Deprecated) (MySuper) option-pair... member...)
[c2] (define-class MyClass (MySuper) (@Deprecated) option-pair... member...)


The advantage of [c1] is that it follows rule that the annotations go after
the new name, thus consistent with [m1]. The advantage of [c2] is that
it is consistent with grouping the annotations with the option-pairs.
I like [c1] more, though it may be less consistent with the other choices.
If one thinks of the (MySuper) spec as "corresponding to" a ::type
specifier, then I guess [c1] is consistent with that.

Either works for me.


Note we're talking about recommended syntactic placement of annotations
in declarations - i.e. the preferred style. The actual compiler might be
a bit more lenient. For example it might allow annotations inter- mingled
with option-pairs.


Note that JSR 308 (slated for Java 8) may add annotations on types.
I think if these get added to Kawa the following would make sense:

(define str ::(@NonNull)Container (...))

I.e. a type annotation would be a prefix of the type specifier.

Seems reasonable.


Comments?

It's valid to have multiple annotations attached to a single declaration in Java,
so Kawa should handle multiple annotations as well:


[v2a] (define var (@Deprecated) (@Foo) ::type init-expr)
[v2b] (define var ((@Deprecated) (@Foo)) ::type init-expr)

Either of these would work for me.



I've mentioned before that I think a @Documentation annotation would be a good way
to store Lisp-style documentation strings so that they would still be available at
runtime. At the syntax level, then, I would like to see these two forms as equivalent:


1. (define (square (n ::number))
     (@Documentation "Returns the square of the number N.")
     ::number
     (* n n))

2. (define (square (n ::number)) ::number
     "Returns the square of the number N."
     (* n n))

That is, the compiler should automatically treat as a @Documentation annotation a
String found as the first expression of the procedure's body (as long as it isn't
the only expression, in which case the String is not a docstring but rather the
return value). Presumably the same would go for class methods.


For simple variables, I believe the Emacs Lisp style (for defconst, defvar, etc)
is to put the docstring after the init-expr, so
(define var ::type init-expr "This is a docstring.") ought to work the same as
(define var (@Documentation "This is a docstring.") ::type init-expr). Likewise
for class fields.


I don't think Common Lisp's defclass has a docstring option, so I don't know a
precedent for how it would look for classes.




I do have a question about where the annotations will end up in the class file.

If I write mymath.scm like this:
$ cat mymath.scm
(module-export square)
(define (square (n ::number)) ::number (* n n))

and compile it, javap tells me
Compiled from "mymath.scm"
public class mymath extends gnu.expr.ModuleBody implements java.lang.Runnable{
public static final gnu.expr.ModuleMethod square;
public static final mymath $instance;
static final gnu.mapping.SimpleSymbol Lit0;
public mymath();
public static gnu.math.Numeric square(gnu.math.Numeric);
public final void run(gnu.mapping.CallContext);
public static {};
public int match1(gnu.expr.ModuleMethod, java.lang.Object, gnu.mapping.CallContext);
public java.lang.Object apply1(gnu.expr.ModuleMethod, java.lang.Object);
}


so there's a Java method square(gnu.math.Numeric), but there's also a ModuleMethod square.
Which of these will get the annotations I give to the square procedure in the source file?


It'll matter for how the eventual #'documentation function should find the correct
@Documentation annotation.




Thanks,
Jamie

--
Jamison Hope
The PTR Group
www.theptrgroup.com




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]