Язык программирования
Xtend
• Язык общего назначения
Xtend
• Язык общего назначения• Транслируется в Java 5
Xtend
• Язык общего назначения• Транслируется в Java 5• ООП + немного ФП
Xtend
• Язык общего назначения• Транслируется в Java 5• ООП + немного ФП• Простота изучения (намного проще
Scala), схожесть с Java
Xtend
• Язык общего назначения• Транслируется в Java 5• ООП + немного ФП• Простота изучения (намного проще
Scala), схожесть с Java• Библиотека – тонкая прослойка над
Java (≈100 классов) + Guava
Языки JVM
Yeti
Erjang
Frege
Языки JVM
Yeti
Erjang
Frege
Языки JVM
Yeti
Frege
Языки JVM
Языки JVM
Языки JVM
Кол-во вопросов на SO
Java Scala Groovy Clojure JRuby Jython Xtend Kotlin Mirah Gosu Fantom Ceylon Yeti X101
10
100
1000
10000
100000
1000000457101
17592
6564 5612
17481143
82
2314
9 8 7 63
Опрос
No ; and ()
class Main { def static void main(String[] args) { println(5.toString) }}
Translation to Java
import org.eclipse.xtext.xbase.lib.InputOutput;
@SuppressWarnings("all")public class Main { public static void main(final String[] args) { String _string = Integer.valueOf(5).toString(); InputOutput.<String>println(_string); }}
val, var and type inference
val n = 5
for (i : 1..n) { var str = i.toString println(str)
str = ...}
val, var and type inference
val int n = 5
for (int i : 1..n) { var String str = i.toString println(str)
str = ...}
Type inference
val list = new ArrayListlist.add(1)list.add("text")list.add(true)
println(list)
Type inference
val list = new ArrayListlist.add(1)list.add("text")list.add(true)
println(list)
Какой тип у ArrayList?
Type inference
val list = new ArrayList<Serializable>list.add(1)list.add("text")list.add(true)
println(list)
Type inference
val list = new ArrayList<Comparable<?>>list.add(1)list.add("text")list.add(true)
println(list)
Everything is an expressiondef static readData() { val data = try { fileContentsToString('data.txt') } catch (IOException e) { "dummy data" }
println(data)
data}
switch
def String describe(Object x) { switch x { Integer case x > 0 : "Positive integer" String : "String" List<?> case x.empty : "Empty list" List<?> : "Non-empty list" default : x.class.simpleName }}
Классы
@Dataclass Person { val String firstName val String lastName val int age
def void sayHello() { println('''Hello, my name is «firstName» «lastName»''') }}
Классы@Data@SuppressWarnings("all")public class Person { private final String _firstName; public String getFirstName() { this._firstName; } private final String _lastName; public String getLastName() { return this._lastName; } private final int _age; public int getAge() { return this._age; } public void sayHello() { ... } public Person(final String firstName, final String lastName, final int age) { ... } @Override public int hashCode() { ... } @Override public boolean equals(final Object obj) { ... } @Override public String toString() { ... }}
Классыclass Task implements Runnable { @Property val String name @Property var int timeout
new(String name, int timeout) { this._name = name this._timeout = timeout }
new(String name) { this(name, 600) }
override run() { println('''Running task "«name»"''') ... }}
Операторы
Xtend Javaa == b Objects.equals(a, b)a === b a == ba -> b Pair.of(a, b)a ** b Math.pow(a, b)a .. b new IntegerRange(a, b)a ..< b new ExclusiveRange(a, b,
true)a >.. b new ExclusiveRange(a, b,
false)a ?: b if (a != null) a else b
a?.doStuff if (a != null) a.doStuff()
extension-методы
"text".toFirstUpper
extension-методы
"text".toFirstUpper
import org.eclipse.xtext.xbase.lib.StringExtensions;
…
StringExtensions.toFirstUpper("text");
Стандартные extension-методы
ObjectExtensionsByteExtensionsShortExtensionsIntegerExtensionsLongExtensionsFloatExtensionsBooleanExtensionsDoubleExtensionsCharacterExtension
s
BigIntegerExtensions
BigDecimalExtensions
IterableExtensionsMapExtensionsListExtensions
CollectionExtensions
FunctionExtensionsProcedureExtensionsComparableExtension
s
Внешние extension-методы
import java.io.Fileimport com.google.common.io.Files;
class Main { def static void main(String[] args) { val file = new File('''C:\jdk1.7.0_25\README.html''') val bytes = Files::toByteArray(file) ... }}
Внешние extension-методы
import java.io.Fileimport static extension com.google.common.io.Files.*;
class Main { def static void main(String[] args) { val file = new File('''C:\jdk1.7.0_25\README.html''') val bytes = file.toByteArray ... }}
Локальные extension-методы
class Main { def static void main(String[] args) { val f = 5.factorial println(f) }
def static int factorial(int n) { if (n == 1) 1 else n * factorial(n - 1) }}
Extension providers
class EntityRepository { var extension EntityManager entityManager
def void doSmth() { val person = new Person("John", "Doe") person.persist }}
Lambdasval Comparator<String> c = [a,b | Integer::compare(a.length, b.length)]
Lambdasval Comparator<String> c = [a,b | Integer::compare(a.length, b.length)]
final Comparator<String> _function = new Comparator<String>() { public int compare(final String a, final String b) { int _length = a.length(); int _length_1 = b.length(); int _compare = Integer.compare(_length, _length_1); return _compare; }};
final Comparator<String> c = _function;
Lambdas
val persons = #[new Person("John", "Doe"),new Person("Jane", "Roe"),new Person("David", "McFly")
]
val names = persons.map([p | p.firstName])// John, Jane, David
Lambdas
val persons = #[new Person("John", "Doe"),new Person("Jane", "Roe"),new Person("David", "McFly")
]
val names = persons.map([it.firstName])// John, Jane, David
Lambdas
val persons = #[new Person("John", "Doe"),new Person("Jane", "Roe"),new Person("David", "McFly")
]
val names = persons.map([firstName])// John, Jane, David
Lambdas
val persons = #[new Person("John", "Doe"),new Person("Jane", "Roe"),new Person("David", "McFly")
]
val names = persons.map[firstName]// John, Jane, David
Lambdas
val persons = #[new Person("John", "Doe", true),new Person("Jane", "Roe", false),new Person("David", "McFly", true)
]
val women = persons.filter[female]// Jane Roe
Задача
Найти человека ссамой длинной фамилией
Решение #0
var Person person = null;for (p : persons) { if (person == null || p.lastName.length > person.lastName.length) { person = p }}
Решение #0
var Person person = null;for (p : persons) { if (person == null || p.lastName.length > person.lastName.length) { person = p }}
Решение #1
val person = persons.sortBy[lastName.length].last
Решение #2
import static extension java.util.Collections.* val person = persons.max[ p1, p2 | p1.lastName.length - p2.lastName.length]
Решение #3
val person = persons.reduce[ pWithLongestLastName, p | if (pWithLongestLastName.lastName.length > p.lastName.length) pWithLongestLastName else p]
Решение #4
val person = persons.maxBy[lastName.length]
Multiple dispatch
GameObject
Spaceship Asteroid
Multiple dispatchdef static void main(String[] args) { val GameObject asteroid = new Asteroid val GameObject spaceship = new Spaceship collide(asteroid, spaceship)}
def static void collide(Asteroid x, Asteroid y) { println('астероид сталкивается с астероидом')}def static void collide(Asteroid x, Spaceship y) { println('астероид сталкивается с космическим кораблем')}def static void collide(Spaceship x, Asteroid y) { println('космический корабль сталкивается с астероидом')}def static void collide(Spaceship x, Spaceship y) { println('космический корабль сталкивается с космическим кораблем')}
Multiple dispatchdef static void main(String[] args) { val GameObject asteroid = new Asteroid val GameObject spaceship = new Spaceship collide(asteroid, spaceship) // Ошибка компиляции}
def static void collide(Asteroid x, Asteroid y) { println('астероид сталкивается с астероидом')}def static void collide(Asteroid x, Spaceship y) { println('астероид сталкивается с космическим кораблем')}def static void collide(Spaceship x, Asteroid y) { println('космический корабль сталкивается с астероидом')}def static void collide(Spaceship x, Spaceship y) { println('космический корабль сталкивается с космическим кораблем')}
Multiple dispatchdef static void main(String[] args) { val GameObject asteroid = new Asteroid val GameObject spaceship = new Spaceship collide(asteroid, spaceship) // OK}
def static dispatch void collide(Asteroid x, Asteroid y) { println('астероид сталкивается с астероидом')}def static dispatch void collide(Asteroid x, Spaceship y) { println('астероид сталкивается с космическим кораблем')}def static dispatch void collide(Spaceship x, Asteroid y) { println('космический корабль сталкивается с астероидом')}def static dispatch void collide(Spaceship x, Spaceship y) { println('космический корабль сталкивается с космическим кораблем')}
Multiple dispatchprotected static void _collide(final Asteroid x, final Asteroid y) { InputOutput.<String>println("астероид сталкивается с астероидом");}protected static void _collide(final Asteroid x, final Spaceship y) { InputOutput.<String>println("астероид сталкивается с космическим кораблем");}protected static void _collide(final Spaceship x, final Asteroid y) { InputOutput.<String>println("космический корабль сталкивается с астероидом");}protected static void _collide(final Spaceship x, final Spaceship y) { InputOutput.<String>println("космический корабль сталкивается с космическим кораблем");}
public static void collide(final GameObject x, final GameObject y) { if (x instanceof Asteroid && y instanceof Asteroid) { _collide((Asteroid)x, (Asteroid)y); return; } else if (x instanceof Asteroid && y instanceof Spaceship) { _collide((Asteroid)x, (Spaceship)y); return; } else if (x instanceof Spaceship && y instanceof Asteroid) { _collide((Spaceship)x, (Asteroid)y); return; } else if (x instanceof Spaceship && y instanceof Spaceship) { _collide((Spaceship)x, (Spaceship)y); return; } else { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.<Object>asList(x, y).toString()); }}
Template expressions
val name = "James"println("Hello " + name + "!")
Template expressions
val name = "James"println('''Hello «name»!''')
Template expressions
val name = "James"println('''Hello «name»!''')
final String name = "James";StringConcatenation _builder = new StringConcatenation();_builder.append("Hello ");_builder.append(name, "");_builder.append("!");InputOutput.<String>println(_builder.toString());
Template expressions
def static html(String text, String image) { ''' <!DOCTYPE html> <html> <body> <p>«text»</p> <img src='«image»' width='«getWidth(image)»' height='«getHeight(image)»'/> </body> </html> '''}
Active annotations
class Tweets { List<String> allTweets = TweetReader::allTweets
...}
Active annotations
class Tweets { @Lazy List<String> allTweets = TweetReader::allTweets
...}
Active annotations@Target(ElementType::FIELD)annotation Lazy {}
Active annotations@Target(ElementType::FIELD)@Active(typeof(LazyProcessor))annotation Lazy {}
Active annotations@Target(ElementType::FIELD)@Active(typeof(LazyProcessor))annotation Lazy {}
class LazyProcessor extends AbstractFieldProcessor { override doTransform(MutableFieldDeclaration field, extension TransformationContext context) { if (field.type.primitive) field.addError("Fields with primitives are not supported by @Lazy") if (field.initializer == null) field.addError("A lazy field must have an initializer.") field.declaringType.addMethod('_init' + field.simpleName) [ visibility = Visibility::PRIVATE returnType = field.type body = field.initializer ] field.declaringType.addMethod('get' + field.simpleName.toFirstUpper) [ returnType = field.type body = [''' if («field.simpleName»==null) «field.simpleName» = _init«field.simpleName»(); return «field.simpleName»; '''] ] }}
Заключение
• Xtend – довольно сырой язык
Заключение
• Xtend – довольно сырой язык– Есть баги– Проблемы с производительностью– Очень маленькое сообщество
Заключение
• Xtend – довольно сырой язык– Есть баги– Проблемы с производительностью– Очень маленькое сообщество
• Неплохая поддержка IDE
Заключение
• Xtend – довольно сырой язык– Есть баги– Проблемы с производительностью– Очень маленькое сообщество
• Неплохая поддержка IDE• Язык не является убийцей Java, он является
убийцей её синтаксиса