Monday, March 09, 2015

Ganztägiger Xtext-Workshop auf der SE 2015 in Dresden, 17. März

[EN] my colleague Stefan and I will give a full-day Xtext workshop At the SE 2015 conference in Dresden. The spoken language will be German.

[DE] Mein Kollege Stefan und ich geben kommende Woche einen ganztägigen Xtext-Workshop auf der Konferenz SE 2015 in Dresden. Auf dem Workshop vermitteln wir ein solides Verständnis von Xtext und allen relevanten Konzepten. Dieser Workshop ist die perfekt Vorbereitung um ein Projekt mit Xtext zu beginnen, diesem beizutreten, oder sein Hintergrundwissen zu verfestigen. Natürlich werden wir auch auf die mit Xtext 2.8 neu verfügbar gewordenen Features eingehen. Zur Teilnahme ist die Anmeldung über die Konferenz-Webseite erforderlich.

Der Titel ist Xtext - Werkzeugunterstützung für bestehende sowie eigene Sprachen einfach entwickeln und Folgendes ist der Inhalt:

Eine Vielzahl von formalen Sprachen haben ihre Daseinsberechtigung, da ihre Eigenschaften oft speziell zugeschnitten sind auf ihre Anwendungsdomäne, das Vorwissen ihrer Anwender und eventuell ein oder mehrere Zielplatformen.

Mögliche Motivationen für das Verwenden einer bestimmten - oder sogar dem Designen einer eigenen Sprache können sein:
- Erhöhung der Produktivität der Anwender durch ein hohes, direkt auf die Anwendungsdomäne zugeschnittenes Abstraktionsniveau
- Senkung der Einstiegshürde durch das Verwenden einer den Anwendern bereits vertrauten Syntax
- Vermeiden von Anwenderfehlern durch Vermeidung unnötiger Freiheitsgrade in der Sprache
- Reduzierung der benötigten Vorkenntnisse von Anwenden durch Spezialisierung auf deren Domäne und dem Weglassen von nicht benötigten Konzepten
- Frühes erkennen von Anwenderfehlern durch statische Analysierbarkeit von Dokumenten
- Unterstützung mehrerer Zielplatformen durch Abstraktion über selbige
- Forcierung eines Denkmodells
- Forcierung einer gewünschten Softwarearchitektur

Unabhängig von der Wahl der Sprache ist der Bedarf für gute Werkzeugunterstützung: Genau so, wie heutzutage von einer Textverarbeitung eine Rechtschreibkorrektur erwartet wird, darf von einer Entwicklungsumgebung exakte Syntaxprüfung, statische Validierung, context-sensitive Vervollständigung und vieles Mehr erwartet werden.

Xtext hat sich als de­facto Standard zur Erstellung von Werkzeugunterstützung für formale, textuelle Sprachen etabliert. Zur Werkzeugunterstützung zählen neben einem “intelligenten” Editor mit IDE­-Integration, Syntax­-Highlighting, Content Assist, live­Validierung etc. Generatoren und Interpreter. Hierbei hat Xtext den nötigen Arbeitsaufwand zur Erstellung selbiger derartig gesenkt, dass eigene Sprachen in vorher undenkbaren Szenarien praktikabel werden.

Teilnehmer dieses Tutorials werden in Vorträgen die relevanten Konzepte kennenlernen sowie eigene Erfahrung mit Xtext anhand von Übungsaufgaben sammeln. Ziel des Tutorials ist es, die Teilnehmer zur eigenständigen Entwicklung von domänenspezifischen Sprachen und Codegeneratoren zu befähigen.

Zentrale Themenbereiche sind: 
• Überblick über Xtext
• Die Xtext Grammar Sprache • Integration mit EMF
• Überblick über Xtexts Architektur
• Modell-­Validierung
• Scoping: Linking und mehr
• Code Completion
• Template Proposals
• Formatting (Pretty Printing)
• Codegenerierung mit Xtend
• Erstellung von ASTs: Actions in der Grammatik 
• UI hooks (Quickfixes, Coloring, Outline, etc.)
• Allgemeine Strategien zur Problemlösung
• Ausblick

Tuesday, November 18, 2014

New Eclipse JUnit Feature: Run Subtrees of Tests Individually, e.g. from Parameterized Tests

In Eclipse, the JUnit view nicely visualizes execution status and results of JUnit tests. JUnit tests usually are Java classes with test methods or Java classes annotated with @SuiteClasses, which compose multiple other test classes or suites.

But JUnit is more powerful than that. It allows you to implement custom test runners. Those test runners are responsible for creating a tree structure of test descriptions. Later the runner needs to execute all leafs of that tree as test cases.

A node in this tree of tests is not necessarily backed by a Java class, as it is for test suites. It can be something purely virtual. JUnit itself ships with a test runner for which this is true: org.junit.runners.Parameterized.

The screenshots above shows a Parameterized test on the left-hand-side and the Eclipse JUnit View (after the test has been executed) on the right-hand-side. The method parameters() returns a list of test data sets and the Parameterized runner will call the constructor of this test class for each data set. Consequently, the number of constructor parameters must match the number of items in each data set. For each data set, all test methods are executed and what we get, effectively, is a matrix test.

In the screenshot of the JUnit view we can see how the Parameterized runner presents the test matrix as a tree: The test class itself is the root node, every data set is a subtree and every entry of the test matrix is a leaf.

As of now (Eclipse Mars M4), it is possible to run individual subtrees by choosing "run" from the context menu. This effectively means to execute a row from the test matrix.

Additionally, it is now possible to run a single column from the test matrix by running a single method from a Parameterized test.

Note that in the picture on the left-hand-side I'm explicitly clicking on the method's name. Clicking elsewhere would execute all test methods from the class.

The new mechanism to filter down test description trees can achieve this without being specific to the JUnit's Parameterized runner: The filter first extracts the leading part of the test desription's name which is a valid Java identifier. The test is executed if this leading part exists and if it equals the to-be-executed method's name.

I would like to thank NumberFour for having me implement this fix specifically for Xpect. Gratitude also goes to itemis, my employer, who gave me the time to generalize and contribute the fix to Eclipse JDT. Also I would like to thank the JDT team for accepting the contribution.

Tuesday, September 03, 2013

Introduction to Xpect

Xpect is a framework that helps you to test, discuss, and explain Xtext languages.

Before I start, I'd like to tell a bit about me, since it gives a context on why I created Xpect. As you may know, I've been a committer at the Eclipse Xtext project since January 2009. Besides working on Xtext (and Xtend), I have been applying this technology in several customer projects: Project sizes varied from man days to man years and my role varied between designing a language and providing professional support for technical challenges.

All projects have in common that we wanted to develop Xtext languages. Sometimes we were free to design syntax and semantics from scratch and sometimes we were bound to a language specification. In most projects we needed to...

  • have automated tests for our language tooling.
  • discuss design and implementations decisions.
  • explain the language and tooling to fellow developers and prospective users.
  • allow our implementation to be reviewed regarding completeness and correctness. I.e. pass an acceptance test.
  • set up test stubs for fellow developers to implement tests.

To comply with these use cases I found myself writing plenty of JUnit tests and creating many example documents of the language, often with redundant content. I could not use the JUnit test to explain and discuss the language with others, since the Java code was distracting them from what I wanted to show. Furthermore, I was annoyed that I could not use the language's Xtext editor to craft test data, since the test data was embedded in string literals in the test's Java code. Also, when I wrote example documents, I found myself inserting comments to explain the language: "This expression will evaluate to xxx", "This statement causes error yyy", "This cross reference links to zzz", etc.

The idea arose to converge test cases and example documents: What if I could embed test expectations within comments inside my example documents? What if I could find a format for these comments so they're both human understandable and automatically verifiable by a test suite?

Xpect realizes this idea. The version introduced by this blog post or older versions are actively being used by in-house projects, several customer projects, and open source projects such as Xcore and Spray.

One File, Two Languages

What you can see in the screenshot above is a JUnit that has been executed and which passed. The test class is org.domainmodel.tests.validation.DMValidationTest and it has executed a file named test1.dmodel.xt. The file defines two test cases, one called warnings and one called errors. On the right hand side you can see the file's contents in an editor. The editor generically combines support for two languages: First, the language that is being tested. In the screenshot this is the Domainmodel language (*.dmodel) which ships with Xtext as an example language. Secondly, the editor supports the Xpect language (*.xt). The two languages do not interfere with each other since the Domainmodel language ignores text insides comments and the Xpect language ignores text that doesn't start with an "XPECT" keyword. The editor applies a greenish background color to Xpect syntax.

Let's take a closer look at the Xpect syntax. At the beginning of test1.dmodel.xt, there is a region called XPECT_SETUP. It holds a reference to the JUnit test that can run this file. Further down we find test cases such as:

// capitalized property names are discouraged

// XPECT warnings --> "Name should start with a lowercase" at "Property1"

Property1 : String

The first line is an optional title for the test. warnings references a JUnit test method (implemented in Java) and the part following the --> is the test expectation, which is passed as a parameter into the JUnit test method. The test method can then compare the test expectation with what it calculated to be the actual test value and pass or fail accordingly. For this example, the test expectation is composed of the error/warning message (Name should start with a lowercase) and the text that would be underlined by the red curly line in the editor (Property1). For this validation test, the XPECT statement collects all errors or warning occurring in the next line. A feature you might find very useful is, that the XPECT statement consumes error or warning markers: An expected error or warning will not be shown as an error marker in the Eclipse editor.

Synchronize Expectations and Implementation

The fact that Xpect uses textual expectations and embeds them into DSL documents opens the door for another awesome (IMHO) feature: Using the Eclipse comparison editor to inspect failed tests and to fix out-dated test expectations:

When one or more tests fail and you want to fix them, it is crucial to quickly get an overview over all failed tests. With Xpect you can not only see all failed test cases from one file in a single comparison editor, but there are also no assert statements which sometimes prevent execution of follow-up assert statements and thereby hide valuable hints on why the test failed. The comparison editor, as the name suggests, also lets you edit the test file.

Reusable Test Library

In Xtext projects, there are several scenarios where it is reasonable to have test coverage. The validation test I explained earlier in this article is just one of these scenarios. Xpect ships the Java-part for such tests as a library. There is also an example project that demonstrates their usage.

There are test for:

  • The parser and Abstract Syntax Tree (AST) structure (demo only, no library).
  • Code generators implemented via Xtext's IGenerator interface.
  • Validation: Test for absence, presence, message and location of errors and warnings.
  • Linking: Verify a cross reference resolved to the intended model element
  • Scoping: Verify the expected names are included or excluded from a cross references's scope.
  • ResourceDescriptions: Verify a document exports the intended model elements with proper names.
  • JvmModelInferrer: For languages using Xbase, test the inferred JVM model

There will be more tests in future versions of Xpect.

Support for Standalone and Workspace Tests

UI-independent parts of Xtext, such as the parser, can operate standalone (i.e. without OSGi and Eclipse Workspace). The same is true for Xpect. For capabilities where Xtext does not require OSGi or an Eclipse Workspace, Xpect does not do so either. Consequently, Xpect tests can be executed as plain JUnit test or Plug-In JUnit tests.

Since both scenarios require different kinds of setups, both can be configured separately in the XPECT_SETUP section. When executed as plain JUnit test, the ResourceSet-configuration is used and for Plug-In JUnit tests, the Workspace-Configuration is used.

The screenshot also illustrates how an additional file can be loaded so that it is included in the current ResourceSet or Workspace during test execution.

Suites: Combine Tests in the Same File

When explaining a specific concept of a language, it is helpful to look at the language concept from all sides: This is the valid syntax, these scenarios are disallowed, this is how cross references resolve, this is how it is executed, etc. So far, testers were required to create a new test file for every technical aspect. With Xpect test suites, however, it is possible to combine the Java-parts of various tests into a single test suite.

The test suite XtextTests combines several tests so that in CombiningMultipleTests.dmodel.xt test methods from all these tests can be used. This allows to group tests by language concept.

Works with CI Builds

Xpect tests have proven to run fine with Maven, Tycho, Surefire, Buckminster and Jenkins. No special integration is necessary since Xpect tests run as JUnit tests.

Source & Download

You can find a link to the update site at www.xpect-tests.org. The source code and an issue tracker are on the github project page.

Thursday, April 25, 2013

Probes or How to Analyze Application State in a Profiler

Disclaimer: I'm not affiliated with Yourkit, but I am grateful for their free licenses for open source projects. I've been using Yourkit for my work on Xtext and Xtend.


Introduction

Improving the performance of an application can be a challenging thing to do. As a developer, you usually have some immediate ideas of what are the performance bottlenecks. However, as Ed said in his presentation at EclipseCon North America 2013, "Don't trust yourself, don't trust your friends, and don't even trust me."

I fully approve his message. Why? Experience shows there is truth in this statement.

If trust doesn't work, we need facts: We need to measure. We need to measure how much time it takes to execute our program for specific tasks. Two tools probably come to your mind as you read this:

  • java.lang.System.nanoSeconds(): This simple but useful method gives you access to a decently precise time stamp at any time. You can call this method from your own code and calculate and report the time for what every your desire. But there's a catch: You need to modify the code that you want to inspect, which you sometimes can't do because the code is part of a library/framework or you just don't want to pollute the code.
  • A Profiler (such as Yourkit): This powerful tool lets you measure measure the execution time of every since method invocation. Sounds awesome? Yes, but there are some problems with it:
    • The "lost in the jungle syndrome": The result of a profiling session are a bunch of trees representing all states of the call stack your application had during the profiling session. And just like in a jungle, these trees are incredibly huge. Sometimes the profiler can point out some performance hot spots, but I think that only works well if you have some very obvious performance problems. So you end up spending a lot of time climbing through the trees, considering for every branch whether its existence and time consumption is justified.
    • Observing a system changes it: A profiler usually uses a java agent, which is a hook in the JVM that allows to manipulate class files before they're executed. This way the profiler can inject byte code for performance measurements into the to-be-analyzed classes. Surely this injected code is small and fast, but it can have an impact on how the Java JIT can optimize the byte code. Example: A method that could be in-lined before may not be in-lined anymore. I don't mind if an application runs slower during a profiling session, but I do mind if the times measured during profiling are disproportional to the actual times.
    • Parameter values are not available: To understand what the code is doing, you sometimes need to know the values of the method parameters. Consider questions such as: Does a certain value occur so often that introducing an early-exit to the method would improve the speed? Does the same value occur because the method was accidentally called from within a loop? Would it help to cache the result of the method?

Probes to the Rescue

Yourkit allows you to have so-called Probes. Here are some facts in a nutshell:

  • A probe is a Java class that hooks into the invocation of methods of the to-be-analyzed code. Such hooks can be registered to be invoked before or after a method has been invoked.
  • Installing pre-/post-invocation hooks into methods may sounds familiar to you from Aspect Oriented Programming (AOP). It's indeed the same kind of hook, but unlike in AOP you don't need to a special compiler: Yourkit registers the probes at runtime via its Java agent. Therefore, probes don't change your build and are applicable for already compiled libraries.
  • You can use probes independently of CPU profiling (sampling/tracing). A probe is active once it has been registered and you can choose not to enable CPU profiling at the same time. This may safe you from getting the "Observing a system changes it" bias.
  • Yourkit ships with a set of predefined probes for standard events, such as Tread lifecycles, file system I/O, etc. You can as well implement your own probes.
  • In a probe's implementation, you can access the hooked method's parameter- and return values.
  • Youkit encourages you to build a Java data structure for your measured data that resembles a relational data base. If you follow that pattern, Yourkit has a nice graphical user interface to explore your measured data.

Probing EMF ResourceSets and Resources

As an example and for further illustration, I've build a small probe that tracks instantiation of EMF ResourceSets and invocation of EMF Resources. In the terminology of the Eclipse Modeling Framework (EMF) a Resource usually represents a file from the file system. A resource furthermore provides implementations to load a file into memory as an object tree (aka model) or persist a tree back to disk.

The following screenshot shows an Eclipse IDE with two open editors. One editor shows an *.xtend file and the other one a *.genmodel. Even though both use EMF under the hood, they have little in common:

  1. The *.xtend text-editor shows a file persisted as plain text; It's Resource.load() implementation delegates to an ANTLR parser.
  2. The *.genmodel tree-editor shows the structure of a file that is persisted as XML. Here, an XML parser is used.

The Yourkit probe was registered while opening both editors. The following screenshot shows the measured data:

  • In the tree view on the left hand side you can see all available probes. The probe "EMF ResourceSets" has been developed by me, all others ship with Yourkit. The checkbox does not register/unregister the probe. The checkbox shows/hides the data measured by the probe in the views on the right-hand side of the tree-view.
  • The table on the top on the right-hand side shows a list of all ResourceSets that have been instantiated. The AdapterFactoryEditingDomainResourceSet is the one used by the *.genmodel editor. As you can see, there was more going on in my Eclipse instance before I took the screenshot. A click on the column labeled "stack trace" would reveal how a specific ResourceSet has been instantiated.
  • The table on the bottom right-hand side shows all invocations of Resource.load() for the ResourceSet that is selected in the table above. Here we can see that tracking of application state is possible: The column "uri" displays the file name of the file that has been loaded. The "wall time" is the time in milliseconds that was spent executing the load() method.

Implementing a Probe

You can find the full source code of this example here on github.

Before we start implementing a probe, some considerations:

  • The code that the probe hooks into needs to have the probe implementation on the classpath. Furthermore, it is helpful if the probe has the code it hooks into on the classpath, since otherwise the probe implementation would need to use Java reflection to inspect the to-be-analyzed object. This sounds tricky since it is in fact a cyclic dependency between the probe and the inspected code. Luckily Eclipse has a simple mechanism to contribute to a plugin's classapth: Fragments. A fragment is a bundle with class files, own dependencies and extension points that at runtime is integrated into the classpath of a chosen host-plugin. We choose org.eclipse.emf.ecore to be that host-plugin.
  • Probes need to be registered: We could do that by changing the JVM's startup arguments, but in an Eclipse environment it seems more convenient to use the extension point org.eclipse.ui.startup.
  • The probe implementation uses Java API provided by Yourkit. This API ca be found in /lib/yjp.jar inside the Yourkit installation.

The next screenshot shows the the implementation of the probe. It is a java class with static members to

  • define the data structures for storing the measured values (TABLE_RESOURCESET, TABLE_RESOURCE).
  • intercept calls to ResourceSet constructors (ResourceSetInit) and Resource#load() invocations.
  • map ResourceSet-Objects to Table-Row-IDs (rs2row and getResourceSetRow()).

Now that you've had an overview over the probe implementation, here is finally the core, the actual hooks: Each method-hook is a static Java class that can implement the static methods onEnter() and onReturn(). Annotations are used for further configuration:

  • @MethodPattern specifies the signature of the to-be-intercepted method.
  • @This gives access to the object on which the method has been called.
  • @OnEnterResult gives access to the return value of the onEnter method.
  • @Param(1) gives access to the first parameter of the intercepted method.
  • etc.

Conclusion

  1. Probes can deliver concise and precise performance measurements for an application or a group of applications that are based on the same frameworks/libraries.
  2. Probes have the potential to define reasonable performance metrics for specific applications that can be shared across a team of developers.
  3. Probes cause significantly less side-effects compared to general profiling.
  4. Probes can make use of more information than a profiler, such as application state, parameter values and return values.
  5. Implementing probes is some effort. This may be of less significance when probes can be reused. However, in scenarios were reuse in not intended - for example the explorative search for performance issues - their use may be too much effort.

Thursday, April 18, 2013

Pattern-Aware Formatting

During the last year I had the pleasure to implement a formatter for a programming language. You know, this little but incredibly useful thing that arranges indentation, line-wraps and whitespace in your code nicely. If you know me, you may have guessed that the programming languages in question is Xtend. Version 2.4.0 is the first version to ship with this formatter.

In case you haven't heard of Xtend, it is a language that compiles down to human-readable Java code and integrates seamlessly with any Java project.

We like to advertise Xtend as a language that is more concise and expressive compared to Java. And indeed it is, due to powerful type inference, higher-order functions, and less syntactical noise. Furthermore, Xtend supports concepts that provide a great degree of syntactical freedom to the developer. Among them are extension methods, operator overloading, and an implicit variable called "it".

This conciseness, expressiveness and syntactical freedom gives a great deal of power to the developer. This is a power a developer can use to increase his/her efficiency and at the same time write code in exactly that way that he/she considers the most readable to a human. It makes Xtend a perfect match for internal DSLs.

This has interesting consequences for formatting:

  • People who care about the readability of their code do have a strong opinion about formatting. This is easy to explain: Unformatted code just isn't readable.
  • But the strong opinion is about more than just having the code formatted. It's about having the code formatted in exactly the way they consider the most readable. Suddenly the formatting strategy doesn't depend on which syntactical element is being formatted, but on how a syntactical element is being used. This is an interesting thing I had to learn, as it is completely different from how the Eclipse Java formatter does its job.

The question is, how can a formatter decide how a syntactical element is being used? The amount of APIs, internal DSLs and programming styles converges to infinite, so there is no way of considering all of them. However, there are a small number of recurring formatting patterns.

Example 1: The If-Expression

This is probably how you would express it in Java: Imperative programming style and formatted as one line per statement:

var String z
if(variable == 1)
  z = "it is one"
else
  z = "it differs from one"

In Xtend, however, the if-statement is actually an if-expression, i.e. it has a result value. Java has an If-Expression as well, it is the ternary operator: (variable == 1) ? "then" : "else". Instead of assigning values inside the bodies of the if-statement, we can directly assign the if-expression. Besides being more concise, this has the tremendous advantage that the variable can be immutable and will never exist in an uninitialized state. Here is the snippet, we choose to keep the formatting style from the example above:

val y = if(variable == 1)
    "it is one"
  else
    "it differs from one"

We could also want to write it in a single line, just like you would do it with the ternary operator in Java:

val x = if(variable == 1) "it is one" else "it differs from one"

What we see here are two different formatting patterns that are alternative to each other. An if-expression can be formatted single-line as well as multi-line. You might argue that it should be formatted multi-line when it is used as a statement and single-line when it is used as an expression. While this might sound like a smart strategy at the beginning and it will probably work for most scenarios, it will frustrate the developer for the remaining cases. Frustration is something we should prevent by all costs. Therefore, the Xtend formatter leaves the choice to the developer: It recognizes which formatting pattern the developer had in mind. The decision strategy is as follows:

  1. If the then- or the else-body contain at least one line-wrap, format the if-expression multi-line.
  2. If the length of the full if-expression exceeds the maximum length of a line, format it multi line.
  3. Apply single-line formatting in all other cases.

This empowers the developer to choose for every individual if-expression, if he/she prefers the sing-line or multi-line style.

Example 2: Lambda-Expressions

Thanks to lambda-expressions you can choose a functional programming style when you work with Xtend. You can think of lambda-expressions as executable snippets of code that can be passed around in parameters and variables.

The following example calculates the total size of all files within the same directory. You can recognize the lambda-expressions by their square brackets "[" "]".

val file = new java.io.File(".")
val totalLength = file.listFiles.filter[isFile].map[length].reduce[x, y|x + y]
println("The size of all files in " + file + " is " + totalLength + " bytes.")

  • filter[isFile] removes all items from the list which are not files, such as directories.
  • map[length] converts a list of files into a list of integers, each representing the file size (length).
  • reduce[x, y|x + y] applies x + y to all list items until all are summed up to a single value.

I think there is some beauty in this code since you can understand it just by reading it from the left to the right. Furthermore, it is much more concise than anything you can do with loops in Java.

For this code to be readable, surely we want the lambda-expressions to be formatted without line-wraps, similar to parameters of a method call.

Another use case for lambdas is to provide handlers for events and asynchronous communication. The following example creates an instance of java.lang.Runnable that prints to stdout when run() is called.

val Runnable runnable = [ |
  println("Hello from " + Thread::currentThread.name)
]

Here, a multi-line style of the lambda-expression may be preferable if the implementation of the handler follows imperative programming style. If the lambda-expression does nothing but delegate to another method, a single-line style may be preferable.

A third use case for lambda-expression are named parameter values. In this example the assignments to name and priority are compiled to thread.setName(...) and thread.setPriority(...).

val thread = new Thread(runnable) => [
  name = "my thread"
  priority = Thread::MIN_PRIORITY
]

Here as well, a multi-line style is usually preferable.

Similar to if-expressions, there is no automated way for the formatter to decide for single-line or multi-line formatting. Therefore, the decision strategy is as follows:

  1. If there is a line-wrap before the closing bracket "]", apply multi-line style.
  2. If the the length of the closure exceeds the maximum line length, apply multi-line style.
  3. Apply single-line style in any other cases.

I decided that the "magic line-wrap" that triggers multi-line formatting of a lambda-expression should only be the line-wrap before the closing bracket "]" to make it easier to convert a multi-line lambda back to its single-line style. In this scenario, you'll only need to remove one single line-wrap and re-run the formatter instead of removing multiple line-wraps.

Other Examples You Can Try

As of Xtend 2.4.0, the following formatting patterns are supported besides the ones listed above:

  • single-line/multi-line style for method parameter declarations, triggered by the line-wrap before the closing parenthesis ")".
  • single-line/multi-line style for method call parameters, triggered by the line-wrap before the closing parenthesis ")".
  • switch-exprssions can be formatted single-line or multi line.
  • case-blocks inside switch-expressions can be formatted single-line or multi-line.

Thursday, December 22, 2011

Building SWT User Interfaces with Xtend

Xtend is a programming language that compiles to Java, but adds new features, such as closures. This article applies Xtend to implement SWT UIs and shows how the resulting code can be more readable and concise compared to Java.

When you’ve been programming desktop applications with Eclipse before, you probably have used the Standard Widget Toolkit (SWT), since it provides the fundamental UI elements (aka Widgets), such as windows, buttons, edit fields, checkboxes, etc.

The first thing you probably did was to create a window with several nicely arranged widgets. This task includes choosing the proper parent widget for all widgets, configuring layouts, etc. Then, the next step usually is to implement behavior for some widgets, so that the user can interact with the UI. This includes for example implementing selection listeners for buttons.

These two tasks have different characteristics:

  • To arrange widgets nicely, the developer's code needs to creates trees of objects. In such trees, windows are the root nodes, composites etc. the intermediate nodes and buttons, text fields, etc. are the leaf nodes. In the context of the web and HTML, an equivalent tree is the DOM (Document Object Model). For SWT, this tree becomes very visible in the XML-based approaches to specify UIs, such as CookSwt and swtxml.
  • To implement behavior, the developer usually creates anonymous or nested classes in Java. These classes implement event handlers and are registered as event listeners.

SWT User Interfaces are usually implemented using Java. However, the way to implement both patterns in Java bears room for improvement, because:

  • Java doesn’t have a special pattern to create trees. The standard pattern is to imperatively create objects and establish references between them. Whether the resulting objects form a tree or a graph is not obvious to the reader of the code, since for him/her it is just a linear sequence of statements.
  • Anonymous classes in Java have a particularly noisy syntax. The extreme scenario (which is fairly common) is when the actual code that handles the event is only a single Java statement. In this scenario, the majority of the code is not the execution logic of the handler, but the declaration of the class and the handlers method.

Designing User Interfaces using Trees: Builder Syntax

Xtend offers to improve the situation due to its support for a builder syntax and its support for closures.

  • Builder syntax is a pattern that creates an object tree and allows the code to be formatted like a tree (using indentation an brackets).
  • Closures allow to define instructions that can be executed later. You may perceive it as similar to an anonymous class with a single method, but without the syntactic overhead of a method declaration.

The following snippet illustrates the builder syntax in Xtend. As indicated already, the style of the code reflects the tree structure of the SWT widgets. This example creates a shell with one label, one text filed and one button. Additionally, it arranges them using a GridLayout.

Builder Syntax

val shell = newShell(display) [ 

    layout = new GridLayout(3, false)

    newLabel(SWT::NONE) [ 

        text = "To:"

    ]      

    newText(SWT::BORDER) [

        layoutData = newGridData() [

            grabExcessHorizontalSpace = true

            horizontalAlignment = SWT::FILL

        ]

    ]

    newButton(SWT::PUSH) [

        text = "Send"

    ]

]

To understand the code from the Xtend code snippet above and to compare it with Java, the following things may be noteworthy:

  • All referenced elements in the snippet are Java elements from SWT, except for the new*()-methods. Those are methods implemented in a custom Java factory class. They all conform to the following pattern illustrated in the next code snippet.

    public static Button newButton(Composite parent, int style, Procedure1<Button> init) {

        Button btn = new Button(parent, style);

        init.apply(btn);

        return btn;

    }

    The new*()-methods can be invoked from the snippet like member methods since they have been imported as extension methods. Extension methods are methods defined in a different class which can be invoked like member methods on any kind of object that the method accepts as its first parameter. In the snippet, the extension methods are invoked on the implicit variable it.
  • You probably have noticed that all invocations of new*()-methods are followed by a code block surrounded by brackets "[]". This code block defines a closure which is passed as the last parameter to the new*()-method. You could as well pass in the closure explicitly as the last parameter to the method. However, this syntax can improve readability of the code. Since the closure has one parameter and no return value, its class implements interface Procedure1 (src).
  • No closures in this example declare parameters. However, they do have one implicit parameter. An example of a closure with parameters is [param | param.doSomething() ]. Xtend supports an implicit variable named it. If a closure has a parameter but does not declare the parameter, the parameters' value can be accessed through the variable it. Usage of the variable it is implicit in the same way as you know it from this, with the difference that you can not assign new values to this. When accessing members of it (e.g. horizontalAlignment), stating the name it is optional. Furthermore, you can invoke extension methods on it: In the code snippet, the method newText(Composite, int) has two parameters. The value for Composite is the value of it from the surrounding closure, which is in fact the shell (the window).
  • Xtend allows to use Getter/Setter-pairs like properties: Instead of setText("Send") you may write text = "Send"

Using Closures to make User Interfaces Interactive

To implement event handlers it is common in Java to use anonymous or nested classes. The snippet below uses Xtends closures to do the same in a syntactically more concise way.

Event Handling

newButton(SWT::PUSH) [

    text = "Send"

    addListener(SWT::Selection) [

        newMessageBox((widget as Control).shell, SWT::OK) [ 

            message = "Hello World"

        ].open()

    ]

]

The snippet above uses the Builder Syntax (as described in the last section) to create a Button. When the button is clicked, a MessageBox will be created and shown to the user.

The interesting part here is addListener(int, Listener) . This method accepts two parameters with the second parameter being an instance of interface Listener (src) . In the snippet the second parameter for addListener is a closure (the code block surrounded with [] in addListener(SWT::Selection) [ ... ] ). When the Xtend code is compiled to Java, the closure is compiled into an anonymous Java class which implements the interface Listener . This, however, is only possible for interfaces that have just a single method.

A Comprehensive Example

Builder Syntax and Event Handling

package blog_001_xtend_and_swt


import org.eclipse.swt.SWT

import org.eclipse.swt.layout.GridLayout

import org.eclipse.swt.widgets.Display


import static extension blog_001_xtend_and_swt.XtendSWTLib.*


class MessageForm {


    def static void main(String[] args) {

        new MessageForm().run(args)

    }

    

    def void run(String[] args) {

        val display = new Display()

        val shell = newShell(display) [ 

            setSize(400, 400)

            layout = new GridLayout(3, false)

            newLabel(SWT::NONE) [ 

                text = "To:"

            ]      

            val to = newText(SWT::BORDER) [

                layoutData = newGridData() [

                    grabExcessHorizontalSpace = true

                    horizontalAlignment = SWT::FILL

                ]

            ]

            val send = newButton(SWT::PUSH) [

                text = "Send"

            ]

            val msg = newText(SWT::BORDER) [

                layoutData = newGridData() [

                    grabExcessHorizontalSpace = true

                    grabExcessVerticalSpace = true

                    horizontalSpan = 3

                    horizontalAlignment = SWT::FILL

                    verticalAlignment = SWT::FILL 

                ]

            ]

            send.addListener(SWT::Selection) [

                newMessageBox(send.shell, SWT::OK) [ 

                    message = to.text + "\n" + msg.text

                ].open()

            ]

        ]

        

        shell.open()

        while (!shell.isDisposed()) {

            if (!display.readAndDispatch())

                display.sleep()

        }

        display.dispose()

    }

}