X10 version 2.4 is not fully backwards compatible with previous versions of the X10 language. The motivation for making backwards incompatible language changes with this release of X10 is to significantly improve the ability of the X10 programmer to exploit the expanded memory capabilities of modern computer systems. In particular, X10 v2.4 includes an extensive redesign of arrays and a change of the default type of unqualified integral literals (e.g. 2) from Int to Long. Taken together these two changes enable natural exploitation of large memories via 64-bit addressing and Long-based indexing of arrays and similar data structures.
Due to the pervasive use of arrays and integral literals in most programs, updating code that worked with X10 version 2.3 to work with X10 2.4 is likely to require small changes on many lines of code. However, our experience with porting the X10 standard libraries, test suite, benchmarks, and other large X10 applications is that the process is actually fairly straightforward and the X10 compiler is effective at reporting what needs to be changed.
When porting code ourselves, we followed the two stage process outlined below.
Stage One: Functional port to X10 2.4
-
Fix the main method signature. It is now public static def main(Rail[String]) { ...}
-
Make minimal changes to Array based codes so that they can compile against the new structure of the standard library. In X10 2.3, x10.array was auto-imported and contained the code that in X10 2.4 is in the x10.regionarray package (which is not auto-imported). The minimal set of changes are:
- Change all imports of x10.array to x10.regionarray
- Add import x10.regionarray.* in any file that uses Array/DistArray/Region/etc.
- Update Array/DistArray constructors that use initialization closures from (int)=>T to (long)=>T
- In X10 2.4, there is no longer a conversion from IntRange to x10.regionarray.Region. The * operator on IntRange was also removed. Region creation code like 1..10 * 1..10 needs to be re-written to Region.make(1..10, 1..10)
- Arrays, Regions, and Points are now long-based, so related variables/fields may need to be changed from Int to Long.
- If your code was using the "Rail[T]" typedef for a rank 1, zero-based, densely-indexed Array[T], usually the simplest change is to convert directly to using the new x10.lang.Rail[T] class. If attempting to use x10.lang.Rail[T] causes significant rippling changes, you may instead defer the non-local changes by initially replacing Rail[T] with Array[T]{rail}, then converting to x10.lang.Rail[T] in a second stage of porting.
- If you had any Array literals, use the Array constructor that takes a (long)=>T initialization closure passing in the literal. For example [1.0, 2.0] becomes new Array[Double]([1.0,2.0]). In Stage 2, you may change this to a Rail literal (back to [1.0, 2.0]).
- Fix compilation errors related to the change in type of unqualified integral literals now being Longs instead of Ints. Usually the simplest fix is to add a "n" suffix to the literal to indicate that it is a 32 bit integer. In some cases a better fix is to change the type of the expression/variable to Long instead.
- Fix any remaining compilation errors (for example due to other places in the standard library APIs where Ints were changed to Longs) and verify that the program is functionally correct.
Stage 2: Take advantage of new Rail/Array classes
The performance of x10.lang.Rail and x10.array.Array is significantly better than that of the corresponding classes in x10.regionarray. Where possible, you should use Rail and/or the new x10.array classes in your code. The basic steps are:
- Become familiar with the new Rail and x10.array classes by examining their documentation, reading the Rails and Arrays chapter of the X10 language specification, and looking at the sample programs and X10 Benchmarks.
- Look for opportunities to use Rail in your program. Almost all rank 1 (one-dimensional), zero-based, densely indexed Arrays should become Rails.
- Look for opportunities to replace multi-dimensional x10.regionarray.Array with the corresponding x10.array.Array classes.
The primary source of bugs/problems when changing from x10.regionarray to Rail or x10.array is in for loop comprehensions. The old x10.regionarray classes implement Iterable[Point], so the default for loop comprehension was to iterate over the Points that index the Array, not over the values of the Array. Both Rail and x10.array implement Iterable[T], so the default loop comprehension is iterate over the values of the Rail/Array not over the Longs/Points that index them. The error prone (but uncommon) case is a for loop comprehension when the Array element type is Point because either interpretation of the for loop comprehension is statically type correct.
Quirks and Other Issues in Porting to X10 2.4
-
A haszero constraint was added to the generic type of x10.lang.PlaceLocalHandle to enable PlaceLocalHandles to be cleared (set to null). If your code created a PlaceLocalHandle with a non-null constraint (for example PlaceLocalHandle[Array[Long]{self!=null}]) in X10 2.4 you will get a somewhat opaque error message from the compiler. For example, for the code
val t = PlaceLocalHandle.make[Rail[long]{self!=null}](PlaceGroup.WORLD, ()=>[2,4]);
The compiler will report an error
Type guard [x10.lang.Rail[x10.lang.Long]{self!=null} isref, x10.lang.Rail[x10.lang.Long]{self!=null} haszero] cannot be established; inconsistent in calling context.