December 2011 : Xtend 2.2 has been released.
Embrace Java ...
Java is a great platform and also the language has some nice features. Xtend is not meant to replace Java all together but to be a convenient alternative in situations where Java doesn't shine. Therefore Xtend ...
... but kill the noise ...
In contrast to Java, Xtend removes unnecessary noise. Reducing code to the minimum not only helps you type less, but more important makes the code more readable and maintainable. These features avoid the boilerplate:
- type inference
- property access
- better defaults
- operator overloading Updated !
- everything is an expression Updated !
... and add some sugar!
Simply improving on Java by removing the noise is already very helpful, but Java also lacks some important language features. Therefore Xtend adds the following features, which you will love once you got your hands on them:
Download Installation and first steps
Option 1: Download Eclipse
Option 2: Install the Xtend SDK
If you already have a running Eclipse including the Java Development Tools (JDT), you can either use the Eclipse Marketplace Client in your IDE or click on the following link to install the Xtend SDK.
Documentation Getting started
The user guide provides detailed information about the various language concepts.
An introductory article we wrote for the PragPub Magazine in December 2011. It covers a walkthough of the language and outlines the motivations behind its design.
Tutorial
If you want to get your hands on it, we recommend to materialize the tutorial example using Eclipse's example wizard. To do so in the IDE click:
File->New->Example...
The project consists of a bunch of Xtend files. Each of them illustrates a certain language feature and they are named accordingly. Those sample files contain a lot of working code snippets with some explanation in the comments.
Just try it, it's straight forward.
Latest Release Xtend 2.2 - December 2011
- Standalone Compiler
- A standalone compiler allows to translate Xtend files to Java source code. No Eclipse required!
- Maven Support
- A Maven plugin for standalone compilation as well as the standard lib is available. Read more »
- Reworked Exception Handling
- It's now possible to declare a throw clause just like in Java. Unlike in Java, checked exceptions don't need to be declared or caught.
- Constructors, Static Members, Field Initializer
- Launch Shortcuts
- Launch shortcuts for main methods and junit tests.
- Open Type Hierarchy
- Quick Outline shows inherited members
- Like in JDT the quick outline can optionally show inherited members.
- More Quick Fixes
- Quick fixes for implementing abstract methods, adding imports, and more.
- Better Content Assist
- Content Assist for overriding methods and implementing constructors from supertypes.
Embrace Java at least the good parts!
Xtend compiles to readable Java code
Instead of generating bytecode directly, you get Java source code you can actually look at and debug through if you want.
Compilation is done incrementally whenever you save a file in Eclipse just like with Java. The tooling makes sure you can navigate between the generated code and the original Xtend code even when it is called from Java.
State of the art Eclipse tooling
Xtend was designed and developed together with the IDE support.
The Eclipse support is deeply integrated with Java's development tools in Eclipse, such that the development experience is as seamless as possible.
The Eclipse plug-in comes with almost all the features you are used to from the Java IDE :
- syntax coloring
- content assist
- rename refactoring
- organize imports
- quick fixes
- rich hover
- outline views
- navigation (go to declaration, find references, etc.)
- open type
- incremental compilation
- bracket matching
- mark occurences
- ... and many more
Java type system It's the one you know!
Static typing is great! It allows for better static analysis and much better tooling based on the available type information.
Although Java's type system might not be perfect, it is widely used and well understood.
That's why Xtend reuses just everything about it. In contrast to Java, however, one seldomly has to write types down because of Xtend's type inference.
// qualified names java.lang.Object // primitives boolean, int, long, char, ... // arrays String[] // generics List<? extends CharSequence> java.util.Map<String,String>
Xtend just does classes and nothing else
Interface definitions in Java are already nice and concise. They have a decent default visibility and also in other areas there is very little to improve. Given all the knowledge and the great tools being able to handle these files there is no reason to define them in a different way. The same applies for enums and annotation types.
That's why Xtend can do classes only and relies on interfaces, annotations and enums being defined in Java. Xtend is really not meant to replace Java but to modernize it.
Kill the noise because it hurts in the eye
Type inference Get rid of the redundancy
A lot of the information written down in a Java file is actually technically redundant. In the following Java example, the type of the variable could already be determined from the right hand side.
//Java List<String> names = getTheListOfNames()
It's sometimes a good idea to write the type nevertheless, but most of the time it's just redundant noise and distracting the reader.
Xtend doesn't force you to write the type everywhere, but you still can, if you want.
- Variable Declarations
val names = getTheListOfNames() val List<String> names = getTheListOfNames()
- For-Loops
for (name : getTheListOfNames()) // do something with name for (String name : getTheListOfNames()) // do something with name
- Return types
def getTheListOfNames() { newArrayList("Tomte","Pippi","Carlson") } def List<String> getTheListOfNames() { newArrayList("Tomte","Pippi","Carlson") } - Closures
getTheListOfNames().map( name | "Mr. "+name ) getTheListOfNames().map( String name | "Mr. "+name )
More noise reduction
Property access
Getter methods can be called using the Java property syntax. For example, you can write
person.name
instead of
person.getName()
This also works great for setters and assignments.
person.name = "Foo"
is equivalent to
person.setName("Foo")
Optionality
Parenthesis for method invocations are optional, if the method does not take any arguments.
obj.compute
instead of
obj.compute()
Semicolons are optional and even the return keyword doesn't need to be specified. The result of the last expression in a method definition is treated as the implicit return value. Read more »
Operator Overloading
Operators in Xtend are just a shortcut syntax for method invocations. This means that you can for instance use arithmetic operators when working with numeric types like BigDecimal.
Also this is handy when using concatenation on collections:
val apples = newArrayList(new Apple()) val oranges = newArrayList(new Orange()) val fruits = apples + oranges // fruits is now of type Iterable<Fruit>
The user's guide contains a list of all operators, their precedence, and associativity. Each operator is mapped to a special method name starting with prefix 'operator_'.
The standard library already enhances some types from Java's SDK with operators through extension methods.
Everything is an expression
In Xtend everything that looks like a statement is actually an expression. Even a block is just an expression. This allows for using them in places where it would just not be allowed in Java. Here's an example:
val data = try {
fileContentsToString('data.txt')
} catch (IOException e) {
'data.txt'
}
In Java it wouldn't be possible to use a try-catch on the righthand side of an assignment. Since it's a statement it doesn't result in a value. In Xtend however it's valid code and the result would be either the result of fileContentsToString or the string 'data.txt' (in case an IOException was thrown).
By the way: Xtend doesn't force you to catch or declare exceptions. All exceptions are treated like runtime exceptions. Read more »
Where is the sugar? the cool new features
Extension methods
Xtend got its name from the great support for extending existing types using extension methods. Extension methods allow to add new methods to existing types without touching them. In Xtend local methods are always available as extension methods and are available on the member scope of the first argument's type. Given the following method definition ...
/**
* will be available as extension method locally.
*/
def getFullName(Person p) {
p.firstName + " " + p.lastName
}
you can write
myPerson.fullNamewhich will be translated to and is the same as
this.getFullName(myPerson)So it's basically syntactic sugar, but it reads better and the content assist in the IDE can be much more helpful.
Static extensions
Xtend puts some useful extension methods on the scope by default. They are mostly higher-order functions for Java's collection library. However, you can use any existing static method as an extension method if you use the keyword extension in the static import:
import static extension java.util.Collections.*
Extension methods and injection
The real fun begins when you use the extension keyword on fields together with some dependency injection framework (we recommend Guice):
@Inject extension PersonExtension /* no field name */
def example(Person p) {
// calls PersonExtension#getFullName(Person) on
// the injected instance
println( p.fullName )
}
This way you can define layer-specific libraries for your domain model, without poluting the model. And the best thing is, you can easily change the implementation without touching the code. All you need to do is to change the configuration of the dependency injection container.
If you wonder how you get polymorphism into this, that's what multiple dispatch is for.
Multiple dispatch no more visitors!
Everybody knows the visitor pattern.
In essence, the visitor allows to add new virtual functions to a family of classes without modifying the classes themselves
Wikipedia, November 2011
The visitor pattern is actually a work-around for the lack of multiple dispatch. By default Xtend (like Java) links overloaded methods at compile time based on the static types of the arguments:
def example() {
val Shape s = new Rectangle()
println(s.label) // prints "some shape"
val Rectangle r = new Rectangle()
println(r.label) // prints "a rectangle"
}
def label(Shape s) {
"some shape"
}
def label(Rectangle r) {
"a rectangle"
}
However, Xtend also allows for a set of overloaded methods to do the dispatching based on the actual runtime argument types. All you need to do is add the dispatch keyword to the methods:
def example() {
val Shape s = new Rectangle()
println(s.label) // prints "a rectangle" !!!
val Rectangle r = new Rectangle()
println(r.label) // prints "a rectangle"
}
def dispatch label(Shape s) {
"some shape"
}
def dispatch label(Rectangle r) {
"a rectangle"
}
Note, that the multiple dispatch behavior is compiled into the declaration, so it will always behave the same no matter whether it's called from Java or Xtend. Read more »
Closures finally!
Closures are the single most demanded feature for Java. To collect all the names from persons in a list in in Java, you would typically write:
//Java
List<String> names = new ArrayList<String>();
for (String name : persons) {
names.add(name);
}
In Xtend you can just use the map extension method, which is available on every instance of java.lang.Iterable and pass it a closure :
persons.map( p | p.name )
Although closures have a Java compatible type, Xtend provides a nicer notation for function types. The following example defines a closure which would be useful to filter a list of persons by a specific name.
val (Person) => Boolean predicate = [ person | "Hans" == person.name ]You usually don't have to write the types for functions that often, but would write instead:
val predicate = [ Person person | "Hans" == person.name ]Such a function can be passed to the extension method Iterable.filter((T) => Boolean):
persons.filter(predicate)
Closures are helpful in many different scenarios. For instance, in combination with extension methods they allow to define nice builder APIs:
html [
head [
title [$("XML encoding with Xtend")]
]
body [
h1 [$("XML encoding with Xtend")]
p [$("this format can be used as an alternative to XML")]
// an element with attributes and text content
a("http://www.xtend-lang.org") [$("Xtend")]
// mixed content
p [
$("This is some")
b[$("mixed")]
$("text. For more see the")
a("http://www.xtext.org")[$("Xtext")]
$("project")
]
p [$("some text")]
// content generated from arguments
p [
for (arg : args)
$(arg)
]
]
]
Switch expression a pragmatic approach to pattern matching
The switch statement in Java is a relict from C and has strange and errorprone semantics. At the same time it is almost useless in today's programming. Xtend comes with a switch expression, which is very convenient and different from what a switch means in Java:
- switch on anything using equals
- no fall through!
- it checks in the defined order
- supports type guards
Type guards
Type guards let you switch (or match) for types, which is much nicer and less errorprone than the usual lengthy instanceof-cascades we write in Java. In practice it is almost as useful as pattern matching but without introducing all the additional complexity.
In the following example we have a type hierarchy, consisting of a type Shape which is extended by Rectangle and Circle. We use the switch with type guards to create a descriptive string for the different shapes. Note, that right after the type guard, the variable shape is automatically typed to the respective type. No down casting is neccessary and no ClassCastExceptions can ever happen.
val Shape shape = ...
switch (shape) {
Rectangle case shape.width == shape.height :
"Square ("+shape.width+")"
Rectangle :
"Rectangle ("+shape.width+" x "+shape.height+")"
Circle :
"Circle ("+shape.diameter+")"
default :
"Don't know"
}
Template expressions with a unique way of whitespace handling
Java's support for string literals and string concatenation is very limited. It lacks multi-line string literals and although the string concatenation using the plus operator is better then using method invocations it's often recommended to use the latter.
In Xtend all string literals can span multiple lines by default. Also you can use single quotes or double quotes, to minimize the need for escape sequences. If you have some text containing a lot of double quotes better use the single quoted string literal and vice versa:
val msg = 'This is some multi-line
text with "double quotes" in it'
Template expressions can do more than plain multi-line strings. They allow interpolating expressions and support a FOR-loop and an IF-condition. The most compelling feature is however the automatic whitespace handling!
Whitespace and Greyspace
A typical problem in text generation is, that you want to generate nice looking output with proper whitespaces and indentation. However, at the same time you want the template to be nicely indented. Therefore until now, templates either looked great and the output looked bad, or vice versa.
Xtend can do better. It detects what whitespace is meant to indent the template code and what is meant to indent the output code using an algorithm which feels surprisingly intuitive. To help developers understand how Xtend handles whitespace, the editor supports coloring for the different kinds of whitespace. Read more »
Hello World using JAX-RS and templates
A small example using JAX-RS API. The greyspace will go into the result.
Exceptional DSL support When APIs are not sufficient
A domain specific language (DSL) is a small executable language solving a particular problem. Imagine you are working on a web framework. A typical aspect is to map http requests to controller methods or other resources. Instead of configuring that in an untyped, clumsy XML file you could define it like this:
GET /index -> StartController.index()
GET /list/Persons -> PersonController.list()
GET /edit/Person/{id} -> PersonController.edit(id)
Wouldn't it be cool to have all the great tool support you see in Xtend, including specific validations, which for instance would warn you about certain unreachable mappings? Also the references to classes and methods should be statically typed, including content assist and even cross-language rename refactoring would be extremely nice. With Xtend and it's support for DSLs this is an easy thing to do.
Xtend is built with
,
Eclipse's language and IDE development framework. With that tool
chain you can build such a request mapping language in no time.
It will support you to embed Xtend’s expressions, Java types and
annotations everywhere you want. You can reuse the whole type
inferrer, compilation and editor support. There's even an
interpreter allowing for execution of any DSLs at runtime.
Have a look at
's
website to understand how to do that. You'll be amazed how simple
it is to build compiling, statically typed domain-specific
language with full blown Xtend expressions.
Here's another example. A DSL for Behavior Driven Design :
History The Origins.
The first version of Xtend was developed in 2004. At that time it acted as a small functional language used to add functionality to existing class hierarchies through extension methods. It was merely used in the context of code generation and model transformation and shipped as part of the Xpand project at Eclipse. This version is not further developed but maintained by itemis.
Although Xtend was quite popular in the model-driven community, the language fall short on some important aspects, such as performance and tooling. Also conceptually there were a couple of shortcuts taken which made the language not as widely applicable as wished. This had to be fixed.
In 2008 the original designer of Xtend and Xpand formed a team to work on Xtext. Xtext eases the development of domain-specific languages but also of programming languages like Xtend. It took the team three years until it was ready to start working on Xtend 2, which is now based on Xtext.
Today (December 2011) Xtend 2.2 is released and this website tells you what it is.
Future Plans What's Next?
With the recently released version, Xtend is now a fully working, readable and convenient alternative to Java classes. The editor is close to what Eclipse's Java tooling can do and in some aspects even better.
Here's a list of things we want to focus on during the next months:
-
Even tighter integration with Eclipse's Java tooling.
Whenever you click on a Java class derived from Xtend, being it in a search result, in a type hierarchy, junit test results or within the debugger. The original Xtend source will be opened. Follow this bugzilla to stay tuned.
Debugging.
We are working on support for JSR-45, which is already supported by JDT. With that you'll be able to easily switch between stepping through Xtend and the derived Java source. This will also make sure the stacktraces contain proper xtend entries.
Further editor improvements.
Although the editor and the rest of the DIE is already quite advanced, there are still a lot of cool features we want to work on. Among them are useful refactorings such as extract method or extract local variable. But also things like JavaDoc support will be added.
-
Nullsafety.
Finally, the JDT got control-flow analysis for @Nullable types. This is an important feature and we will definitely work on supporting this in Xtend as well.
Quality and Performance.
We'll further improve the performance of the static analysis, type inference and compilation, to make sure people experience a super short turn-around.
Move Xtend to its own project at Eclipse.
Today Xtend is released as part of Xtext. Although it's more or less the same team working on both technologies we feel that it's time to move Xtend to its own project at Eclipse.