k47.cz
mastodon twitter RSS
bandcamp explorer

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

7. 1. 2011 (před 12 lety) — k47 (CC by-nc-sa)

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:

C# 3.0 vs. Scala

píše k47, ascii@k47.cz