Cas na novy .NET jazyk

Cim viac switchujem medzi C# a Typescript, tym viac mi C# pride zastaraly.

Napriklad, preco v C# nemozem spravit Union alebo Intersection? Napr:

void DoSomethind(IFoo & IBar fooBar) { ... }

Alebo Literal Types

type Direction = "UP" | "DOWN" | "LEFT" | "RIGHT";  
void Move(Direction direction) { ... }

Alebo Mapped Types (typy namapovane na ine typy pomocou KeyOf a podobne)

Toto vsetko by mohlo vyborne fungovat nad CLR so vsetkymi vyhodami .NETu a prinieslo by to este lepsi type checking. Zaroven si myslim, ze lepit to do C# by uz bolo moc.

Nemyslite, ze je cas na novy jazyk?

Na F# si sa uz pozeral? Lebo to co pozadujes je dost podobne.

Napriklad, preco v C# nemozem spravit Union alebo Intersection?

Prave o Intersection som rozmyslal, ze tie by sa v pripade generik hodili

class Foo<T> where T: IFoo & IBar
{
}

Ale to je asi vsteko, tiez by som bol nerad keby priamo v jazyku skoncia discrimined union (co sa da uz dnes rieist source generatormi), a proste uz 90% veci co tam posledne tri verzie (uz pridavaju hrozne vela veci, ktore robia to iste ale inak a nici to cistotu jazyku).

Alebo Literal Types

Literal types ako su v typescripte mi nevonia, lebo je to cisto len nutna implementacia kvoli praseniu v javascripte. Proste v javascripte museli nejako vyriesit chybajuce enumy.

Zaroven si myslim, ze lepit to do C# by uz bolo moc.

Uplne suhlasim.

Nemyslite, ze je cas na novy jazyk?

Ja by som naopak bral, nieco ako C# classic, proste okresanu verziu C#, kde by neboli stare veci, ale proste tie starostlivo vybrane, aby mal tu “akademicku” cistotu zameranu na OPP ale s vyvazenymi prvkami FP.

Byt tebou skusim F#, ten ma v podstate vsteko co si popisal. Ja som ho skusal davnejsie ale bolo to len par experimentov.

Ja si myslim, ze v casoch pattern matchingu nepotrebuje nikto union typy. Potrebujes nieco, co sa podoba na iny typ, sprav si pattern matching. Mozno troska viac podpory napriklad v generikach.

Hlavne union typy sa daju plne nahradit obycajnym polymorfizmom a dokonca je to este pohodlnejsie (ked pridas dalsi typ do unionu nemusis prepisovat polku aplikacie). Popripade pouzit vzor double dispatch alebo visitor (v poslednej dobe ich vyuzivam pomerne dost).

No ak uz clovek chce uinion typy, tak ja momentalne pouzivam kniznicu Dunet, ma to velmi prehladny zapis typu a transformuje ho na polymorfizmus s cim som dusevne ok.

Asi by som mal povedat, ze tato tema ma napadla preto, ze teraz v C# riesim zasa UI (vdaka Blazoru) a pisem aj nejake kniznice. A tieto dve domeny maju trochu specificke naroky.

co sa da uz dnes riesit source generatormi

Ano, presne preto, aby sa to nemuselo riesit source generatormi. Isteze source generatori su sposob, ako vies vyriesit vela veci, ale je to imho najhorsi sposob, ked uz nic ine nezostava. (Anders Hejlsbers im branil takmer 15 rokov, cize niesom sam, kto si to mysli.)


Ja si myslim, ze v casoch pattern matchingu nepotrebuje nikto union typy

Praveze nie. Napriklad Int a String nemaju spolocnu base classu, cize toto:

function padLeft(padding: string | number): string {
 if (typeof padding === "number") {
     ...
 }
 else {
    ...
  }
}

by si musel napisal ako netypovy kod

string padLeft(object padding) 
{
     switch (padding)
     {
           case Int int: ...
               break;
           case string int:  ...
               break;
           default:
               throw new ArgumentException(nameof(padding));
     }
}

v pripade parametrov funkcii sa to este da riesit rozne, napriklad cez overload, ale property, alebo variable uz tak nevyriesis. Spominal si na WCF, ako generovalo DTOcka s WDL. Bud vygenerovalo property typu Object, alebo dve property. Obe je nespravne.


Iny Priklad. Vevies vytvorit z classy odvodenu classu, ktora ma vsetky property nullable - velmi sikovne pri tvorbe kniznic.

napr:

interface IMyState { string: Name; count: number };
public state: IMyState {get; set;}
void SetState(state: Optional<IMyState>) { .... }

setState({ count: 1 };

A ked z toho chces spravit genericke API, ani source generatori ti nepomozu.

Rovnako napriklad je obcas uzitocne odvodit classu, ktora ma iba readonly vlastnosti:

void foo<T>(value: Readonly<T>);

Literal types…Proste v javascripte museli nejako vyriesit chybajuce enumy

omyl. Enumy mohli vyriesit pridanim enumov, co aj spravili neskor.

takyto C# kod je uplne bezny:

void Foo(Direction someEnum)
{
    switch(someEnum)
    {
           case SomeEnum.Value1: ...
                break;
           case SomeEnum.Value2: ...
                throw new InvalidOperationException("Value 2 is not valid in this context");
           case SomeEnum.Value3: ...
                 break;
           default:
               throw new ArgumentOutOfRangeException();
    }
}

v typescripte vies spravit odvodeny typ, ktory nebude obsahovat Value2.

Type SomeEnumWithoutValue1 = Extract<SomeEnum, SomeEnum.Value3>;

Ano, presne preto, aby sa to nemuselo riesit source generatormi. Isteze source generatori su sposob, ako vies vyriesit vela veci, ale je to imho najhorsi sposob, ked uz nic ine nezostava. (Anders Hejlsbers im branil takmer 15 rokov, cize niesom sam, kto si to mysli.)

Ja si naopak myslim, ze source generatori su cesta ako do jazyka dostat nove featury, ked ich potrebujes a sucasne ho nezaplevelit.

Inac taky F# ma source generatori uz poriadne dlho (pocul som o nich pred 7 mimi rokmi), len ich nazyvaju type provideri, no technicky je to to iste.

by si musel napisal ako netypovy kod

V tomto pripade, ked nechces pouzit source genertori tak pouzijes kniznicu AnyOf. Co sa tyka WCF tak to zvlada polymorfizmus co je za mna semantickejsie rienie.

omyl. Enumy mohli vyriesit pridanim enumov, co aj spravili neskor.

Javascript enumy stale nema, ma ich typescript. String literals je tam pre to, ze mnoho existujuceho JS api pouziva stringy namiesto enumov.

takyto C# kod je uplne bezny:

Viem co tym chces povedat a suhlasim. Na druhej strane, ak mas takyto kod, dakde budes musiet previest ten povodny enum na mapovany a ten throw sa ti priste presunie tam. No beriem, ze je to lepsi sposob.

Ja v tomto pripade, ak ide o public api radsej definujem dalsi enum.