k47.cz
mastodon twitter RSS
bandcamp explorer

Ceylon Project

7. 6. 2011 (před 12 lety) — k47 (CC by)

Red Hat dva roky potajmu vyvíjel vlastní programovací jazyk Ceylon, který byl stejně nenápadně oznámen Gainem Kingem na nějaké asijské konferenci. Nikdo z Red Hatu nečekal velké ohlasy, šlo jenom o malé oznámení. Ale věci nabraly nečekaný spád a o Ceylonu se v poslední době píše všude možně. A to i přesto, že máme k dispozici jenom dvojici slajdů z konference. Nemáme kompilátor, žádné info o připravované vlastní SDK, nic.


Jde o další pokus udělat Javu, která se stává dnešním COBOLem, správně, tak jak by byl dnes navrhován jazyk pro business computing.

Ceylon v sobě nese několik velice zajímavých nápadů, ale má jeden obrovský problém: Scalu. Naprostou většinu z toho, co Ceylon někdy v budoucnu nabídne, už teď Scala obsahuje a ještě mnohem víc. Scala je jako asymptota, jejímž směrem se snahy projektu Ceylon z větší čísti ubírají. Ceylon se poučil z nedostatků Javy a posunul se o jeden krok dál, může tak vyřešit současné problémy, ale stejně jako v případě Javy za několik let narazíme na další problémy, které budou mí stejné řešení: Scalu (resp. nějakou její budoucí verzi) jako velice flexibilní a ortogonální jazyk.

A teď moje nesouvislé poznámky k Ceylonu:

Zajímavou myšlenkou je nahrazení většiny klíčových slov anotacemi, které na rozdíl od Javy nejsou uvozeny zavináčem, takže vypadají jako skutečná klíčová slova. Ale na druhou stranu je podivné, proč byla zažitá pojmenování zaměněna za zcela jiná. Jmenná škatulata jsou následující:

Proč se zříkat zažitých termínů a zavádět jiná, když to nemá žádný patrný přínos. Ale na druhou stranu, jde jenom o anotace, takže mohou být kdykoli změněny (a to snad i samotným programátorem) bez toho aby se musela měnit gramatika jazyka.


Přetěžování operátorů: operátor v Ceylonu je alias pro předdefiniovanou metodu na předdefinovaném rozhraní. + je alias pro Numeric.plus(), > pro Comparable.largerThan() Jde o něco bezpečnější způsob než klasicé přetěžování operátorů, protože si zkrátka nemůžu vytvořit vlastní operátor +, který by měl jiný význam než sčítání nebo >, který by neporovnával. Na druhou stranu se ztrácí spousta flexibility. Není možné definovat expresivní DSL jako např. parser combinators ze Scaly:

def obj: Parser[Map[String, Any]] = "{" ~> repsep(member, ",") <~ "}" ^^ (Map() ++ _)
def arr: Parser[List[Any]]        = "[" ~> repsep(value, ",") <~ "]"

Scala navíc problém přetěžování operátorů vyřešila velice šalamounsky – mezi oběma pojmy není žádný rozdíl, operátor je jejom jinak zapsaná metoda, což je ještě o něco pružnější přístup, ale plyne z něj petenciální riziko, že se kód může stát nepřehledným, když si lidi začnou definovat vlastní ASCII art operátory.


Ceylon zcela ignoruje pattern matching jednu ze silných vlastností Scaly.


Type unions & intersections – stejný koncept jako junctions z Perlu 6.

A & B & C – průnik typů – musí implementovat rozhraní A a zároveň B a zároveň C A | B | C – sjednocení typů – odpovídá typu A nebo B nebo C

Zvlášť průnik není možné nijak jednoduše emulovat. Ale otázka zní, jestli je tolik potřeba, když máme k dispozici dědičnost, strukturální typy, typ Either nebo tenhle klenot využívající Curry-Howard isomorfismus.


Spousta rozhodnutí jde správným směrem. Např: žádný overloading, žádný null. Otázka zní, jak to ovlivní interoperabilitu s Javou. Martin Odersky se v nějakým rozhovoru zmínil, že v případě Scaly také uvažovali o podobně zásadních změnách – nahradit null typem Option[T] a v případě overladingu se vydat na druhou stranu a zavést plně dynamický multiple dispatch, ale právě proto, aby byli schopni hladné spolupráce s Javou se rozhodli nebýt tak radikální. Interoperabilita s nějakou již existující platformou je zásadní pro adopci nového jazyka. Všechno je mnohem jednodušší, když můžeme bezproblémově využívat již existující knihovny od času T = 0.

Dále je zajímavá zmínka, že Ceylon je zaměřen na JVM, ale může být později portován i na jiné platformy. Logický další krok .NET. Scala má podobnou filosofii a kromě hlavní JVM verze existuje i její .NET protějšek. Že by se tady rýsovala nová generace výkonných (myšleno neskriptovacích) jazyků vrozeně agnostických k použitému virtuálnímu stroji?

Vlastnost ze které jsem hodně nadšený je type reification a to dokonce i na JVM, které používá type erasure. Jak to vlastně implementovat, když pro dodatečné typové informace není podpora v bytekódu? Napadá mě jediné řešení: kompilátor pro každý typový parametr doplní jeden hodnotový atribut, který bude uchovávat konkrétní třídu generického typu.

Kompilátor následující třídu (v syntaxi Scaly)

class A[B](a: B)

transformuje na následující:

class A[B](a: B) {
  val B: Class[B]
}

A všechna volání

new A(x)

přepíše na

new A(x) {
  val B = x.getClass // getClass musí zase vrátit reifikovaný typ
}

Bude to mít dva důsledky:

  1. generické objekty budou o několik extra referencí větší
  2. spolupráce s klasickými javovskými objekty, které podlehnou type erasure může být problematická.

Reifikace typů může být užitečná i když pro ní není podpora na nižší úrovni. Ve Scale v bych si ji dokázal představit na vyžádání, podobně jako specializaci generických tříd:

@reify
class List[+A]

Ceylon se zkrátka snaží jenom vyřešit některé konkrétní nedostatky v návrhu Javy, ale není dost flexibilní, aby umožňoval zásadní rozšíření vlastních možností skrz knihovny.


Další čtení:

píše k47, ascii@k47.cz