Moderné programovacie jazyky vo veľkom kopírujú rôzne populárne postupy, napr. rekord typ, match pattern, async/await, funkcionálne programovanie atď. Akurát to public static void main si nik neobľúbil, dokonca ani Java platform jazyky. Čím to je?
Netuším kde je problém. Kompiler vytvorí objekt a sám zavolá main metódu. (Nie som si úplne istý, ale tak by to zrejme mali robiť aj Kotlin a Groovy.) Tým že je main statická, tak musia byť aj premenné s ktorými pracuje statické. A to je presne to, čo v 99.999% prípadoch nechcete. A preto kóšer Java kód pre minimálnu aplikáciu musí mať nie jednu triedu, ale rovno dve. Pretože tá prvá je len Application starter.
Ak sa toto niekomu páči... Ale čo ja viem, ja som len obyčajný F#/Groovy programátor.
> A preto kóšer Java kód pre minimálnu aplikáciu musí mať nie jednu triedu, ale rovno dve.
Nemusí. Funkce main() je obvykle jenom wrapper, ale může vytvořit objekt ze stejné třídy a zavolat její metodu. Můj typicky kód pro hodně jednoduché věci (bez DI a jiných komplikací):
public class A {
public static void main(String[] args) {
System.exit(new A().run(args))
}
public int run(String[] args) {
// do the actual stuff
}
}
To zjednodušení v Java 21 je nejspíš cíleno na skriptování apod, pro větší program to smysl nemá.
Když kompilátor vytvoří objekt, musí ten objekt mít bezparametrický konstruktor. Co kdybyste chtěl zařídit, aby ten „hlavní“ objekt byl singleton? Co kdybyste chtěl instanci toho objektu někam předat – asi budete muset z konstruktoru někam předávat this, což je prasárna na entou.
Aneb abyste si mohl zjednodušit život a ušetřit jedno klíčové slovo u definice metody, musíte kolem toho vyrobit celý aparát složitých pravidel. Jsou jazyky, které to tak dělají, třeba Kotlin. Java na to jde přesně opačně – pár jednoduchých pravidel, z nichž už se pak dají složitější věci poskládat. Občas to znamená napsat trochu víc písmenek, ale dneska už máme IDE, která ta písmenka píšou za nás. A kdo chce ušetřit písmenka, nepoužívá Javu.
Kde tak Kotlin činí? IIUC, v Kotlinu máte dvě možnosti:
a. Udělat main mimo třídu, pak se Vám pro JVM automaticky vygeneruje třída MainKt (nebo tak nějak) s public static void main.
b. Udělat companion object a v něm metodu main s @JvmStatic. Companion object je v podstatě singleton (takže tam neřešíte žádné parametry pro konstruktor), přijde mi to jako lépe navržená alternativa statických metod. Anotace JvmStatic pak zajistí, že se při kompilaci pro JVM vygeneruje i statická proxy metoda.
První způsob je multiplatformní, tedy bude fungovat i na Kotlin/Native. On Kotlin obecně k některým věcem (např. kolekce) dělá v podstatě aliasy, aby mohl fungovat multiplatformně.
Druhý způsob je víc low-level a funguje jen na JVM, nebude tedy fungovat např. s Kotlin/Native nebo Kotlin/JS. Resp. i na dalších platformách to půjde zkompilovat (pokud kompilátor bude mít na classpath anotace pro JVM), ale nevyrobí to žádný entry-point.
> Netuším kde je problém. Kompiler vytvorí objekt a sám zavolá main metódu.
No já v tom vidím problém v tom, že je to ještě jeden další "neviditelný" krok navíc. Rozdíly mezi statickými proměnnými a nestatickými proměnnými v nějakém "statickém" unikátním objektu jsou dost kosmetické.
A pokud ten main objekt není jen jeden, ale chcete pak vytvářet další, tak mi to zas smrdí porušením single responsibility principle.
Co mi přijde příčetné je opustit Cčkoidní main funkci a mít přímo kus kódu, který se zrovna vykoná (jak je oblíbené u skriptovacích jazyků). Jestli si pro to chce překladač vytvořit nějaké svoje pomocné objekty, ať si poslouží. Ale pro mně jako pro programátora jsou tak dobře schované, že vlastně ani neexistujou a nemusím jejich existenci nijak řešit.
Chápu jak ten statický main historicky vznikl. Jistým zvráceným způsobem mi přijde že Java zahodila špatné části Cčka a dobré části C++.
To nejlepší, co šlo pryč? Podle mě hodnotová sémantika. V c++ je zvykem, pokud to jenom jde, aby se i vaše typy chovaly jako int (bez Cčkovských podivností). Proměnná je chlívek na hodnotu, ne odkaz na nezávisle existující (a potenciálně sdílenou) entitu.
V kombinaci s mutabilitou (což je v Javě obvyklé) to přidává věci na které musí programátor myslet. Změní mi volaný ten předaný objekt a kdy? Můžu volajícímu ten objekt upravit, nebo si ho musím naklonovat? U velkých (nebo spíš high level) objektů to až tak nevadí, ale je to bolest pro ty malé dílky (kontejnery, 3d vektory a podobně). A takových je IMO drtivá většina.
Naprostou souhlasím.
V problémvé doméně jsou dva druhy objektů. 1) enity s životním cyklem a rovností přes nějaký druh identity (id) a 2) hodnotové typy bez životního cyklu s rovností definovanou jejich atributy. Těch druhých je neskonale větší procento. V některých dménách vlastně skoro všechny (např. simulace). A pro hodnotové typy se přidala podopora pár let nazpět, jinak se t muselo stále řešit otravným předefinováním metod. Python na tom nebyl dlouho o moc lépe. Asi prostě relikt 90kových "OO" jazyků.
Nepřijde mi, že by byla nepopulární. Quarkus, Micronaut, Apache Camel, Kogito tohle všechno jsou frameworky, které jsem v poslední době viděl v nespočetných instancích napříč různými odvětvími. Počínaje tour operators, přes iGaming po Telco. Jeden z nejpopulárnějších open data table format Apache Iceberg, opět Java. Vlastně když nad tím přemýšlím Delta Lake je opět Java. Ja osobně bych v JVM ekosystému v některých případech dal přednost Kotlinu a to i v případě backend, ale sehnat kvalitního backend developera s Kotlinem je trochu oříšek. Jinak pokud bychom mluvili o tom, že Java programmers jsou drazí, tak kvalitní Python programmer, vás v Estonsku vyjde cca na 5000 Eur čistého. Obdobně jako Java. Ja osobně Javu nemám moc v oblibě, ale rozhodne bych se neodvážil tvrdit, že je nepopulární, většina toho hejtu nemá logický základ, nebo je založených na dávno neplatnych předpokladech.
> Netuším kde je problém. Kompiler vytvorí objekt a sám zavolá main metódu.
Kdyby toto měl mít na starost kompilátor, musel by něco vědět o metodě main. Vsadil bych se, že ve zdrojáku javac nenajdete žádný kód, který by se věnoval specificky metodě main, protože tam žádný takový nebude.
> Nie som si úplne istý, ale tak by to zrejme mali robiť aj Kotlin a Groovy.
U Groovy nevím, nicméně u Kotlinu vím jen o jednom zjednodušení – hodíte main úplně mimo třídu. Tam to ale dává smysl i kvůli tomu, že Kotlin je multiplatformní, nejen pro JVM.