Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "RoadmapOAW5"

(Functions)
(Redirecting to OAW)
 
(49 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{| border=0
+
#REDIRECT [[OAW]]
| width=90% |
+
= Collection of features (rough) =
+
 
+
== Xtend ==
+
 
+
In Version 5 we want to improve some of the Xtend language concepts and features.
+
Codename is Xtend++ :
+
 
+
=== Imports ===
+
The import mechanism should be reworked, so that every import is explicit.
+
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. The token directly after the
+
import keyword defines which adapter to use.
+
 
+
==== 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, so that
+
imported stuff (types and functions) will be reexported.
+
 
+
Example:
+
 
+
myext1.ext
+
 
+
  foo() : 'foo';
+
 
+
myext2.ext
+
 
+
  import myext1 reexport;
+
  bar() : 'bar';
+
 
+
client.ext
+
 
+
  import myext2;
+
  fooBar() : foo()+bar();
+
 
+
 
+
=== Generics ===
+
We need full-fledged generics, which can conceptually be copied from Java's generics.
+
Maybe we can leave out some of the more advanced capabilities?
+
 
+
=== Closures ===
+
We'll have real closures, not the built-in stuff we have now.
+
Closure syntax:
+
 
+
  parameterList '|' expression-using-parameters-and-scope
+
 
+
Where parameter list must be typed, either implicitly or explicitly.
+
 
+
Example:
+
 
+
  // type of e is inferred from the declaration of the 'select()' function
+
  myList.select(e|e.name == "test")
+
 
+
or
+
  {
+
    String myText := "test";
+
    (Attribute)=>Boolean myClosure := e|e.name==myText;    // e is inferred from the declared type of the assignee
+
    myList.select(myClosure);
+
  }
+
 
+
alternatively declare the parameter types explicitly
+
  {
+
    var myText := "test";
+
    var myClosure := Attribute e|e.name==myText;
+
    myList.select(myClosure);
+
  }
+
 
+
 
+
==== Type signatures of functions ====
+
The syntax for of a function's type signature looks as follows:
+
 
+
  (parameterTypes)=>returnType
+
 
+
Examples:
+
 
+
  ()=>Object
+
  (String)=>Boolean
+
  (String, Entity)=>Entity
+
 
+
Example 2: declaration of higher-order functions using generics :
+
 
+
  List<T> select<T>(List<T> this, (T)=>Boolean closure) {
+
    ...
+
  }
+
 
+
=== Functions ===
+
 
+
Functions can be invoked either using the functional syntax or using the member syntax (operation like, aka extensions):
+
 
+
  myFunction(foo, bar) == foo.myFuntion(bar)
+
 
+
A function is declared as follows:
+
 
+
  (private|cached) ReturnType? functionName(declaredParameterList) guardExpression? : bodyExpression ;
+
 
+
Example:
+
  private doStuff(Entity this) name!=null :
+
      name+"Stuff";
+
 
+
The detailed semantics of how the polymorphic resolution works (what role guards play here) and is described in the upcoming section.
+
 
+
or
+
  (private|cached) functionName(declaredParameterList) guardExpression blockExpression
+
 
+
Example:
+
  cached makeAbstract(Entity this) {
+
      abstract := true;
+
      name := 'Abstract'+name;
+
      this;
+
  }
+
 
+
Block expressions are explained in their own section.
+
 
+
==== Polymorphic Resolution with signatures and guards ====
+
Usually polymorphism is based on the types of parameters. The same applies for Xtend++.
+
In contrast to e.g. Java we use the dynamic types (actual types at runtime) of a given set of parameters in order to find the function which
+
best fits (has the most specific declared paramter types).
+
 
+
Example:
+
given the following two functions
+
 
+
  foo(String x) : "string";
+
  foo(Object o) : "object";
+
 
+
this assertions can be made:
+
 
+
  foo('S') == "string"
+
  foo(34)  == "object"
+
  foo((Object)'S') == "string" // would be "object" in Java
+
+
In addition to these concept, commonly known as "multiple dispatch" or "multi method", we introduce guards which can be used to controll the resolution based on the state of a given object not only the type.
+
 
+
Example:
+
 
+
  foo(String x) x.length>5 : "long";
+
  foo(String x) : "short";
+
+
this assertions can be made:
+
 
+
  foo('honolulu') == 'long'
+
  foo("bar") == 'short'
+
 
+
The semantics are as follows:
+
 
+
* First select all possible features (functions and operations), based on the name and the given parameter types.
+
* Then order those features by parameter types (best match first).Those functions with the same parameter type should be order so that the ones having a guard defined come first.
+
 
+
pseudo code
+
 
+
  for (Feature f : features)  {
+
      if (f.hasGuard()) {
+
        if (f.guard.evaluate())
+
            return f; // return the feature where the guard evaluates to true
+
      } else {
+
        return f; // return the feature without a guard
+
      }
+
  }
+
  return null; // no invocation
+
 
+
* if there are features, but the guards evaluate to false, return null:
+
 
+
The static semantics are straight forward:
+
* The guard must be of type boolean.
+
 
+
====Extensions overwrite semantics====
+
Functions and Operations can be overwritten.
+
The precedence is based on th order of imports.
+
Functions from later declared imports overwrite functions introduced before.
+
Local functions overwrite imported functions.
+
Consider overwriting the toString() Operation  (which is invoked on String concatenations) for arbitrary meta types.
+
This will allow very readable templates.
+
 
+
==== Sticky Extensions ====
+
Extensions are accessible with a static scope. Unfortunately once an object leaves that scope a function (overwriting an operation) is no longer available,
+
so the operation implementation would be used.
+
We need a way to "attach" functions to objects, so that we can effectively "wrap" objects and add new functionality to them.
+
 
+
We have two different ideas of how this could be done:
+
1) adding a stickedTo keyword to the first parameter of an extension:
+
 
+
toString(stickedto Entity this) : "foobar";
+
 
+
for each Entity which has been created within a scope where such a sticky extension is declared, the to String() extension will be used for this object.
+
If an object has not been created in such a scope, the sticky function will only be used while the object is in that scope.
+
 
+
 
+
2) adding an extension explicitely to an object:
+
 
+
TO BE CONTINUED
+
 
+
=== Code blocks ===
+
 
+
A code block is the replacement for chain expressions ( a-> b-> x) with the additional features:
+
* provides variable declarations (Expression returning the assigned value)
+
 
+
It's something like a pseudo imperative syntax (but still is an expression!).
+
 
+
Variables are assign-once!
+
 
+
Example:
+
 
+
  myExtension(String stuff) {
+
    var x := stuff.length();
+
    if (x>56)
+
        "Foo"
+
    else {
+
        "Bar";
+
    }
+
  }
+
 
+
A code block is itself an expression consisting of a list of expressions.
+
It returns the value returned by the last expression.
+
 
+
It is possible to overwrite the scope.
+
Example:
+
 
+
  doStuff() {
+
    var x := "Foo";
+
    {
+
      var x:= "Bar";
+
      x;
+
    }
+
  }
+
 
+
will return "Bar"
+
 
+
=== 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.
+
They return the assigned value.
+
 
+
==== Operator Overloading ====
+
There will be predefined operators which can be used instead of the usual function invocation syntax if there is an operator for a name and a specific number of parameters.
+
 
+
Some examples:
+
 
+
add(Object a, Object b) => a + b
+
subtract(Object a, Object b) => a- b
+
not(Object a) => !a
+
 
+
...
+
 
+
 
+
==== 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.
+
 
+
The scope of the caching is per execution context, which can be reused in several invocations?
+
+
Examples:
+
 
+
  var paramPerOperationAndName := new Parameter cachedwith op,name {
+
      this.name := name;
+
      type := aDatatype;
+
  }
+
 
+
  var localSingleton := new Foo cachedwith {
+
      stuff := "bla";
+
  }
+
 
+
==== cross referencing ====
+
 
+
We need a way to specify cross references within a declared 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 Entity as localRef {
+
      // x is not visible here, because the right hand expression has not been evaluated so far.
+
      // localRef holds a reference to the created but not yet initialized entity.
+
        name := "Person";
+
        references += new Reference {
+
            name := "partner"
+
            type := localRef
+
        }
+
      }
+
 
+
=== XString (Template syntax) ===
+
We want to come up with a special datatype calle XString, which has a special literal syntax (like Xpand template syntax) and is mutable and streamable.
+
 
+
Example:
+
  toJava(Entity this) :"""
+
    package «packageName()»;
+
     
+
      public class «name» {
+
        «FOREACH attributes AS a»
+
        public «a.type» «a.name»;
+
        «ENDFOREACH»
+
      }""";
+
 
+
It's just a string literal with the xpand syntax within. The terminals '«' and '»' should be configurable (or there should be an alternative at least).
+
 
+
The FILE statement will be removed.
+
Files can be opened through extensions:
+
 
+
  generateCode(Entity e) :
+
    writeToFile(e.JavaFile(),e.toJava());
+
 
+
==== Container (NOT CLEAR HOW THIS COULD WORK) ====
+
Because XStrings are mutable and are converted to a string late, it is possible to create a tree structure containing XStrings, where
+
you can add XStrings (or normal Strings) later on.
+
 
+
Example:
+
  toJava(Entity this) :"""
+
      package «packageName()»;
+
      «imports()»
+
 
+
      ...
+
  """;
+
 
+
  cached imports(Entity this) :"""
+
      import java.util.*;
+
  """;
+
 
+
... to be continued (and cleaned up;-))
+
 
+
 
+
=== 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.
+
 
+
Example:
+
  // The following expression will return null:
+
  if (false) "Holla"
+
 
+
===No Checks anymore===
+
Checks used to provide a declarative way of specifying constraints on types.
+
We will come up with a framework to do the same thing, so a constraint can be written like so:
+
 
+
  import assertion::Extensions;
+
 
+
  check(Entity this) abstract :
+
      error("The abstract entity "+name+" has no subclasses.",
+
            subClasses.notEmpty);
+
 
+
This would be the replacement for
+
 
+
  context Entity if abstract
+
      ERROR "The abstract entity "+name+" has no subclasses." :
+
      subClasses.notEmpty;
+
 
+
No big difference I think, but we don't need to introduce a whole new concept (checks).
+
 
+
In addition it is now possible to write hierarchicly structured constraints which depend on each other:
+
  check(Property this) {
+
      dev column := findTable(entity()).columnForName(columnName());
+
      if (error("No corresponding column found ",
+
                column!=null) {
+
          error("The type does not match",
+
                column.type == this.type.sqlType())
+
      }
+
  }
+
 
+
Moreover one can have a name for a constraint like this (only the 'check' prefix is needed)
+
 
+
  checkTableExists(Entity this) :
+
      error("No corresponding table exists ",
+
                findTable(this)!=null);
+
 
+
looks and is similar to what xunit does. And it's a good idea to have something like XUnit for our language as well.
+
 
+
=== Definition of Types (later) ===
+
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;
+
                      ...
+
                  };
+
  }
+
}
+
 
+
MV: I agree that this is not the most urgent feature.
+
 
+
=== BK added --- To be discussed ===
+
==== Add private keyword to XPand ====
+
This is useful for marking Definitions in Xpand-Files as Private-API, especially useful when using AOP-features. Otherwise the whole generator is public API which is not intended in most cases
+
 
+
SE: We don't have "Xpand definitions" anymore. We have functions with XString expressions (which look the same).
+
As functions have a private keyword, I think your requirement is met.
+
 
+
==== AOP for Checks ====
+
When modifying an expression using AOP, there might be the situation that a check is no longer valid. It has to be modified as well
+
 
+
SE: We can't modify expressions using AOP. We just can hang an Advice around a function call.
+
I don't understand what you mean by, checks have to be modified.
+
 
+
== XPand ==
+
=== PF added --- to be discussed ===
+
==== Add a FOLDER keyword ====
+
In order to create empty directory structures, it would be nice to have a FOLDER keyword.
+
Syntax:
+
«FOLDER expression»
+

Latest revision as of 08:59, 9 December 2008

Redirect to:

Back to the top