Žádné zlo to není. Ani žádné dobro. Je to prostě jedna z mnoha platforem, resp. jeden z mnoha programovacích jazyků, v tomhle případě se zajímavým návrhem ale celkem mizernou implementací.
A představa, že budeme obecně vyvíjet weby ve WebAssembly je, mírně řečeno, nesmyslná a ukazuje, že to evidentně není váš obor a vyprávíte o něčem, o čem nic nevíte. V zásadě je to stejné, jako tvrdit, že shell skripty jsou zlo a všude by měla být možnost skriptovat v binárně kompilovaném jazyce (ano, ten antagonismus vidíte správně).
Přesně naopak, JavaScript je jazyk s nedomyšleným návrhem, který nejde aktualizovat tak, aby z toho nebyl úplně jiný jazyk. To je celý jeho problém.
WebAssembly je bytekód a jeho představa není, že budeme vyvíjet ve wasm, ale v čemkoliv, co do něj jde skompilovat. Už teď se JS bundluje a minifikuje a "psaný" zdroják má hodně daleko k tomu "spouštenému". Srovnání se shell skripty je úplný nesmysl.
Nepiš mu, že tomu nerozumí, když ani nevíš o čem je řeč.
Akorát ES4 neadresuje žádný z opravdu nepříjemných problémů JavaScriptu (mnoho ze seznamu https://github.com/denysdovhan/wtfjs existovalo už tenkrát). A co máme dnes v moderním JS a zejména TS je lepší a IMO i lépe navržené (snad až na třídy), než by bylo ES4.
Jasně. Až na to, že mě Linux, web a JavaScript asi tak patnáct let živí vlastně vůbec nevím, o čem je řeč. Ostatně srovnávat "bundlování", resp. transpilaci abychom byli korektní, a minifikaci JavaScriptu s kompilací do binárních balíčků může jen jakýsi anonym na diskuzi, že.
Ano, nerozumí. To, co napsal je nesmysl. Ve WASM se pochopitelně vyvíjet aplikace dají. A je celkem pravděpodobné, že časem vznikne i skutečně použitelné napojení na DOM nebo že naopak DOM bude nahrazené něčím jiným co bude tvořít renderovací platformu. Ale samo o sobě je to přesně jako s těmi shell scripty a ty jeho a zvlášť ten váš blábol jen ukazuje, že vůbec nechápete odkud JavaScript přišel a proč. Nemluvě o tom, že evidentně ani nechápete proč je ten návrh jaký je.
Je to ostatně jev, který sleduju u celkem dost lidí z nové generace vývojářů. Což je asi samo o sobě přirozené. Jenže pak máte problém pochopit, proč je některá technologie úspěšná a z jakého důvodu.
mě web živí tak dlouho, že ještě pamatuji dobu, kdy JS vyšel ve své první verzi a nebo, že se weby daleko více psaly pomocí activex, java appletů či flashe (jako action script). Tak doufám, že se k tomu mohu podle tvých měřítek vyjádřit.
JS je prostě ošklivé káčátko, pamatuješ na tanečky kolem ECMAScript 4? Tenhle okamžik je hodně důležitý, ovlivnilo to jak dnes JS vypadá a proč dnes JS je špatný jazyk.
JS v současné době je neskutečná bariéra pro to, aby weby mohly být výrazně bezpečnější. Stejně tak JS stojí za tím, že současné weby jsou neskutečně náročné na HW prostředky. Nenabízí jiné řešení než to brát hrubou silou ala React.
Ten jazyk je příliš jednoduchý na dnešní potřeby, špatně podporuje více cpu, vůbec nepodporuje asymetrická cpu jádra, hodně nešikovně podporuje úsporné režimi, nepodporuje správně izolaci procesů od sebe (ano, prohlížeče musí díky tomu spouštět procesy odděleně přes thready), nemá prostor pro bezpečnou implementaci šifrovacích algoritmů. Google pak přes Chrome do něj zpřístupňuje věci, které by vůbec zpřístupňovat neměl.
Ten jazyk měl zůstat tím, kým byl a nesnažit se z něho udělat univerzální věc pro vývoj. Příprava ES6 sebrala neskutečně moc člověkohodin a promarnila šanci posunout webový vývoj zase o kus dál, je to pouze pozlátko.
...: Jak je vidět, to, že vás web živí, neznamená, že těm technologiím rozumíte.
Bezpečnost moc nesouvisí s použitým jazykem. Respektive pokud by se web psal třeba v C a hrozily tam chyby typu buffer overflow, byla by bezpečnost snížená programovacím jazykem. Ale JavaScript má automatickou správu paměti, takže tento typ chyb nehrozí, stejně jako nehrozí jiné typy bezpečnostních chyb dané programovacím jazykem. Zkrátka z pohledu bezpečnosti je na tom JavaScript stejně dobře, jako desítky dalších jazyků.
Za „náročností na HW prostředky“ je podle mne DOM a ne JavaScript. Ale když to porovnáte s jinými přístupy, nejsou na tom webové aplikace nijak zle. Multiplatformní aplikace napsané v Javě nebo s Qt na tom budou co se týče zdrojů podobně.
JavaScript je jednovláknový, což ale například dává velké možnosti interpretu/JIT, takže to nemusí být na škodu. Nepodpora asymetrických CPU jader nebo úsporných režimů je blábol – když už si něco vymýšlíte, zkuste se alespoň zamyslet nad tím, zda by to alespoň teoreticky mohla být pravda (plánování procesů na CPU a řízení spotřeby dělá OS, programovací jazyk je od toho kilometry daleko). Izolace procesů opět není věcí programovacího jazyka – proces je objekt operačního systému, procesy od sebe musí izolovat operační systém, nemůžete to nechat na procesech samotných.
Nevím, co myslíte „prostorem pro bezpečnou implementaci šifrovacích algoritmů“. Šifrovací algoritmy můžete bezpečně implementovat i v JavaScriptu. Pokud vám jde o to, abyste měl třeba lépe chráněné klíče v paměti, to je věc běhového prostředí a ne programovacího jazyka – a kdyby někdo chtěl, může takové běhové prostředí implementovat i pro JavaScript.
Zpřístupňování různých služeb skrze API webového prohlížeče nedělá jen Chrome, dělají to všechny prohlížeče. Nijak to nesouvisí s JavaScriptem – ten můžete používat i mimo prohlížeč a opačně, ta webová API nejsou principiálně vázána na JavaScript, akorát je shodou okolností v tuto chvíli JavaScriptový engine v prohlížečích jediný, kdo k nim má přístup. Ale v budoucnu budou přístupná i pro WebAssembly.
Navíc to, že jsou tyhle služby zpřístupňovány skrze omezené API chráněné oprávněním, je v pořádku. Porovnejte si to s tím, jak se to dělá mimo prohlížeč – prostě ty služby může volat každá aplikace, neomezeně, nepotřebuje k tomu od uživatele žádné oprávnění.
Nikdo neměl v plánu udělat z JavaScriptu univerzální jazyk pro vývoj. Ale byl to jediný jazyk dostupný v prohlížečích, tak ho prostě vývojáři používali, jak jen to šlo. Teprve v závěsu za tím šel vývoj jazyka a webových prohlížečů, které jen reagovali na to, co se v praxi používalo. Podle vás se asi měl vyvinout zcela nový jazyk pro prohlížeče a vše ostatní se do té doby mělo zastavit. Jenže ten nový jazyk se vyvíjí – WebAssembly. A podívejte se, jak dlouho to trvá. To se podle vás měl webový vývoj na deset nebo patnáct let zastavit? On by se nezastavil, jenom by šel jinou cestou – třeba Flashe nebo Silverlight.
Bezpečnost moc nesouvisí s použitým jazykem
K tomu nemám komentář. Vždyť to i sám hned v tom odstavci popíráš.
Kdyby za tím byl jen DOM, problém by vyřešily nástroje jako react nebo vue, ne? Neřeší to. JS nenabízí efektivní cesty a vede k spamování event loopy (např. způsob zpracování promise nebo timerů). Jen režije timerů je třeba u webových aplikací i desítky % (tab throttling toho je důkazem). JS nenabízí lepší možnosti. Však si zkus vzít profiler na JS kód v prohlížeči a uvidíš.
Ano, jednovláknový, to nedává OS moc možnosti, jak jeho práci správně plánovat a rozložit, vede to k protěžování jednoho CPU jádra a zvedání jeho frekvence, místo aby se práce rozložila přes více. Výrobci HW a prohlížečů musejí dělat ohejbáky, aby to fungovalo lépe.
JS nechrání proti útokům jako code injection nebo side-channel attacks. Nelze zabezpečit vstupy od uživatele a zabránit, aby citlivé údaje unikly (to se týká i node.js). Web crypto api od W3C problém neřeší, je to pouze částečná záplata.
Nikdo neměl v plánu udělat z JavaScriptu univerzální jazyk pro vývoj
Na to odpovíám citací ze standardu:
This Standard defines the ECMAScript 2021 general-purpose programming language.
Ano, wasm měl vzniknout daleko dříve, aktivita se začala už s ES4, pak dlouho nic a až herní průmysl (a lidi kolem webgl v mozille) to začal více tlačit, nebýt třeba Alona Zakai, asi by to ještě dlouho nikam nevedlo.
> ...: Ano, jednovláknový, to nedává OS moc možnosti, jak jeho práci správně plánovat a rozložit, vede to k protěžování jednoho CPU jádra a zvedání jeho frekvence, místo aby se práce rozložila přes více. Výrobci HW a prohlížečů musejí dělat ohejbáky, aby to fungovalo lépe.
To samé můžeš říct i o C/C++ ;-) Taky je jednovláknové a musíš používat speciální funkce pro vytvoření a práci s dalšími vlákny*. A protože je to pro méně zkušené programátory komplikované, tak spousta GUI aplikací vytěžuje jedno jádro CPU na max a "zamrzá". Ano, jsou knihovny, které některé operace umí rozložit na více vláken automaticky, ale takové nadstavby jsou i pro ten JS (knihovny pro usnadnění využívání více jader).
Jinak pro OS je naopak mnohem jednodušší plánovat jednovláknové aplikace. Naopak taková Electron aplikace na 20 vláken, co se rozleze na všechna jádra, to je peklo.
EDIT: *) I v C/C++ je spousta knihoven, včetně GUI a grafických, bez plné podpory multithreadingu. Takže na tom nejseš o nic líp než v JS, kde WebWorker dělá jen početní práci, ale nemůže např. přímo "kreslit do okna".
9. 8. 2022, 13:36 editováno autorem komentáře
K tomu nemám komentář. Vždyť to i sám hned v tom odstavci popíráš.
Nepopírám. V následujícím odstavci jsem napsal, že bezpečnost může ohrozit třeba chybějící automatická správa paměti. Což ale není věc přímo programovacího jazyka – i v C můžete používat automatickou správu paměti, když použijete nějakou knihovnu.
Kdyby za tím byl jen DOM, problém by vyřešily nástroje jako react nebo vue, ne?
Proč píšete o něčem, o čem vůbec nic nevíte? React nebo Vue samozřejmě také používají DOM.
JS nenabízí efektivní cesty a vede k spamování event loopy (např. způsob zpracování promise nebo timerů). Jen režije timerů je třeba u webových aplikací i desítky % (tab throttling toho je důkazem).
Což ovšem není problém JS, nýbrž nějakého „programátora“, který nějaké vizuální efekty programuje pomocí JavaScriptu, místo toho, aby použil CSS.
Ano, jednovláknový, to nedává OS moc možnosti, jak jeho práci správně plánovat a rozložit, vede to k protěžování jednoho CPU jádra a zvedání jeho frekvence, místo aby se práce rozložila přes více.
Naopak to, že je jednovláknový a interpretovaný, dává možnosti interpretu to optimalizovat. Jinak z hlediska spotřeby je samozřejmě lepší, když běží jedno CPU s vyšší spotřebou než dvě CPU s jednotkovou nižší spotřebou, ale v součtu vyšší spotřebou.
JS nechrání proti útokům jako code injection nebo side-channel attacks.
To žádný jazyk.
Nelze zabezpečit vstupy od uživatele a zabránit, aby citlivé údaje unikly
Lze. if existuje i v JavaScriptu.
Web crypto api od W3C problém neřeší, je to pouze částečná záplata.
Web crypto API slouží k něčemu úplně jinému.
Zhruba rámcově souhlasím, protože u hodně věcí je správná odpověď "it depends". U CSS vs JavaScript nesouhlasím. Je řada věcí, které čistě v CSS udělat nejde vůbec nebo to bude tak složité, že to bude nepraktické. Dost pravděpodobně to bude mít grafické glitche/ nebude to rychlé. Někdy je to naopak, ale opravdu CSS není obecně uplatnitelný nástroj na vizuální efekty.
Děláme jeden takový "drobný" projekt, který odhaluje různé nešvary/ limity "webových" API.
Adam Kalisz: To je pak zase na domluvě s designery, zda tam opravdu musí být takový efekt, který nejde udělat pomocí CSS. Protože to často vznikne jenom tím, že takový efekt designer snadno vyrobí ve svém nástroji, ale v CSS jde udělat jiný, velmi podobný efekt – a designerovi je vlastně jedno, který se použije. (Tohle už naštěstí přestává být problém s Figmou, která je zaměřená primárně na web.)
Samozřejmě že někdy narazíte na limity a někdy má ten efekt smysl a musí se naprogramovat v JavaScriptu. Ale asi ne přes timery, že.
"... pamatuješ na tanečky kolem ECMAScript 4? Tenhle okamžik je hodně důležitý, ovlivnilo to jak dnes JS vypadá a proč dnes JS je špatný jazyk."
Samozřejmě. A já osobně zcela souhlasím (a říkám to už léta) s tím, že snahou namontovat do JS něco, co tam původně nebylo ten jazyk zprasili velice solidně. To se naprosto nevylučuje. Bohužel.
JS v současné době je neskutečná bariéra pro to, aby weby mohly být výrazně bezpečnější.
A čím tu bariéru konkrétně tvoří?
Stejně tak JS stojí za tím, že současné weby jsou neskutečně náročné na HW prostředky.
Většinu výkonu sežere renderování, nikoliv běh skriptů. Je naprosto jedno, čím budete ten renderovací engine rozhýbávat. I když pravda, dost výkonu žerou některé frameworky, které se snaží řešit některé problémy ve vývoji (nikoliv s platformou) čímž efektivně způsobují další problémy.
Nenabízí jiné řešení než to brát hrubou silou ala React.
Což je nesmysl. Třeba Svelte to tak skutečně nedělá. A když budete modifikovat přímo DOM, taky se to dít nebude. Naopak: React tím začíná být poněkud zastaralý. Ale to je jiná diskuze.
Aha, další, co nechápe co je návrhem JavaScript vlastně zač ale má plnou hubu odsudků. U pohovorů je takových tak polovina. A jinak JavaScript mohl Javě konkurovat asi jako VBScript céčku; od začátku se používal pro úplně jiné úlohy a trochu se jí přiblížil až v posledních letech a to ještě ne úplně.
V době, kdy JavaScript vznikal byla Java jazyk víceméně na psaní javových appletů do browserů (tj. čistě front-end). Serverová a korporátní popularita Javy jako jazyka pro psaní back-endu přišla později. Ještě v roce 1996 knížka o Javě, kterou jsem si tehdy pořídil byla čistě o psaní apletů, o nějakém použití na serveru v ní nebylo ani písmenko. První specifikace Java servletů pochází z konce roku 1996, JSP 1999... Takže jak to myslíte, že Java a JavaScript byly od začátku určené na něco jiného?
Skriptování na straně klienta a psaní appletů byly absolutně rozdílné technologie. Applety vycházely z tehdy rozšířeného principu remote objects, a byly odpovědí na ms technologii DCOMu. JavaScript původně sloužil k automatizaci klienta - byla to analogie s microsoft vba v Microsoft Office.
Java rozhodně nebyla designovaná pro applety - vznikla v době, kdy http protokol byl v plenkách. Ale byla navržená tak, aby byla platformě nezávislá už s podporou remote objects, a s velice dobrou podporou TCP/IP. První applety byly defakto tlustí klienti běžící v prohlížeči. V druhé polovině 90 let byly jen dvě technologie, na kterých by se to dalo postavit - Java nebo DCOM. DCOM byl čistě Microsftí. Java byla univerzální - ale výrazně pomalejší a výrazně žravější. DCOM byl zase relativně nebezpečný. Takže se hledaly cesty, jak se obojího zbavit.
Alternativy byly tři - flash, JavaScript a VBScript. Flash a VBScript byly proprietární technologie. VBScript navíc byl zase jen MS záležitost. Vyhrál JavaScript. Java je jazyk a univerzální prostředí navržené v 90 letech, kdy v době návrhu nikdo netušil, že něco jako web bude. JavaScript byl jednoduchý skriptovací jazyk určení k skriptování - automatizaci browseru.
Borek Lupoměský: To je nějaká alternativní historie? Java i JavaScript byly představeny v roce 1995, Java 1.0 oficiálně vyšla v roce 1996. Netscape v roce 1995 řešil, jak zavést interaktivitu webových stránek, a měl dvě varianty – vložit do prohlížeče Javu od Sunu nebo vytvořit nový skriptovací jazyk. To dostal za úkol Brendan Eich a Netscape dal nakonec přednost této variantě. (Ale Sun využil NPAPI, které už v roce 1995 v Netscape Navigatoru bylo, a umožnil tak vkládat do webových stránek Java Applety.)
JavaScript byl od počátku určen pro interaktivitu samotné webové stránky. Java Applety byl způsob, jak do stránky vložit jako jeden objekt nějakou aplikaci (a stejně se tam dali vkládat jiné objekty). Java Applety neměly možnost manipulovat s obsahem webové stránky – tu získaly právě až s JavaScriptem, kdy z Java Appletu šlo zavolat JavaScriptový kód, který mohl stránkou manipulovat. A Java samozřejmě nebyly jenom Applety, to byl jenom jeden z více způsobů použití.
Co je to proboha JIT bytecode?
JIT je JIT, z čeho je zkompilovaný je irelevantní. JS žádnou specifikaci pro bytecode nemá, a jestli JS-VM nějaký bytecode používá je jen na něm. První verze V8, což byl první JIT VM pro JS třeba žádný bytecode neměl, jen AST a IR, pak přímo machine code. Trvalo možná dekádu než do V8 ten bytecode dali, aby to mohlo běžet i tam, kde JIT není možný (třeba iOS tuším).
Petr Polášek> Jaký myslíte? WASM není jazyk, ve kterém byste psal. Píšete v nějakém vyšším, C/C++, C#, ... I ta Java jde zkompilovat do WASM. WASM právě řeší to, abychom mohli programovat jako dřív, ale aby to běželo stejně bezpečně jako JS (WASM běží v enginu a sandboxu JS). Bezpečnost byl jediný důvod, proč ty dřívější technologie umřely (prohlížeče zrušily podporu pluginů).
9. 8. 2022, 11:17 editováno autorem komentáře
Ne, chápete to špatně. Bajtkódové jazyky jsou ty zdaleka nejpoužívanější (JavaScript, Java, C#, Python, PHP), hodně kódu kompilovaného do nativního kódu je psaného v daných jazycích spíše z historických důvodů (C, C++), nové jazyky kompilované do nativního kódu zas tolik rozšířené nejsou (nejlépe je na tom Swift a Objective-C, o Go nebo Rustu je sice hodně slyšet, ale zas tak rozšířené nejsou).
to znamená, že ti vlastně může být jedno, jestli v cestě pak bude wasm, babel, google closure či něco podobného. Podívej se na pětici nejpoužívanějších JS frameworků (angular, react, vue, ember, meteor), u všech potřebuješ kód nejprve prohnat nějakým transpilerem/compilerem (je jedno jestli je součástí runtime nebo to musíš udělat dopředu).
WebAssembly je poněkud lowlevel. Někdy se hodí, často ale lze narazit na omezení:
1. Nemá GC. Samozřejmě můžete použít nějakou implementaci GC, ale to by znamenalo, že stránka přibalí svůj GC. Toto se zřejmě změní časem, návrh už je. Tím by stránky bobtnaly.
2. Nemá možnost přímo používat DOM, zřejmě ani referencovat objekty z DOM. Toto omezení lze též s nějakým úsilím a runtime overheadem vyřešit.
Reálně tak je WebAssembly vhodné spíše pro nějaké komponenty, kde tato omezení nevadí, plnohodnotná náhrada JS to zatím pořádně není.
Předpokládám, že nebyl myšlen současný stav implementace WebAssembly, ale cíl. WebAssembly se implementuje postupně, aby se pracně několik let neimplementovalo všechno najednou, a pak se nezjistilo, že někde v základu je něco nedomyšlené. GC i přístup k prohlížečovým API budou součástí WebAssembly, ale až v dalších úrovních.
Problém je, Jirsáku, že to je zase vaše klasická umělá konstrukce a dojem. Žádný "cíl" neexistuje. Momentálně to v podstatě nmá prioritu protože jsou na práci důležitější věci a poptávka je sporná.
Na webu by se hodilo mít jiný skriptovací jazyk, JS má zajímavý návrh ale mizernou implementaci, navíc neobvyklou, "jiný" znamená třeba jakýkoliv tak, aby prohlížeč tvořil jen platformu, ale poptávka po tom, aby na webu najednou všichni něco začali bastlit v binárně kompilovaných jazycích je nevelká. protože to také máí svá specifika a prostě to není třeba. Obecně je spíš poptávka právě opačná a to nejen na webu.
> JS má zajímavý návrh ale mizernou implementaci
Opravdu? Já myslím, že zrovna implementace je skvělá. Takový V8 skoro překonává i vlhké sny o tom, co se s jazykem jako JS dá dělat.
Na JS je právě špatně návrh, resp. předpoklady ze kterých ten počáteční návrh vzešel vůbec neodpovídají tomu, k čemu se teď JS používá.
Vždyť i ten operátor === porovnává napřed typy, pokud ten test nedokáže optimalizátor vyhodit. Což není až tak jednoduché. Obzvlášť v místech, kde ten typ potřebuje otestovat programátor. Takže uvnitř téhle nešikovné typové kontroly je schovaná jedna lepší (uvnitř toho typeof). Jen k ní programátor nemá přístup přes nějaké rozumné api.
Třeba v pythonu nedostanu jen jméno typu, ale objekt co toho umí podstatně víc. Kdekoliv jinde bych knihovny jako https://github.com/jonschlinkert/isobject/blob/master/index.js považoval za recesi.
No přece v tom, že tam není ten mezikrok přes string. A teď budu ignorovat výkon, protože mi jde o něco jiného. Když se podíváte na ten můj odkaz :
export default function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false;
};
tak to "val != null && typeof val === 'object'" potřebuje udělat interně i to isArray. Tohleto je dost fundamentální operace, kterou potřebujete pro všechno ostatní. Switch podle typu proměnné. Jenže jednoduché je to jen uvnitř interpretu. Vy jako programátor ten test musíte udělat dvakrát, protáhnout tu informaci různými kanály, protože každý ji zmrší nějak jinak a pak zase rekonstruovat.
Skoro jako kdyby v nějakém systémovém programovacím jazyce nešlo pořádně udělat add-with-carry. :D
9. 8. 2022, 15:26 editováno autorem komentáře
Jaký mezikrok přes string? Pro programátora je úplně jedno, jestli píše typeof x === "string" nebo typeof x === String nebo nějak jinak. Že isArray volá interně val != null && typeof val === 'object' je vaše ničím nepodložené domněnka. Jsem přesvědčený o tom, že by to platilo jen pro nějaký velmi naivní interpret JavaScriptu, který v prohlížeči mohl být možná před dvaceti lety. Dnešní JS enginy nejspíš ten kód často ani neprovedou, protože vědí, že jsou v branchi, kde ta proměnná musí být pole. A nebo se jen podívají na příznak označující, že je to pole.
Vy jako programátor ten test musíte udělat dvakrát
Vy možná, já bych ten test dvakrát nedělal.
Abychom se k něčemu dobrali, vezmeme to po malých krůčcích. Ten test typeof x === 'string' vám tedy vadí z hlediska programátora, protože je ten kód nějak špatně čitelný nebo může být chybný, nebo vám vadí z hlediska interpretu?
> Pro programátora je úplně jedno...
To teda určitě není jedno, jesli porovnávám string nebo třeba enum. A to nejen kvůli rychlosti. U enumu je množina možných hodnot součástí rozhraní, kterému rozumí i překladač. Takže můžu dostat třeba warning, že jsem nepokryl všechny možnosti. K nezaplacení, pokud třeba v budoucnu nejaká přibude.
IsArray určitě nevolá ten kód, ale čistší logický ekvivalent toho kódu. Tohle jsem zapomněl zdůraznit. A že to dělá mám podložené dokumentací chování toho IsArray.
> A nebo se jen podívají na příznak označující, že je to pole.
Ano, to je přesně ta fundamentální operace "switch podle typu", ke které skrz api javascriptu nemáte jednoduchý přístup.
> Abychom se k něčemu dobrali ...
1) string compare je nesrovnatelně komplikovanější a pomalejší než porovnání enumu. Je možné, že interprety mají speciální optimalizace tohohle případu. Ale tam se zas platí komplexitou a délkou překladu. A programátor do téhle optimalizace vždycky může nechtěně hodit vidle.
2) String má daleko víc možných hodnot než enum. Jak už jsem psal, u enumu můžu celkem jednoduše dostat warning, že jsem nějakou možnost nepokryl. Může mi vyskočit i ve starém kódu, když přibude v tom enumu položka. Se stringem mi lintery, statické analyzátory a pod. můžou pomoct podstatně hůř.
3) A typeof v JS má ještě historický bonus, že null se tváří jako objekt kvůli implementačním detailům prvního prototypu. To jsou ty dva testy, které jako programátor musíte udělat - test na null a test na objekt. I když interpret na to určitě bude mít nějakou lepší operaci, protože tohle je součást sémantiky hromady dalších věcí.
Takže místo toho, aby nějaké základní operace, které interpret stejně musí dělat, byly zpřístupněné přes nějaké příčetné api, tak se pro ně v JS světě tahají NPM balíčky. Co by se jen mohlo podělat (ehm ehm, leftpad, ehm ehm)
> 2) Jak už jsem psal, u enumu můžu celkem jednoduše dostat warning, že jsem nějakou možnost nepokryl. Může mi vyskočit i ve starém kódu, když přibude v tom enumu položka. Se stringem mi lintery, statické analyzátory a pod. můžou pomoct podstatně hůř.
Javascript statickou typovou kontrolu nemá, takže tam to opravdu tak je. Ale v Typescriptu je to jiná. Typeof tam podle definice totiž nevrací string, ale jeden z množiny stringů (string literals). Takže tam ta kontrola (nepokrytí možnosti, testu na hodnotu, kterou typeof nemůže vrátit) funguje.
> 3) To jsou ty dva testy, které jako programátor musíte udělat - test na null a test na objekt.
Marně vzpomínám, kdy jsem potřeboval naposledy testovat, jestli je něco "objekt". No, ani si vlastně nevzpomínám. Protože typicky je to tak, že v proměnné je například objekt nebo null - tak otestuju na null a pokud tam není, je tam objekt.
“typicky je to tak, že v proměnné je například objekt nebo null - tak otestuju na null a pokud tam není, je tam objekt.”
Tohle taky používá překladač (JIT) k optimalizaci. Pokud si umí odvodit, že instance je vždy typu Union{AnObject,Nothing}, nemusí se za běhu provádět typová kontrola a nativní kód vypadá, jako kdyby vylezl třeba z Rustu. Nikdo to ale negarantuje.
To teda určitě není jedno, jesli porovnávám string nebo třeba enum. A to nejen kvůli rychlosti.
Bohužel se stále ukazuje, že vůbec netušíte, o čem mluvíte. JavaScript žádné enumy neměl, ale hlavně to, že ve skriptu vidíte porovnání se stringem, vůbec neznamená, že to tak provádí interpret. typeof x === "něco" je výraz, který může interpret vzít a vykonávat ho úplně jinak, třeba ho interně přeloží na ten enum, nebo jakkoli jinak.
U enumu je množina možných hodnot součástí rozhraní, kterému rozumí i překladač.
JavaScript žádný překladač nepotřebuje. A IDE a lintery ten kód analyzovat umí a vědí, které hodnoty může vracet typeof.
IsArray určitě nevolá ten kód, ale čistší logický ekvivalent toho kódu. Tohle jsem zapomněl zdůraznit.
Ale stejně to není pravda. Interní implementace javascriptových objektů v interpretu vypadá jinak, než jak to vidíte v JavaScriptu. Jak jsem psal, klidně každý objekt může mít příznak, jestli je nebo není pole a isArray() jenom otestuje hodnotu tohoto příznaku.
Ano, to je přesně ta fundamentální operace "switch podle typu", ke které skrz api javascriptu nemáte jednoduchý přístup.
Máte k tomu přístup. typeof vrací string a nad stringem můžete udělat switch.
string compare je nesrovnatelně komplikovanější a pomalejší než porovnání enumu.
Chyba je v tom, že bezdůvodně předpokládáte, že tam interpret dělá string compare.
Ale tam se zas platí komplexitou a délkou překladu.
Dnešní javascriptové enginy dělají především spoustu různých optimalizací, samotné běhové prostředí je ta nezajímavá část. Takže jedna takováhle jednoduchá optimalizace navíc není žádný problém. Uvědomte si, že všechny objekty jsou řešené jako hashmapy, které mají jako klíče stringy. Pokud by tohle JS engine neuměl optimalizovat, bude mít daleko horší problémy, než je typeof.
Se stringem mi lintery, statické analyzátory a pod. můžou pomoct podstatně hůř.
Mýlíte se, tyhle nástroje samozřejmě vědí, jaké jsou povolené návratové hodnoty typeof.
A typeof v JS má ještě historický bonus, že null se tváří jako objekt kvůli implementačním detailům prvního prototypu.
To je holt nevýhoda zpětné kompatibility.
To jsou ty dva testy, které jako programátor musíte udělat - test na null a test na objekt.
Ne, nemusím.
Takže místo toho, aby nějaké základní operace, které interpret stejně musí dělat, byly zpřístupněné přes nějaké příčetné api, tak se pro ně v JS světě tahají NPM balíčky.
Pořád jste nenapsal, co by ta základní operace měla dělat jiného, než dělá typeof. V JS světě se na to žádné balíčky netahají. To, že nějaký balíček existuje, ještě neznamená, že ho někdo příčetný používá.
Ach jo, to jsou zas bláboly. Jasně, že to jde zoptimalizovat, vždyť jsem to i explicitně napsal. Takže zareaguju jen na ten největší úlet :
> Dnešní javascriptové enginy dělají především spoustu různých optimalizací, samotné běhové prostředí je ta nezajímavá část. Takže jedna takováhle jednoduchá optimalizace navíc není žádný problém.
Běhové prostředí vůbec není nezajímavá část, protože ten JIT kompilátor co všechny tyhle optimalizace dělá je část toho běhového prostředí. Jednu každou takovouhle optimalizaci musí provádět běhové protředí znova a znova u každého klienta. Takže každá tahle jednoduchá optimalizace je malý střípek velkého problému, protože počet provedení je astronomický.
Ta kompilace je nechutně drahá, takže třeba v8 ty výsledky cachuje. Ale jen někdy, protože to cachování je taky drahé.
> To, že nějaký balíček existuje, ještě neznamená, že ho někdo příčetný používá.
Jo, na tomhle závisí jen necelých 1000 dalších npm balíčků a má to 50k stažení za týden. Až děsivé na balíček s jedinou funkcí.
Jiří Havel: Ano, z vaší strany jsou to bláboly. Proč tedy argumentujete tím, jak by to zpracovával naivní interpret před dvaceti lety, když víte, že dneska javascriptový runtime vypadá úplně jinak?
Běhovým prostředím jsem myslel tu část bez optimalizátoru. Snažil jsem se vám naznačit, že zatímco dříve byl javascript runtime hlavně interpret, který měl možná nějaké drobné optimalizace, posledních 15 let se vývoj javascriptových enginů soustřeďuje hlavně na optimalizace. A schopnost optimalizovat běh JS je to, co dnes rozhoduje o tom, jak je který engine dobrý a je to to, co je na enginech to zajímavé. Protože s interpretem bez optimalizací by už dnes nikdo neuspěl.
Ano, JIT kompilátor je náročný jak na vývoj tak na provoz. Ovšem měl byste si uvědomit, že se tu bavíme o webových prohlížečích. Kdyby si prohlížeč stáhl nativní kód optimalizovaný pro svou platformu, mohla by se JIT kompilace zrušit. Ale myslím, že byste nechtěl na svém počítači spouštět nativní kód stažený náhodně z internetu. Takže ať budete v prohlížeči spouštět cokoli, vždy to bude kód, který bude kontrolovaný prohlížečem. Což se snáze udělá s kódem, který není nativní. No a jestli to bude nějaký bajtkód nebo skript, to ovlivňuje složitost JIT ale ne jeho výkon.
Takže to, co vám vadí, bude v prohlížečích vždy, ať už se bude používat jakýkoli jazyk. A mimochodem jazyků používajících bajtkód nebo interpretovaných je čím dál víc i mimo prohlížeče, protože dělat optimalizace až za běhu aplikace má svoje podstatné výhody.
Z toho, že to používá dalších 1000 npm balíčků, bych si hlavu nedělal. Vy nevíte, že operátor typeof v JavaScriptu nemůže vracet enum, protože v době, kdy byl zaveden, žádné enumy v JS neexistovaly, někdo jiný zase neví, že nepotřebuje funkci isObject().
@Filip Jirsák
function isObject(value) {
return typeof a === 'object' && !Array.isArray(a) && a !== null;
};
let a = new Array();
console.log(typeof a === 'object'); // true
console.log(Array.isArray(a)); // true
console.log(isObject(a)) // false
Something fishy here ...
10. 8. 2022, 20:15 editováno autorem komentáře
@Altan: Prostě v JS je pole objekt, co je na tom divného?
Fascinuje mě posedlost zdejších diskutérů zjišťováním, jestli je něco "nějaký objekt jiný než pole". Dělám v JS/TS fulltime posledních pět let a nepamatuji se, kdy jsem něco takového naposledy potřeboval. K čemu by to bylo dobré? Jo, kontrola, jestli je nějaký objekt instancí konkrétní třídy, to bych pochopil, ale tohle...?
Ale no tak.
Mám selektor, který mi vrátí všechny inputy.
Pak mám funkci, která nad každým inputem provede nějakou práci.
Mám dvě možnosti:
1/ Buď napíšu dva selektory, kdy prvý mi vrátí inputy bez radiobuttonu, a druhý, který mi vrátí radiobuttony(a ty další, co si nepamatuju).
nebo 2/ napíšu selektor vracící všechny inputy a pak podle toho, jestli je ten input jakože pole (radiobutton a ty další, co si nepamatuju) projedu jej ještě v ciklu.
Můžete se mnou nesouhlasit, ale mě prostě ten druhý způsob přijde z mnoha důvodů lepší a ten první vůbec.
@L.
Mě to nepřipadně divné. Dělám i s PHP ;-) Ovšem můj příklad jednoduše dokazuje, že s obyčejným typeof si prostě v některých případech nevystačíte (např. is really really object?), jak tady zase urážel Jirsák. A jazyk sám pro tyto případy žádnou funkci nepostkytuje - pro mě za mě nemusí, ale neposkytuje.
Dělám v JS/TS fulltime posledních pět let a nepamatuji se, kdy jsem něco takového naposledy potřeboval.
Nechci na vás mít nějaké nepříjemné poznámky, ale takové výroky bych být vámi ani radši neříkal.
Kde byste to chtěl použít? Např. tam kde potřebujete iterovat přes opravdový objekt a potřebujete uživatele upozornit, že vám tam přišlo nějaké pole.
11. 8. 2022, 13:14 editováno autorem komentáře
@Filip Jirsák
Altan Sarnai: Pole v JavaScriptu podle vás není opravdový objekt? Jaké vlastnosti má podle vás opravdový objekt?
Třeba takový, který zároveň ale nereprezentuje pole. Netvrdím, že "opravdový objekt" je JS terminologie, ale když jste tak inteligentní, už z toho příkladu by vám to mělo být jasné.
Ten příklad který jsem sem dal neslouží jako urážka, ale abyste viděl, že i pole může být pomocí typeof objekt, protože JS používa strukturu objekt k reprezentaci dalších typů. Jinými slovy, typeof nemusí v některých případech stačit. Takhle narychlo si nevzpomínám, že by ještě nejaký jiný jazyk měl takto zamotané typy a neúplné operátory nebo funkce k porovnání typu proměnné.
function isObject(value) {
return typeof a === 'object' && !Array.isArray(a) && a !== null;
};
let a = ['A']
console.log(typeof a === 'object'); // true
console.log(Array.isArray(a)); // true
console.log(isObject(a)) // false
A kde se vám to může hodit? Třeba zde:
const myObject = {i: 2};
for(const key of myObject) {
console.log(key);
}
TypeError: myObject is not iterable ...
Takže jak vidíte, není to jedno.
Difference between for...of and for...in
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of#difference_between_for...of_and_for...in
11. 8. 2022, 20:17 editováno autorem komentáře
Altan Sarnai: To je ovšem vaše arbitrární definice objektu, která je v praxi úplně k ničemu. Taky bych si mohl nadefinovat objekt jako cokoli, co není primitivní typ, není to pole, není to funkce, má to alespoň jednu stringovou property a nemá to property pojmenovanou name.
Že je v JavaScriptu pole objekt samozřejmě vím. Stejně jako funkce je objekt. Nebo DOM element je objekt. JavaScript nepoužívá strukturu objekt k reprezentaci dalších typů. JavaScript několik primitivních typů (takže není čistě objektový) a všechno ostatní jsou objekty. Nevím, co tady na tom spoustu lidí tak překvapuje – v čistě objektových programovacích jazycích je úplně všechno objekt, JavaScript k tomu jen (jako spousta dalších jazyků) přidává i pár primitivních typů.
Takhle narychlo si nevzpomínám, že by ještě nejaký jiný jazyk měl takto zamotané typy a neúplné operátory nebo funkce k porovnání typu proměnné.
Třeba C, C++, Java, Python…
A kde se vám to může hodit? Třeba zde:
To nemyslíte vážně, že ne? Tušíte alespoň přibližně, co by ten váš kód dělal? Kdybyste tam přidal ten test na isObject, zabránil byste iterování některých objektů, které iterovatelné jsou, a naopak byste pustil do iterování i objekty, které iterovatelné nejsou.
Kdybyste chtěl testovat, zda můžete přes daný objekt iterovat, použijete třeba následující kód:
myObject && typeof myObject[Symbol.iterator] === 'function'
Opět jenom fabulujete. V Pythonu je funkce, která vám o poli řekne že je to objekt, resp. nemůžete určit že se jedná o pole?
Dostal jste konkrétní příklad. To teď jste tvrdil, že nic víc než typeof není potřeba. Je. A proto vznikají i různé další knihovny.
myObject && typeof myObject[Symbol.iterator] === 'function'
To je hezké, ale "vy" chcete iterovat přes cokoliv. Pokud pouze přes pole, toto je vám k ničemu.
Co víc napsat, konkrétní případ jste dostal. Bádejte ...
12. 8. 2022, 09:25 editováno autorem komentáře
> Proč tedy argumentujete tím, jak by to zpracovával naivní interpret před dvaceti lety, když víte, že dneska javascriptový runtime vypadá úplně jinak?
Bingo! Já tak neargumentuju. To vy si tam urputně dosazujete 20 let staré interprety. Prosím, aspoň zkuste interpretovat moje odpovědi v kontextu toho, že mám aspoň hrubou představu o možnostech JIT interpretu.
> Běhovým prostředím jsem myslel tu část bez optimalizátoru.
A k čemu tohle dělení je? Pro kohokoliv kromě vývojářů v8 je ten optimalizátor a všechno za ním jeden blok. Copak můžu tomu za tím strčit nějaký svůj bytecode? Ten kompilátor + optimalizátor nejde obejít. Svým způsobem je to rozhraní k tomu, čemu říkáte to běhové prostředí.
> No a jestli to bude nějaký bajtkód nebo skript, to ovlivňuje složitost JIT ale ne jeho výkon.
Takže to, jestli ta kompilace může jet minuty a víc, nebo jestli musí doběhnout v rozumném čase na nějakám uživatelově střepu, nemá vliv na výkon? Jestli se bude jitovat a optimalizovat textový zdroják nebo předoptimalizovaný bytecode neovlivní výkon? Fakt?
> Takže to, co vám vadí...
Ne, tahle větev začala tím, že jsem ryl do typeof, protože mi to přijde jako mizerné rozhraní. Porovnejte to třeba s tím Array.IsArray. Co všechno musí runtime udělat aby zoptimalizoval to použití typeof vs zoptimalizoval volání nějakého předpřipraveného predikátu? Jo, jednotlivě se to vsákne, ale tyhle drobečky se sčítají.
Jo, spousta lidí tady něco takového nepoužilo. To beru. Ale ten odkazovaný balíček je nechutně používaný na to, že je jeho obsah skoro srovnatelný se složitostí jeho importu. V kolika dalších projektech se vyskytujou stejné obraty si netroufám ani odhadovat.
Že je pole taky objekt je implementační detail JS. Nebo je to možná implementační detail prvního JS. Ani programátoři tak IMO obvykle nepřemýšlejí. Že je absence čehokoliv taky objekt už je regulérní WTF. A argument "typeof je starý krumpl, takže v novém kódu použijte XYZ" jsem tu nezahlédl.
Bingo! Já tak neargumentuju.
Ale argumentujete. To vy tvrdíte, že javascript engine provádí výraz typeof x === 'object' tak, že z operátoru typeof vrátí obecný string a ten pak znak po znaku porovnává s 'object'.
Prosím, aspoň zkuste interpretovat moje odpovědi v kontextu toho, že mám aspoň hrubou představu o možnostech JIT interpretu.
Zkuste vy tu hrubou představu promítnout do vašich odpovědí.
A k čemu tohle dělení je?
K tomu, abyste pochopil, že posledních 15 let se vývojáři věnují právě té části, která řeší optimalizace. A že to je ta podstatná část, kterou má smysl se zabývat, když řešíte výkon dnešních javascript runtime.
Takže to, jestli ta kompilace může jet minuty a víc, nebo jestli musí doběhnout v rozumném čase na nějakám uživatelově střepu, nemá vliv na výkon?
Má, ale o tom já jsem nepsal.
Jestli se bude jitovat a optimalizovat textový zdroják nebo předoptimalizovaný bytecode neovlivní výkon?
No, paradoxně lepší možnosti optimalizace nabízí ten texťák. Je tam sice nějaký overhead kvůli parsování textu, ale to není žádná tragédie. Pak ale v tom texťáku mohou být konstrukce, které se překladem do bajtkódu ztratí, ale které by mohly optimalizátoru napovědět, jak kód optimalizovat.
Ne, tahle větev začala tím, že jsem ryl do typeof, protože mi to přijde jako mizerné rozhraní.
Ano, přijde vám to jako mizerné rozhraní pro 20 let starý naivní interpret. Což ovšem nevypovídá nic o dnešním stavu běhových prostředí. Navíc jste stále nenapsal, jak by to mělo být lépe – u dynamicky typovaného jazyka, který logicky nemá enumy.
Co všechno musí runtime udělat aby zoptimalizoval to použití typeof vs zoptimalizoval volání nějakého předpřipraveného predikátu?
Musí poznat, že typeof X === 'object'> je předpřipravený predikát. typeof je operátor, takže musí poznat, že za typeof se nachází operátor porovnání a za ním stringová konstanta. Vyloženě raketová věda, do dneška nikdo nepřišel na to, jak tohle udělat.
V kolika dalších projektech se vyskytujou stejné obraty si netroufám ani odhadovat.
Nejde o počet projektů, ale o to, jak jsou používané.
Je dost pravděpodobné, že z webu se stala univerzální aplikační platforma právě díky tomu, jak je JavaScript benevolentní k začátečníkům. Existují samozřejmě daleko hezčí a propracovanější jazyky – ale kolik je v nich toho napsáno?
JavaScript má samozřejmě spoustu nešvarů. JavaScript s oblibou kouše do zadku programátory, kteří mu nerozumějí a chtějí dělat něco kapánek složitějšího. Ale typeof vracející string fakt není jeho problém.
Že je pole taky objekt je implementační detail JS. Nebo je to možná implementační detail prvního JS. Ani programátoři tak IMO obvykle nepřemýšlejí.
To, že je všechno objekt, nebo se alespoň umí do objektu automaticky zapouzdřit, je naopak hodně dobrá vlastnost JavaScriptu.
Že je absence čehokoliv taky objekt už je regulérní WTF.
No, díky tomu začíná trošinku dávat smysl rozdíl mezi null a undefined. Ale to je něco, co se v JavaScriptu doopravdy nepovedlo.
A argument "typeof je starý krumpl, takže v novém kódu použijte XYZ" jsem tu nezahlédl.
Protože takový argument neplatí. typeof se nepoužívá nějak moc často, a když už se použije, jeho použití je v pohodě, nevadí ani programátorům, ani javascript runtime. Problém z toho děláte akorát vy.
dw : Mám to chápat tak, že tenhle syntaktický vzor je argument pro to, že v JS je všechno objekt? :)
neco.neco() je syntaktický cukr, který nemusí mít nic společného s OOP (v jakékoliv variantě). Některé jazyky to mají prostě jako alternativní syntaxi pro pro předání prvního parametru do funkce.
Tohle je problém s OOP. Ono není pořádně definované, co to to OOP vůbec je, a v různých jazycích se to tváří výrazně odlišně. A samotné slovo "objekt" je zatraceně vágní a občas se nepoužívá konzistentně ani v kontextu jednoho jazyka.
No tak podle dokumentace je "Number" wrapper objekt pro boxování primitivních hodnot, které objekty nejsou.
"Number is a primitive wrapper object..."
"In JavaScript, a primitive (primitive value, primitive data type) is data that is not an object and has no methods or properties."
Javascript tomuhle zmatení pojmů výrazně napomáhá tím, že věci automaticky boxuje a unboxuje.
> Aspoň že už automatický, nebývalo to tak.
Já bych teda automatický boxing jako dobrou vec nepovažoval, rozhodně ne univerzálně. Třeba při vývoji v Unity (C#) je to víc past než pomoc. A na podobné názory jsem narazil i u Javistů Androiďáků.
Jakkoliv rychlá alokace je vždycky výrazně pomalejší než žádná alokace. A nejvíc to vynikne právě v situacích, kdy nějaká trivialitka spustí nečekaný autoboxing.
Univerzálně ne, ale jestvuje několik typů (auto)boxingu. Například compile-time boxing (jako v Go) je úplně zadarmo, protože za běhu se nic navíc neprovádí. A “skutečný” (runtime) boxing také může být levný, překladač může provést escape analýzu a alokovat na zásobníku (což je taky téměř zdarma). Případně se dá provádět boxing/alokace jako v Julii, kde se také dynamická alokace obchází. Jen v jazycích, které tupě alokují vše na haldě (Java, ale i například Objective-C, kde ostatně boxing v dnešní podobě vzniknul), to může být problém.
https://www.npmjs.com/package/is-number ma 70 milionov stiahnuti, takze az take obskurne to nebude.
mizerná implementace? O které implementaci mluvíš (v8, spidermonkey, nitro, Graal.js atd.)? A co je na ní mizerného a jak je možné to v rámci ecmascript standardu dělat jinak?
Jaký je faktický rozdíl tím, co generuje typescript compiler a mezi třeba wasm text format? Mně ten wasm text format připadá čitelnější než to co produkuje typescript.
martinpoljak: Nejenom, že jsem si to vymyslel, ale ještě jsem to propašoval až na oficiální stránky WebAssembly: WebAssembly High-Level Goals. Nikdo nikdy nepočítal s tím, že to vše bude implementované hned, počítá se s tím, že je to na roky.
Na webu by se hodilo mít jiný skriptovací jazyk, JS má zajímavý návrh ale mizernou implementaci, navíc neobvyklou, "jiný" znamená třeba jakýkoliv tak, aby prohlížeč tvořil jen platformu, ale poptávka po tom, aby na webu najednou všichni něco začali bastlit v binárně kompilovaných jazycích je nevelká. protože to také máí svá specifika a prostě to není třeba. Obecně je spíš poptávka právě opačná a to nejen na webu.
Ta slova i věty jsou česky, ale těžko říct, co jste se vlastně snažil sdělit. Co je mizerného na implementaci V8? Co znamená „prohlížeč by tvořil jen platformu“? Co je „opačná poptávka než aby na webu najednou všichni začali bastlit v binárně kompilovaných jazycích“?
> Předpokládám, že nebyl myšlen současný stav implementace WebAssembly, ale cíl.
Možná ano, ostatně u GC jsem psal:
> Toto se zřejmě změní časem, návrh už je.
Na druhou stranu k referencování objektů mimo svět WASM jsem zatím nenašel ani návrh. IIUC to znamená, že máme v JS nějakou mapu z wasm identifikátoru na JS referenci a z WASM do JS mohu poslat zprávu (WASM ID objektu, operace, parametry), aby to zavolalo nějakou metodu (případně přistoupilo k atributu). A jakmile s objektem přestanu ve WASM pracovat, musím do JS poslat zprávu, aby objekt vyhodil z mapy, jinak to udělá memory leak.