úterý 5. září 2006

Closures v Jave - funkce se bouří

Málokterý materiál týkající se Javy vyvolal v poslední době takový rozruch jako návrh začlenění funkčních typů a inline funkcí nazývaných Closures, za kterým stojí čtveřice Gilad Bracha, Neal Gafter, James Gosling, Peter von der Ahé. Přímou podporu funkčních typů mají například jazyky Ruby, Scala, Smalltalk a nebo JavaScript. Co to bude pro Javu znamenat, jak vypadá syntaxe a jaký mají Closures ohlas - to všechno jsou otázky, na které se pokusíme odpovědět.

Java podporuje anonymní vntiřní třídy, všichni je známe a používáme. Ilustrační příkad pro připomenutí.

List<Person> persons = ...;
Collections.sort(persons, new Comparator<Person>() {
   public int compare(Person a, Person b) {
      return a.getAge() - b.getAge();
   }
});

Metoda sort má dva argumenty, sortovaný list a komparátor, který implementuje vlastní porovnání. V tomto případě je komparátor implementován jako anonymní vnitřní třída.

Closures

Výše zmíněný dokument představuje koncept anonymní funkce též zvaný Closure. V našem příkladu tak bude možné anonymní vnitřní třídu komparátoru nahradit anonymní funkcí. V takovém případě může kód vypadat následovně.

List<Person> persons = ...;
Collections.sort(persons, int(Person a, Person b) { return a.getAge() - b.getAge()});

Kód int(Person a, Person b) {return a.getAge() - b.getAge();} je ona anonymní funkce (closure). V době kompilace se closure přeloží přesně na ten samý kód jako v případě použití anonymní vnitřní třídy. Zamýšlená syntaxe umožňuje využití odvození návratového typu.

Collections.sort(persons, int(Person a, Person b: a.getAge() - b.getAge());

Collections.sort(persons, int(Person a, Person b) { a.getAge() - b.getAge()});

Syntaxe closure by měla umožnit použití zkrácené formy zápisu, v takovém případě je closure napasován jako druhý argument metody.

List<Person> persons = ...;
Collections.sort(personsint(Person a, Person b) {
   return a.getAge() - b.getAge();
}

Lokální funkce

Lokální funkce v signatuře definuje argumenty, návratový typ a případně výjimky v throws klauzuli.

int plus2(int x) { return x+2}

Lokální funkce je zároveň referenčním typem. Následuje přiřazení do proměnné typu lokální funkce.

int(intplus2b = plus2;

A jako takovou lze lokální funkcí zavolat.

System.out.println(plus2b(2));

Pohled na celek

public static void main(String[] args) {
  int plus2(int x) { return x+2}
  int(intplus2b = plus2;
  System.out.println(plus2b(2));
}

Dopad na jazyk

Lokální funkce (closers jsou jejich anonymním vyjádřením) zavádějí do Javy nový rozměr. Pokud jsme doposud mohli vzít jako základní konstrukt objekt, zavedením lokálních funkcí musíme přibrat navíc funkci. Funkce na rozdíl od objektu nemá vnitřní stav a komunikační rozhraní je definováno vstupem a výstupem.

Můžeme tedy napsat metodu, která bude mít jako jeden z argumentů nikoliv objekt, ale funkci se kterou bude pracovat.

/**
 * Obecná metoda pro hledání v seznamu osob, vlastní hledání je 
 * definováno na úrovni funkčního typu.
 *  
 @param concreteFinder funkce která implementuje hledání
 @return seznam osob
 */ 
public List<Person> find(boolean(PersonconcreteFinder) {
  List<Person> persons = ...//načtení dat např. z DB
  List<Person> foundPersons = new ArrayList<Person>();
  for(Person p: persons){
      if(concreteFinder(p)){
        foundPersons.add(p);
      }      
  }
  return foundPersons;   


//lokální funkce, která vrací true v případě, že je osoba nezletilá
boolean(PersonteenFinder = (Person p: p.getAge() 19;

//použití
List<Persons> teenagers = find(teenFinder);

Ohlasy

Zatím se zdá, že je část vývojářů, kteří si slastně mlaskají podstatně menší než ta, která se cítí zmateně. Pokud pominu ultrageeky, tak jsem získal pocit, že vývojářů, kteří si po něčem takovém stýskají je velice málo. Vesměs by se ten postoj dal pospat Opravdu to potřebuji?. Syntaktické veletoče (jinak se tohle nazvat nedá) mají tu nespornou nevýhodu, že boží zpětnou kompatibilitu a činí kód hůře čitelnějším. Samozřejmě musíme vzít jako bernou minci pokročilejší konstrukce (například subtyp funkce boolean(Person) teenFinder = (Female f) : f.getAge() < 19; , či přetypování) ne ilustrativní příklad komparátoru.

Budoucnost

Na přesné specifikaci closures a lokálních funkcí se stále pracuje, takže ne vše výše uvedené musí v budoucnu platit. Pokud budou closers začleněny do Javy mělo by to být ve verzi 7. Související odkazy s tímto tématem můžete najít pěkně pohromadě v článku Closures Syntax in Java 7.