|
|
(82 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
− | {| border=0
| + | #REDIRECT [[OAW]] |
− | | width=90% |
| + | |
− | == Collection of features (rough) ==
| + | |
− | | + | |
− | In Version 5 we want to improve some of the Xtend language concepts and features.
| + | |
− | Codename is Xtend++ :
| + | |
− | | + | |
− | === Imports ===
| + | |
− | The import mechanism should be overworked, so that every import is explicite.
| + | |
− | We won't need any metamodel configuration in the workflow nor in the editors anymore.
| + | |
− | This will not only make the setup simpler but will also improve the performance.
| + | |
− | | + | |
− | The syntax would change to something like the following:
| + | |
− | | + | |
− | import org:openarchitectureware:Extension; // native import
| + | |
− | import EMF "my/package/model.ecore"; // non-native import
| + | |
− | import UML "my/test.profile.uml" as profile; // non-native import with name space definition
| + | |
− | import Java "my.test.Class"; // non-native import introduces java types and features form my.test.Class
| + | |
− | import XSD "http://www.mywebsite.org/xsd/metamodel.xsd" // non-native import importing the types from an XSD file
| + | |
− | ... (think of Hibernate mapping files, Groovy, etc.)
| + | |
− | | + | |
− | ==== Native import ====
| + | |
− | A native import refers to another extension file imports all public members (types, functions, extensions).
| + | |
− | | + | |
− | ==== Non-native Import ====
| + | |
− | A non native import starts with an identifier pointing to an installed adapter.
| + | |
− | The adapter is responsible for loading and converting the type information from the given string.
| + | |
− | The syntax in the string is defined by the adapter.
| + | |
− | | + | |
− | ==== Namespace definition ====
| + | |
− | All members are included without namespace information. If you need a namespace you can explicitely define one per import.
| + | |
− | | + | |
− | ==== Reexport ====
| + | |
− | The reexport keyword will be supported.
| + | |
− | | + | |
− | === Object creation expression ===
| + | |
− | We are thinking about a syntax to create model graphs inline.
| + | |
− | We need this not only for model transformations but also for writing model transformation tests.
| + | |
− | | + | |
− | Example:
| + | |
− | | + | |
− | new Entity {
| + | |
− | name := "Person";
| + | |
− | references += new Reference {
| + | |
− | name := "someRef"
| + | |
− | type := anotherEntity
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | ==== Assignment Expressions ====
| + | |
− | They are just another syntax for invoking a setter resp. adder-operation (which will be removed).
| + | |
− | They return the assigned value.
| + | |
− | | + | |
− | ==== create / cache semantics ====
| + | |
− | The creation expression should replace the "create extension" mechanism from Xtend 1.0.
| + | |
− | A creation of an Object is cached if the type name is suffixed with parenthesis containing any number of arguments.
| + | |
− | The arguments act as a key.
| + | |
− | | + | |
− | Examples:
| + | |
− | | + | |
− | var paramPerOperationAndName := new Parameter(op,name) {
| + | |
− | this.name := name;
| + | |
− | type := aDatatype;
| + | |
− | }
| + | |
− | | + | |
− | var localSingleton := new Foo() {
| + | |
− | stuff := "bla";
| + | |
− | }
| + | |
− | | + | |
− | ==== cross referencing ===
| + | |
− | | + | |
− | We need a way to specify crossreferences within a deklared tree. The problem is that we need a reference to a created type after it has been created and before it will be initialized. This can be accomplished by adding a special assignment construct:
| + | |
− | | + | |
− | var x := new localRef:=Entity {
| + | |
− | // x is not visible here, because the right hand expression has not be evaluated so far.
| + | |
− | // localRef holds a reference to the created but not yet intialized entity.
| + | |
− | name := "Person";
| + | |
− | references += new Reference {
| + | |
− | name := "partner"
| + | |
− | type := localRef
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | === Extensions vs. Functions ===
| + | |
− | I (Sven) would like to discuss if it wouldn't be a good idea to explicitely separate between functions and extensions.
| + | |
− | I think the author of an extension can decide how it should be invoked (<pre>my.ext() vs. ext(my)</pre>).
| + | |
− | This would make the syntax more strict, so we can provide better error messages.
| + | |
− | In addition I think it would make extension files more readable.
| + | |
− | The syntax could look like the following:
| + | |
− | | + | |
− | myFunction(String stuff) :
| + | |
− | stuff+"-+"stuff;
| + | |
− |
| + | |
− | context Entity {
| + | |
− | javaName() : name.toFirstUpper();
| + | |
− | allAttributes() : ....;
| + | |
− | anotherExtension(String name) : ...;
| + | |
− | }
| + | |
− | | + | |
− | That is functions in a ''context [Type] {}''-Block are extension - everything else is a function.
| + | |
− | | + | |
− | === Code blocks ===
| + | |
− | I (Sven) would like to discuss a ruby-like code block syntax.
| + | |
− | A code block is similar to a chain expression ( a-> b-> x) with the additional features:
| + | |
− | * provides variable declarations (Expression returning void)
| + | |
− | * support early exit using the 'return' keyword, which forces outer code blocks to exit themselfes.
| + | |
− | | + | |
− | It's something like a pseudo imperative syntax.
| + | |
− | | + | |
− | Example:
| + | |
− | | + | |
− | myExtension(String stuff) : {
| + | |
− | var x := stuff.length();
| + | |
− | if (x>56)
| + | |
− | return "Foo";
| + | |
− | else {
| + | |
− | return "Bar";
| + | |
− | }
| + | |
− | };
| + | |
− | | + | |
− | A code block is itself an expression consisting of a list of expressions.
| + | |
− | It returns the value returned by the first executed "return-expression", or the value of the last expression.
| + | |
− | | + | |
− | We should make the colon and semicolon optional so that
| + | |
− | myExt() { "stuff"; }
| + | |
− | equals
| + | |
− | myExt() : { "stuff"; };
| + | |
− | | + | |
− | === if expression ===
| + | |
− | As seen in the previous example, we want an if-expression. using if, else keywords.
| + | |
− | | + | |
− | if (predicate) expression (else if (predicate) expression)* (else expression)?
| + | |
− | | + | |
− | The else part is optional and will return null if not defined.
| + | |
− | The following expression will return null:
| + | |
− | if (false) "Holla"
| + | |
− | | + | |
− | ===Integration of Check===
| + | |
− | The language check will be integrated into Xtend. That is you can define checks and extensions in the same file:
| + | |
− | | + | |
− | allEntities(emf::EObject obj) : eRootContainer.eAllContents.typeSelect(Entity);
| + | |
− |
| + | |
− | context Entity {
| + | |
− | warning "name "+name+" should start with an uppercase letter" :
| + | |
− | name.firstToLowerCase()!=name
| + | |
− | error "duplicate name "+name :
| + | |
− | allEntities(this).select(e|e.name==name).size==1;
| + | |
− | }
| + | |
− | | + | |
− | of course you can use everything we have defined before in checks, too. Example :
| + | |
− | | + | |
− | | + | |
− | context Entity {
| + | |
− | error "duplicate name "+name {
| + | |
− | var entities := eRootContainer.eAllContents.typeSelect(Entity);
| + | |
− | allEntities(this).select(e|e.name==name).size==1;
| + | |
− | }
| + | |
− | | + | |
− | === Definition of Types ===
| + | |
− | So far we couldn't define Types within Xtend but had to define them using other techniques (ecore, Java, UML-profile, etc.).
| + | |
− | Defining tyoes within Xtend would be a great feature. Because it is much simpler and faster to write them in text.
| + | |
− | In addition we could define Type with logic (operations).
| + | |
− | A syntax could look like this:
| + | |
− | | + | |
− | type Entity extends Named {
| + | |
− | // simple attributes
| + | |
− | String name;
| + | |
− | Boolean isAbstract {
| + | |
− | private set(aValue)
| + | |
− | get : name.startsWith("Abstract");
| + | |
− | };
| + | |
− |
| + | |
− | // references
| + | |
− | Set<Entity> superTypes;
| + | |
− | Set<Features>* features; // asterisk means containment
| + | |
− | Set<Reference>* references subsets features;
| + | |
− |
| + | |
− | // operations
| + | |
− | doStuff(String x) : x+name;
| + | |
− | doMoreStuff(String x) {
| + | |
− | name := x;
| + | |
− | features += var f := new Feature{
| + | |
− | f.name:= x;
| + | |
− | ...
| + | |
− | };
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | === Template syntax ===
| + | |
− | We want to come up with a simple template syntax integrated into Xtend.
| + | |
− | Example:
| + | |
− | context Entity {
| + | |
− |
| + | |
− | toJava() :
| + | |
− | »package «packageName()»;
| + | |
− |
| + | |
− | public class «name» {
| + | |
− | «attributes.each(a|»
| + | |
− | public «a.type» «a.name»;
| + | |
− | «)»
| + | |
− | }«;
| + | |
− | | + | |
− | It's just a string literal with the xpand terminals '«' and '»'.
| + | |
− | In addition if you use these type of string literals, string concatenation is implicit.
| + | |
− | Under the hood we might come up with a special string type (for performance reasons), but it should be compatible to the oaw String type and therefore transparent to the user.
| + | |
− | | + | |
− | Files are opened thorugh extensions:
| + | |
− | | + | |
− | | + | |
− | generateCode(Entity e) :
| + | |
− | writeToFile(e.JavaFile(),e.toJava());
| + | |
− | | + | |
− | | + | |
− | Something like this...
| + | |
− | | + | |
− | ===Extensions overwrite semantics===
| + | |
− | Extensions with the same signature will overwrite Operations.
| + | |
− | Consider overwriting the toString() Operation (which is invoked on String concatenations) for arbitrary meta types.
| + | |
− | This will allow very readable templates.
| + | |
− | | + | |
− | | + | |
− | ===Optional parentheses for operations, functions, extensions without parameters===
| + | |
− | We should discuss if we want to make empty parentheses on invocations of operations optional.
| + | |
− | So that :
| + | |
− | my.operation()
| + | |
− | equals
| + | |
− | my.operation
| + | |
− | | + | |
− | | + | |
− | === Polymorphic Guards ===
| + | |
− | I (Sven) would like to discuss if we want to have the ability to specify
| + | |
− | guards on functions, extensions and operations.
| + | |
− | Example:
| + | |
− | context Entity {
| + | |
− | String javaName() {this.isAbstract} : "Abstract"+name;
| + | |
− | }
| + | |
− | | + | |
− | In addition I would like to use guards in a polymorphic context:
| + | |
− | | + | |
− | context Entity {
| + | |
− | String javaName() {this.isAbstract} : "Abstract"+name;
| + | |
− | String javaName() : name;
| + | |
− | }
| + | |
− | | + | |
− | The dynamic semantics are:
| + | |
− | | + | |
− | * First select all possible features (functions or extensions and operations), based on the name and the types.
| + | |
− | * Then order those features by parameter types (best match first).
| + | |
− | * For each feature
| + | |
− | * evaluate the guard
| + | |
− | * if it doesn't evaluate to true skip it
| + | |
− | * if it evaluates to true
| + | |
− | * make sure that there is no second feature with the same signature where the guard evaluates to true
| + | |
− | * if there is no such feature, we've found our feature -> success!
| + | |
− | * else throw new Exception("Unambigous feature ... more than one feature ... bla")
| + | |
− | | + | |
− | * if there are features, but the guards evaluate to false, return null:
| + | |
− | * if there is no feature, do "feature not found" (i.e. raising exception or invoking 'featureNotFound' operation)
| + | |
− | | + | |
− | The static semantics are straight forward: The guard must be of type boolean.
| + | |
− | | + | |
− | | valign=top |
| + | |
− | {| border=0 cellspacing=3 cellpadding=4
| + | |
− | ! bgcolor="Gainsboro" | OAW Navigation
| + | |
− | |-
| + | |
− | | bgcolor="GhostWhite" | [[OAW| Main Page]]
| + | |
− | |}
| + | |
− | |}
| + | |
− | | + | |
− | === Closures ===
| + | |
− | We'll have real closures, not the built-in stuff we have now.
| + | |
− | | + | |
− | Example:
| + | |
− | | + | |
− | myList.select(e|e.name == "test")
| + | |
− | | + | |
− | or
| + | |
− | {
| + | |
− | String myText := "test";
| + | |
− | (Attribute)=>Boolean myClosure := e|e.name==myText;
| + | |
− | myList.select(myClosure);
| + | |
− | }
| + | |
− | | + | |
− | alternatively make use of type inference
| + | |
− | | + | |
− | {
| + | |
− | var myText := "test";
| + | |
− | var myClosure := Attribute e|e.name==myText;
| + | |
− | myList.select(myClosure);
| + | |
− | }
| + | |
− | | + | |
− | declaration of select :
| + | |
− | | + | |
− | List<T> select<T>(List<T> this, (T)=>Boolean closure) {
| + | |
− | ...
| + | |
− | }
| + | |
− | | + | |
− | === Xpand Container ===
| + | |
− | We'll have a possibility to add a string to a previously defined "outlet"
| + | |