Problémy s JavaScript v praxi

ava

Re:Problémy s JavaScript v praxi
« Odpověď #585 kdy: 13. 10. 2018, 15:18:14 »
Jakékoli zpracování stromu se bez toho neobejde - uzly i listy mohou být tvořeny instancemi různých tříd dle potřeby. Stačí mít společné rozhraní.
Ano, to je přesně místo, kde se perfektně využijí součtové typy - garantují, že uzly/listy mohou nabývat pouze předem definovaných hodnot (instance konkrétních tříd). Kotlin už tohle umožňuje jako tzv. sealed classes. Naopak přístup Javy  je spíš přístupem dynamického jazyka - ta třída je interně otagovaná a při přetypování (nebo instanceOf) se ty tagy runtime porovnávají.

Jen ze zvědavosti - rozumím, že často se hodí graf (,list, atp.) kde jsou hodnoty nějakého uzavřeného typu (součtový typ). Co když chci mít v Haskellu typ otevřený? Je možné mít např. hodnoty "všech typů, které jsou instancí nějaké typeclass"? V Rustu tohle jde (trait objects), v Javě a spol. to skoro jinak ani nejde (použije se třídní polymorfizmus), jak je to v Haskellu?


v

Re:Problémy s JavaScript v praxi
« Odpověď #586 kdy: 13. 10. 2018, 15:35:58 »
Jakékoli zpracování stromu se bez toho neobejde - uzly i listy mohou být tvořeny instancemi různých tříd dle potřeby. Stačí mít společné rozhraní.
Ano, to je přesně místo, kde se perfektně využijí součtové typy - garantují, že uzly/listy mohou nabývat pouze předem definovaných hodnot (instance konkrétních tříd). Kotlin už tohle umožňuje jako tzv. sealed classes. Naopak přístup Javy  je spíš přístupem dynamického jazyka - ta třída je interně otagovaná a při přetypování (nebo instanceOf) se ty tagy runtime porovnávají.

Jen ze zvědavosti - rozumím, že často se hodí graf (,list, atp.) kde jsou hodnoty nějakého uzavřeného typu (součtový typ). Co když chci mít v Haskellu typ otevřený? Je možné mít např. hodnoty "všech typů, které jsou instancí nějaké typeclass"? V Rustu tohle jde (trait objects), v Javě a spol. to skoro jinak ani nejde (použije se třídní polymorfizmus), jak je to v Haskellu?
dovolím si odpovědět za andyho, jo, jde to

v

Re:Problémy s JavaScript v praxi
« Odpověď #587 kdy: 13. 10. 2018, 15:40:10 »
jedna z obecnějších možností:
Kód: [Vybrat]
{-# LANGUAGE ExistentialQuantification, ConstraintKinds, GADTs #-}

data Ex c = forall x. c x => Ex x

instance x ~ Show => Show (Ex x) where
    show (Ex x) = show x

xxx :: [Ex Show]
xxx = [Ex (), Ex 2, Ex "3"]

main = print xxx

Kit

Re:Problémy s JavaScript v praxi
« Odpověď #588 kdy: 13. 10. 2018, 18:23:35 »
Jakékoli zpracování stromu se bez toho neobejde - uzly i listy mohou být tvořeny instancemi různých tříd dle potřeby. Stačí mít společné rozhraní.
Ano, to je přesně místo, kde se perfektně využijí součtové typy - garantují, že uzly/listy mohou nabývat pouze předem definovaných hodnot (instance konkrétních tříd). Kotlin už tohle umožňuje jako tzv. sealed classes. Naopak přístup Javy  je spíš přístupem dynamického jazyka - ta třída je interně otagovaná a při přetypování (nebo instanceOf) se ty tagy runtime porovnávají.

Jaké přetypování máš na mysli? Jaké instanceOf? To někdo používá?

andy

Re:Problémy s JavaScript v praxi
« Odpověď #589 kdy: 13. 10. 2018, 22:58:59 »
Jakékoli zpracování stromu se bez toho neobejde - uzly i listy mohou být tvořeny instancemi různých tříd dle potřeby. Stačí mít společné rozhraní.
Ano, to je přesně místo, kde se perfektně využijí součtové typy - garantují, že uzly/listy mohou nabývat pouze předem definovaných hodnot (instance konkrétních tříd). Kotlin už tohle umožňuje jako tzv. sealed classes. Naopak přístup Javy  je spíš přístupem dynamického jazyka - ta třída je interně otagovaná a při přetypování (nebo instanceOf) se ty tagy runtime porovnávají.

Jaké přetypování máš na mysli? Jaké instanceOf? To někdo používá?
Neuvědomil jsem si, že se ptáš na objekty se stejným rozhraním. Byl jsem už o krok dál, občas člověk potřebuje ukládat  nějaké objekty, na které napasovat stejné rozhraní je trošku přes ruku. Ta odpověď od v je správně, přes ConstraintKinds a ExistentialQuantification se dá tohle udělat docela pěkně. Z nějakého důvodu se to považuje spíš za anti-pattern, ale mám trošku podezření, že tohle je pravidlo ve stylu "nejdřív se ho nauč, a pak ho porušuj".


Kit

Re:Problémy s JavaScript v praxi
« Odpověď #590 kdy: 13. 10. 2018, 23:30:42 »
Jakékoli zpracování stromu se bez toho neobejde - uzly i listy mohou být tvořeny instancemi různých tříd dle potřeby. Stačí mít společné rozhraní.
Ano, to je přesně místo, kde se perfektně využijí součtové typy - garantují, že uzly/listy mohou nabývat pouze předem definovaných hodnot (instance konkrétních tříd). Kotlin už tohle umožňuje jako tzv. sealed classes. Naopak přístup Javy  je spíš přístupem dynamického jazyka - ta třída je interně otagovaná a při přetypování (nebo instanceOf) se ty tagy runtime porovnávají.

Jaké přetypování máš na mysli? Jaké instanceOf? To někdo používá?
Neuvědomil jsem si, že se ptáš na objekty se stejným rozhraním. Byl jsem už o krok dál, občas člověk potřebuje ukládat  nějaké objekty, na které napasovat stejné rozhraní je trošku přes ruku.

Vždycky se objekty dají napasovat na společné rozhraní - v nouzi použiješ proxy. Společné rozhraní však mívám už v okamžiku návrhu, teprve pak řeším implementaci komponent.

andy

Re:Problémy s JavaScript v praxi
« Odpověď #591 kdy: 14. 10. 2018, 09:07:55 »
Vždycky se objekty dají napasovat na společné rozhraní - v nouzi použiješ proxy. Společné rozhraní však mívám už v okamžiku návrhu, teprve pak řeším implementaci komponent.
Ano, vždycky dají...... a často to bývá zbytečné žonglování, když se to dá vyřešit součtovým typem...

Kit

Re:Problémy s JavaScript v praxi
« Odpověď #592 kdy: 14. 10. 2018, 10:11:01 »
Vždycky se objekty dají napasovat na společné rozhraní - v nouzi použiješ proxy. Společné rozhraní však mívám už v okamžiku návrhu, teprve pak řeším implementaci komponent.
Ano, vždycky dají...... a často to bývá zbytečné žonglování, když se to dá vyřešit součtovým typem...

Zbytečné žonglování je to jen tehdy, když se snažíš udělat rozhraní až dodatečně místo předem.

andy

Re:Problémy s JavaScript v praxi
« Odpověď #593 kdy: 14. 10. 2018, 11:06:49 »
Vždycky se objekty dají napasovat na společné rozhraní - v nouzi použiješ proxy. Společné rozhraní však mívám už v okamžiku návrhu, teprve pak řeším implementaci komponent.
Ano, vždycky dají...... a často to bývá zbytečné žonglování, když se to dá vyřešit součtovým typem...

Zbytečné žonglování je to jen tehdy, když se snažíš udělat rozhraní až dodatečně místo předem.
Rád se poučím - jak v Javě implementuješ normální binární strom? V jazycích se součtovými typy se to dělá takhle:
Kód: [Vybrat]
data Tree a = Node (Tree a) (Tree a) | Leaf aJak to uděláš v Javě? Buď si uděláš dvě třídy (Node, Leaf) a budeš to přetypovávat. Nebo nad to uděláš společný interface (případně to rovnou vrazíš do jedné třídy), a budeš tam mít metody typu "isNode", "isLeaf", "getLeft", "getRight". To ti pro změnu nezabrání udělat "getLeft" na Leaf, takže ten společný interface je dost násilný. Nebo do interfacu dáš metodu "udělěj()" a budeš to v podstatě řešit přes inversion of control (což by byla zrovna tady docela lahůdka). Nic jiného mě nenapadá, ale nejsem Java nejvyšší guru - jaké je podle tebe to správné řešení?

A samozřejmě totéž se může stát u konkrétních hodnot - mohou mít něco společného, ale také můžou mít diametrálně odlišné vlastnosti. Součtový typ je logické řešení a hezky se mapuje na to, co to má modelovat - prvek je "A nebo B nebo C". Rvát na to stejný interface je prostě snaha ten součtový typ nějak namodelovat.

Kit

Re:Problémy s JavaScript v praxi
« Odpověď #594 kdy: 14. 10. 2018, 12:07:48 »
Vždycky se objekty dají napasovat na společné rozhraní - v nouzi použiješ proxy. Společné rozhraní však mívám už v okamžiku návrhu, teprve pak řeším implementaci komponent.
Ano, vždycky dají...... a často to bývá zbytečné žonglování, když se to dá vyřešit součtovým typem...

Zbytečné žonglování je to jen tehdy, když se snažíš udělat rozhraní až dodatečně místo předem.
Rád se poučím - jak v Javě implementuješ normální binární strom? V jazycích se součtovými typy se to dělá takhle:
Kód: [Vybrat]
data Tree a = Node (Tree a) (Tree a) | Leaf aJak to uděláš v Javě? Buď si uděláš dvě třídy (Node, Leaf) a budeš to přetypovávat. Nebo nad to uděláš společný interface (případně to rovnou vrazíš do jedné třídy), a budeš tam mít metody typu "isNode", "isLeaf", "getLeft", "getRight". To ti pro změnu nezabrání udělat "getLeft" na Leaf, takže ten společný interface je dost násilný. Nebo do interfacu dáš metodu "udělěj()" a budeš to v podstatě řešit přes inversion of control (což by byla zrovna tady docela lahůdka).

V Javě nedělám, ale v PHP tohle řeším právě přes to "udělěj()". Je to mnohem jednodušší než ostatní uvažovaná řešení. Hlavně tím odpadnou zbytečné metody "isNode", "isLeaf", "getLeft", "getRight" apod. Nehledě k tomu, že tento přístup by tě omezoval pouze na binární stromy.

ava

Re:Problémy s JavaScript v praxi
« Odpověď #595 kdy: 14. 10. 2018, 13:15:16 »
Vždycky se objekty dají napasovat na společné rozhraní - v nouzi použiješ proxy. Společné rozhraní však mívám už v okamžiku návrhu, teprve pak řeším implementaci komponent.
Ano, vždycky dají...... a často to bývá zbytečné žonglování, když se to dá vyřešit součtovým typem...

Zbytečné žonglování je to jen tehdy, když se snažíš udělat rozhraní až dodatečně místo předem.
Rád se poučím - jak v Javě implementuješ normální binární strom? V jazycích se součtovými typy se to dělá takhle:
Kód: [Vybrat]
data Tree a = Node (Tree a) (Tree a) | Leaf aJak to uděláš v Javě? Buď si uděláš dvě třídy (Node, Leaf) a budeš to přetypovávat. Nebo nad to uděláš společný interface (případně to rovnou vrazíš do jedné třídy), a budeš tam mít metody typu "isNode", "isLeaf", "getLeft", "getRight". To ti pro změnu nezabrání udělat "getLeft" na Leaf, takže ten společný interface je dost násilný. Nebo do interfacu dáš metodu "udělěj()" a budeš to v podstatě řešit přes inversion of control (což by byla zrovna tady docela lahůdka).

V Javě nedělám, ale v PHP tohle řeším právě přes to "udělěj()". Je to mnohem jednodušší než ostatní uvažovaná řešení. Hlavně tím odpadnou zbytečné metody "isNode", "isLeaf", "getLeft", "getRight" apod. Nehledě k tomu, že tento přístup by tě omezoval pouze na binární stromy.

Jo, když má člověk v arzenálu i součtový typ, i nějakou formu polymorfizmu, může si vybrat, a každé řešení má svoje pro a proti.

Když použiju součtový typ, těžko se mi rozšiřuje množina hodnot, nad kterými můžu operovat (musím editovat původní zdroják), ale snadno se mi rozšiřuje množina algoritmů, které s tím pracují (použiju pattern matching, mám zaručený exahustiveness checking).

Když použiju otevřený typ (interface/instance), snadno se mi rozšiřuje množina hodnot (prostě někde jinde udělám novou instanci a ono to s ní funguje), ale blbě se mi rozšiřuje množina algoritmů (chci třeba umět každou hodnotu vykreslit, což by znamenalo přidat do interface nějakou metodu "draw" - musím editovat původní zdroják).

Takže podle situace je prostě vhodnější jedno nebo druhé, součtový typ používám tam, kde očekávám že typ se nebude moc rozšiřovat (třeba AST nějakého daného jazyka), otevřený typ tam, kde se zas moc nebudou rozšiřovat operace nad tím typem, ale chci mít možnost přidat další hodnoty (třeba grafické widgety si chci mít možnost přidělat v nějakém rozšiřujícím modulu, ale operace přibývat nebudou - bude tam nějaké kreslení, události atp. a hotovo).

Když chci oboje, dostanu https://en.wikipedia.org/wiki/Expression_problem :-)

Takže je to spíš rozhodnutí podle specifického případu, který řeším, než podle jazyka - ovšem za předpokladu, že mám slušný jazyk, který umí součtové typy :) Jinak se to skutečně musí v OOP bez ADT řešit přes dispatch na nějaké "udělej". Ona to v praxi není zas taková tragédie, když si na to člověk zvykne, ale mít k dispozici skutečný součtový typ a pattern matching je samozřejmě mnohem lepší...

Bacsa

Re:Problémy s JavaScript v praxi
« Odpověď #596 kdy: 14. 10. 2018, 13:28:12 »
Vždycky se objekty dají napasovat na společné rozhraní - v nouzi použiješ proxy. Společné rozhraní však mívám už v okamžiku návrhu, teprve pak řeším implementaci komponent.
Ano, vždycky dají...... a často to bývá zbytečné žonglování, když se to dá vyřešit součtovým typem...

Zbytečné žonglování je to jen tehdy, když se snažíš udělat rozhraní až dodatečně místo předem.
Rád se poučím - jak v Javě implementuješ normální binární strom? V jazycích se součtovými typy se to dělá takhle:
Kód: [Vybrat]
data Tree a = Node (Tree a) (Tree a) | Leaf aJak to uděláš v Javě? Buď si uděláš dvě třídy (Node, Leaf) a budeš to přetypovávat. Nebo nad to uděláš společný interface (případně to rovnou vrazíš do jedné třídy), a budeš tam mít metody typu "isNode", "isLeaf", "getLeft", "getRight". To ti pro změnu nezabrání udělat "getLeft" na Leaf, takže ten společný interface je dost násilný. Nebo do interfacu dáš metodu "udělěj()" a budeš to v podstatě řešit přes inversion of control (což by byla zrovna tady docela lahůdka).
V Javě nedělám, ale v PHP tohle řeším právě přes to "udělěj()". Je to mnohem jednodušší než ostatní uvažovaná řešení. Hlavně tím odpadnou zbytečné metody "isNode", "isLeaf", "getLeft", "getRight" apod. Nehledě k tomu, že tento přístup by tě omezoval pouze na binární stromy.
Gratuluju k objevu volných monád.

Kit

Re:Problémy s JavaScript v praxi
« Odpověď #597 kdy: 14. 10. 2018, 13:54:45 »
V Javě nedělám, ale v PHP tohle řeším právě přes to "udělěj()". Je to mnohem jednodušší než ostatní uvažovaná řešení. Hlavně tím odpadnou zbytečné metody "isNode", "isLeaf", "getLeft", "getRight" apod. Nehledě k tomu, že tento přístup by tě omezoval pouze na binární stromy.
Gratuluju k objevu volných monád.

Nevím, co je volná monáda (prosím zdroj) ale je to úplně normální OOP.

andy

Re:Problémy s JavaScript v praxi
« Odpověď #598 kdy: 14. 10. 2018, 17:55:14 »
V Javě nedělám, ale v PHP tohle řeším právě přes to "udělěj()". Je to mnohem jednodušší než ostatní uvažovaná řešení. Hlavně tím odpadnou zbytečné metody "isNode", "isLeaf", "getLeft", "getRight" apod. Nehledě k tomu, že tento přístup by tě omezoval pouze na binární stromy.
Když vyrábím vyvážený binární strom, tak mě fakt netrápí, že tento přístup mě omezuje pouze na binární stromy...
Ten problém je, když máš na jednom místě věci, které dělají něco jiného. Funkce "vraťPotomky" nedává smysl na listu (při vyvažování), takže bude nějak stupidně implementovaná. Nebo se to celý můžeš pokusit obrátit,  psát uzlu, aby "vyvážil sebe", jenže uzel nezná svého rodiče, takže to začne být správný sado-maso kód...

Nebo třeba jsem řešil problém, kdy si uživatel v aplikaci volí různé způsoby navigace a pak má na obrazovce různé informace. Problém je, že pro některé typy navigace ty infoboxy prostě nedávají smysl. Takže buď zvolím nějaký interface, který u většiny navigací bude vracet nějaký nesmysl nebo noop (a to i u toho udělej()), a nebo si v tom infoboxu udělám přetypování na tu konkrétní navigaci a budu volat metody přímo. Což je nejelegantnější, a kdyby Java měla součtové typy, tak i čisté.

Součtové typy samozřejmě neřeší všechno, Expression problem je bohužel realita, ale překvapivě hodně věcí se tím modeluje fakt dobře. Což je taky důvod, proč se to v nových jazycích objevuje stále častěji.

Kit

Re:Problémy s JavaScript v praxi
« Odpověď #599 kdy: 14. 10. 2018, 20:38:21 »
V Javě nedělám, ale v PHP tohle řeším právě přes to "udělěj()". Je to mnohem jednodušší než ostatní uvažovaná řešení. Hlavně tím odpadnou zbytečné metody "isNode", "isLeaf", "getLeft", "getRight" apod. Nehledě k tomu, že tento přístup by tě omezoval pouze na binární stromy.
Když vyrábím vyvážený binární strom, tak mě fakt netrápí, že tento přístup mě omezuje pouze na binární stromy...
Ten problém je, když máš na jednom místě věci, které dělají něco jiného. Funkce "vraťPotomky" nedává smysl na listu (při vyvažování), takže bude nějak stupidně implementovaná. Nebo se to celý můžeš pokusit obrátit,  psát uzlu, aby "vyvážil sebe", jenže uzel nezná svého rodiče, takže to začne být správný sado-maso kód...

Nebo třeba jsem řešil problém, kdy si uživatel v aplikaci volí různé způsoby navigace a pak má na obrazovce různé informace. Problém je, že pro některé typy navigace ty infoboxy prostě nedávají smysl. Takže buď zvolím nějaký interface, který u většiny navigací bude vracet nějaký nesmysl nebo noop (a to i u toho udělej()), a nebo si v tom infoboxu udělám přetypování na tu konkrétní navigaci a budu volat metody přímo. Což je nejelegantnější, a kdyby Java měla součtové typy, tak i čisté.

Součtové typy samozřejmě neřeší všechno, Expression problem je bohužel realita, ale překvapivě hodně věcí se tím modeluje fakt dobře. Což je taky důvod, proč se to v nových jazycích objevuje stále častěji.

Jsem sice známý tím, že nerad používám frameworky, ale přece jen už nemám potřebu programovat AVL stromy, když dnešní jazyky mají řazení jako součást syntaktického cukru.

Různé informace na obrazovce řeším různými objekty. Mohu je mezi sebou vyměňovat dle potřeby. Jak prosté - SRP je mnohem lepší než dělat nějaký God object.

Nevím, proč bych měl řešit součtové typy, když PHP to má už v základu.