Scala versus C# 4.0 - Strukturální typy versus Dynamic member lookup

C# je jazyk, který se vyvíjí docela dramaticky a každá nová verze přinese pár zajímavých novinek. Poslední verze 4.0 zavádí podporu pro Dynamic member lookup neboli duck typing. Typový systém jazyka je obohacen o pseudotyp dynamic
, který se chová jako běžný System.Object
, ale všechny přístupy k (i neexistujícím) metodám, vlastnostem a indexerům jsou dovoleny bez jakékoli typové kontroly. Všechno se vyhodnotí až v run-time.
// C# - Dynamic member lookup // vrátí hodnotu property nebo členské proměnné Length jakéhokoli objektu int GetLength(dynamic obj) { return obj.Length; } GetLength("Hello, world"); // string má property Length GetLength(new int[] { 1, 2, 3 }); // pole také GetLength(42); // ale ne integer - zde bude vyhozena výjimka
Problém tohoto přístupu je, že minimalizuje možnosti typové kontroly a všechny případné chyby se projeví až při běhu aplikace.
Scala dokáže vyřešit stejný problém pomocí strukturální typů a to dokonce ještě lépe než C#. Výsledný program je typově bezpečný a všechny chyby jsou odhaleny ve fázi kompilace.
Strukturální typy nepatří do klasické hierarchie tříd a rozhraní, jde o typ u něhož známe jen částečnou strukturu, tedy jestli obsahuje nějaké metody, členské proměnné, typy nebo vnitřní třídy. Nemusí (i když může) být specifikován společným předkem nebo rozhraním. Strukturální typ je například { def close(): Unit }
– do kterého spadají všechny objekty mající metodu close, která nepřijímá žádné parametry a vrací Unit.
K metodám a proměnným strukturálních typů se samozřejmě bude přistupovat přes reflexi (v JDK7 možná přes InvokeDynamic), ale kompilátor zajistí, že celé řešení bude typově bezpečné.
// Scala - Structural types // s vytvořením aliasu strukturální typu type T = { def length: Int } def length(x: T) = x.length // nebo stručněji bez aliasu def length2(x: { def length: Int }) = x.length // nebo s lehkým nádechem generiky def length3[T <: { def length: Int }](x: T) = x.length // test class Test { def length = 42 } length(new Test) // 42 length("string") // 6 length(List(1, 2, 3)) // 3 length(42) // nezkompiluje se - type mismatch
Na závěr srovnání nových vlastností C# 4.0 se Scalou:
- Volitelné a pojmenované parametry Scala má od verze 2.8
- Kovariance a kontravariance generických typů Lidi v Microsoftu se naštěstí poučili minulostí a s C# neopakují fiasko javovských wildcards (neboli use-site variance neboli veselé otazníčky). Ten stejně jako Scala používá varianci na straně definice (definition-site variance).
C# 3.0 vs. Scala
- LINQ: ne, LINQ je kapitola sama pro sebe
- Object initializers: ano
- Collection initializers: ano (v podobě companion objektů)
- Anonymous types: ano, ale mnohem pohodlnější je používat tuple
- Local variable type inference: ano. Scala dokáže odvodit mnohem víc než jenom typ lokálních proměnných.
- Lambda expressions: ano, nedílná součást jazyka. Delegáty v C# jsou pro mě jednou z nejvíce matoucích vlastností.
- Expression trees: tedy možnost výrazy nebo lambda funkce předávat fe formě syntaktického stromu (AST), tohle Scala nemá a bylo by to super. Aktualizace: Ale možná, že se dočkáme i tohohle v rámci současných snah o virtualizaci jazyka. Aktualizace 2: I tato fukcionalita je dostupná v podobě typu
scala.reflect.Code[T]
- Automatic properties: properties jako takové vůbec nejsou potřeba
- Extension methods: nejsou třeba, Scala nabízí mnohem silnější koncept implicitních konverzí