k47.cz  — každý den dokud se vám to nezačne líbit
foto Praha výběr povídky kultura
twitter FB RSS

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

7. 1. 2011 — k47 (CC by-nc-sa) (♪)

C# je jazyk, který se vyvíjí docela dra­ma­ticky a každá nová verze při­nese pár za­jí­ma­vých no­vi­nek. Po­slední verze 4.0 zavádí pod­poru pro Dy­na­mic member lookup neboli duck typing. Typový systém jazyka je obo­ha­cen o pseu­do­typ dynamic, který se chová jako běžný System.Object, ale všechny pří­stupy k (i ne­e­xis­tu­jí­cím) me­to­dám, vlast­nos­tem a in­de­xe­rům jsou do­vo­leny bez ja­ké­koli typové kon­t­roly. Všechno se vy­hod­notí 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

Pro­blém tohoto pří­stupu je, že mi­ni­ma­li­zuje mož­nosti typové kon­t­roly a všechny pří­padné chyby se pro­jeví až při běhu apli­kace.

Scala dokáže vy­ře­šit stejný pro­blém pomocí struk­tu­rální typů a to do­konce ještě lépe než C#. Vý­sledný pro­gram je typově bez­pečný a všechny chyby jsou od­ha­leny ve fázi kom­pi­lace.

Struk­tu­rální typy ne­patří do kla­sické hi­e­rar­chie tříd a roz­hraní, jde o typ u něhož známe jen čás­teč­nou struk­turu, tedy jestli ob­sa­huje nějaké metody, člen­ské pro­měnné, typy nebo vnitřní třídy. Nemusí (i když může) být spe­ci­fi­ko­ván spo­leč­ným před­kem nebo roz­hra­ním. Struk­tu­rální typ je na­pří­klad { def close(): Unit } – do kte­rého spa­dají všechny ob­jekty mající metodu close, která ne­při­jímá žádné pa­ra­me­try a vrací Unit.

K me­to­dám a pro­měn­ným struk­tu­rál­ních typů se sa­mo­zřejmě bude při­stu­po­vat přes re­flexi (v JDK7 možná přes In­vo­ke­Dy­na­mic), ale kom­pi­lá­tor za­jistí, že celé řešení bude typově bez­peč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 srov­nání nových vlast­ností C# 4.0 se Scalou:

C# 3.0 vs. Scala

píše k47 & hosté, ascii@k47.cz