[Grace-core] Annotations: starting discussion
James Noble
kjx at ecs.vuw.ac.nz
Tue Jun 26 23:25:01 PDT 2012
And here's the other one. the state of discussion on annotations.
The main thing that I think has changed is
that we now think we will have to "strop" annotations
@foo @bar
@(foo,bar)
[foo, bar]
<<foo, bar>>
«foo, bar» // just to make andrew happy, but we won't adopt it
or at least have a keyword or some defined place where you'd find annotations.
rather than get to them implicitly
Basically we need to permit annotations to everything:
- declarations (var, def, method, type)
<<@public, @synchronised, @transatction>> method main {print "Hello"}
- literals (objects, numbers, strings, blocks)
<<@confined, @sychronised, at multi-reader>> object {... }
- types, including method arguments & results
type Integer = <<@MachineInteger, at Nofractions, at Primitive>> Number
method report (input : <<@Confined>> Number) -> <<@Confined>> Number
- requests, (resulting in Ly/AmbientTalk style adverbs:
foo.<<@asynch>>bar()
bar <<@asunch>>+ 3
and ideally do it in a way that doesn't make the whole language horrible.
Haskell doesn't have annotations, does it?
James
From: James Noble <kjx at ecs.vuw.ac.nz>
Date: 8 December 2011 1:29:49 AM NZDT
Subject: Annotations Proposal (including Brands as object & type annotations)
To: Andrew P. Black <black at cs.pdx.edu>, Kim Bruce <kim at cs.pomona.edu>
I keep talking about this but haven't written much up.
Basically the plan is to rip off Ceylon's design, but do better, perhaps.
http://in.relation.to/Bloggers/IntroductionToCeylonPart12
- Annotations look like implicit self requests --- i.e. syntactically function calls.
- probably not permit multipart names here.
- Annotations are defined in a dialect as private/confidential methods of the dialect
that return a subclass of Annotation (and are annotated annotation).
- either subclassing or generics used to tag annotations as to what syntatic elements they can annotate
- those methods should be const & return value objects (deep value objects?)
- Annotations on declarations are written as method calls, and accumulate and all apply to the subsequent declarations
- no-arg annotations may be written together one line, the parser needs to do the right thing
doc "This function prints hello world"
public callable synchronized final method hello {print "Hello World"}
- syntactic problem: assuming no stropping or other markers -
- how do we know where annotations end?
- especially in type declarations? do we have to work from right-to-left?
- annotations also need to be placed on types
- again, how do you distinguish within type declaration bodies what's being used as annotation and what's a definition?
(i.e. how do you give an interface that defines a bunch of annotations?)
- annotations also need to be placed on expression
- scala uses "exp : annotation" syntax.
- another option is to use annotations that are identity functions (mostly)
cast<Integer>( 1.0 + 1.0 )
debuggable ( x.foo )
- Annotations as meta-objects
- annotations can be placed on objects.
- how? annotations on class declarations & object constructors.
- any other way (annotated expressions?)
- are annotations added at creation time & thus static, or...?
actor object {
inherits Actors.Actor
method run { "do stuff" }
}
- annotations need to be able to placed on types too:
type MyActor = actor Actors.Actor & { "whatver stuff I have" }
- Brands are just special annotations on types
- generally IF a type is branded, it will only match similarly branded objects.
- thus introducing full nominal types through the back door... :-)
- someone should check this against Chapter 8 Section 8.1 of the Modula-3 book.
brand("Cowboy") class Cowboy {
public method draw { ... }
}
brand("Window") class Window {
public method draw { ... }
}
def myWindow : brand("Window") {draw -> Unit } = Cowbow.new // fails, hopefully at compile time, certainly at runtime!
- brands could be any (constant) object, strings are easy, but real programs
will probably use private objects in a module so that they cannot be duplicated.
- nasty issue, doing e.g. def myBrand = object {} // gets the null object, which is hash-consed :-)
or at any rate equal to any other object {}
- brands must count in object identity: object {} != brand("foo") object {}
- adding a mutable field forces uniqueness (but means the brand itself is no longer immutable - does that matter?)
def myBrand = object { var foo }
- in the implementation, treat object annotations like generic parameters?
- really, like lisp propertylists.
- do we e.g. want *negative* brands, objects with negative brands only match types if the brand is present in the types
- standard brands are "positive", acting like an extra uncallable method on the type.
- an UNBRANDED TYPE will match all structurally-confirming branded and unbranded types (see note below)
- a negative brand would somehow stop an unbranded typed from matching, unless the type was also branded...
- how would that work with dynamic (doesn't even match dynamic, perhaps?)
- Major issue - to strop or not to strop?
- not stropping (the syntatic proposal above) makes the code look much much nicer
but introduces ambiguities / feedback loops into the _parser_
- stropping, we could follow Java & Scala = write @public @annotation
or follow C# [public, annotation] - no ambiguity, but looks uglier.
- possible alternative strop: annotations must be followed by a comma
public, void, def x = 3
- or since they are implicit method calls anyway, just use semicolons: public; static; synchronized; method main {print "Hello"}
- Partial list of annotations
- public -> Annotation < Declaration >
- private -> Annotation < Declaration >
- const -> Annotation < Request >
- value -> Annotation< Object >
- final -> Annotation< Declaration >
- brand( brnd : Any ) -> Annotation< Type | Object >
- owned -> Annotation<Object >
More information about the Grace-core
mailing list