This is the mail archive of the
kawa@sourceware.org
mailing list for the Kawa project.
Re: annotations for Kawa
- From: Jamison Hope <jrh at theptrgroup dot com>
- To: kawa at sourceware dot org
- Date: Sun, 5 Dec 2010 00:00:10 -0500
- Subject: Re: annotations for Kawa
- References: <4CFA6782.7070007@bothner.com>
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