15 komentáře “Názvy argumentů metod v reflexi

  1. Ta anotace by stacila jedna pro tridu, to neni zrovna moc psani. Nebo pro pakaz, kdyz by se dala k package-info.java. Tou anotaci autor prohlasi, ze jmena argumentu zustanou stabilni; bez ni by to byla tak trochu ducharina – marne ale vzpominam, jestli jsem kdy jmeno argumentu menil.

  2. @benzin na tomhle se asi shodneme – konzervatismus má taky své klady

    @Maartin s tou anotací to není úplně špatný nápad, ale kdyby to šlo bez ní, bylo by to přeci jen nejlepší – jde mi přeci taky o úsporu kódu, zjištění těch argumentů se skutečně může odehrávat podobně jako to v současnosti děláme u anotací, tam také musíme skenovat hierarchickou strukturu (a jde to 😉 )

    @vsem díky za podnětné komentáře, jsem rád, že se podařilo trošku rozproudit diskusi

  3. Ja bych to nekomplikoval a zustal u
    > Ok, to beru jako argument – nicméně pravidlo by mohlo být jednoduché – vrátí se mi to na co se zeptám.
    a to jen v pripade ze tam je anotace @ParameterNames (v opacnym pripade predpokladam ze autor s tim nepocital a ty jmena pripadne nekdy zmeni). Tim odpada i nutnost pamatovat si pripadne stary jmena parametru – to je pak stejne absurni jako pamatovat si stary jmena public metod.Jen bych to namisto toho APT dal do rovnou Javy, aby se na to lezlo pres
    String[] Method.getParameterNames()

    Dedeni bych taky neresil, nedokazu si predstavit, ze by programator nevedel kterym smerem v hierarchii se vydat – pokud tam mam dynamicky proxy, tak vim jestli se vygenerovaly k mymu interfejsu nebo k my tride. Zadny konflikty by tez nebylo treba resit, pripadne by si poresil programator kdyby si je tam nadelal – coz si tez moc neumim predstavit.

    Vyhodpu oproti APT by byla prenostitelnost (to APT je treba delat pro kazdy prekladac znova a muze se bit s jinym APT) a standardizace (rozumnel by tomu i Javadoc a jmena patricne zvyraznoval).

    > 4Otec: No ale dost to omezuje pouziti takovych jmen….
    Me se nezda ze by to byl vubec problem, protoze tam kde bych to pouzil bych i presne vedel kam mam jit. Normalne bych to pouzil jen pro jeden druh objektu, rekneme pro entity a kdyz jsem je napsal jako tridy, tak musim u proxy jit k predkovi, atd. (uz bych se opakoval).

    Vic mi vadi, ze to nepujde pouzit pro neco jako konstruktor

    @com.google.inject.Inject
    Article(@Named(„title“) String title, @Named(„description“) String description, Author author, Date publishedDate)

    (to Named jsem schvalne pouzil jen kde je potreba), ale k tomu me vazne nic nenapada.

  4. 4Otec: No ale dost to omezuje pouziti takovych jmen. Protoze musis vzdycky jeste nejak ziskat puvodni klasu. Nemuzes se spolehnout ze ta kterou ziskas z obektu ti staci. Je to podobny problem jako u anotaci. V podstate by stacilo jenom pri buildovani automaticky prihodit anotaci se jmenama promenych k metode. Ale to by presne mel resit ATP.

    Mne spise vadi absence aspektu v zakladni jave a k tomu samozrejme i kontraktovaci api.

    Ale ono je toho strasne moc co by v jave mohlo byt a neni tam a pritom v jinych jazycich to je. Napr. v Lispu je obdoba aspektu od sameho pocatku – tusim se to menuje hook. Na druhou stranu sem ale rad, ze je Java porad docela konzervativni. Prave z Pythonem, mam docela nepekne zkusenoti prave se zpetnou kompatibilitou, vzhledem k tomu ze dost velka cast KDE a Gnome (a utilit pro neho) je psana v Pythonu, tak sem si prosel peklem, kdyz sem nechte upgradoal na novou verzi.

  5. @benzin teď mi dochází, že v případě dynamických proxy, které musí implementovat jmenované interfacy by muselo dojít pro implementované metody k reflexní analýze původních argumentů, tak aby implementované metody držely stejné názvy. Tohle mi při psaní minulého příspěvku úplně nedocvaklo, ale principielní problém to řekl bych neznamená.

  6. Ano JDK Proxy staví pouze na interfacech, kdežte Cglib odvozuje ze superclass + umožňuje implementovat libovlné ifacy – tj. v tomto případě bych s instancí vůbec neoperoval. U proxy dopředu nikdy nevíš co vlastně wrapují a jestli něco wrapují. Tohle se mi nechce moc brát jako argument.

    Nicméně souhlasím s tebou, že nic není triviální, jak se na první zdá. Určitě by se komplikace našly. Je otázka jak problematicky jsou řešitelné. Skutečně už je v Javě dost znát ta stále narůstající koule s nálepkou zpětná kompatibilita.

    Co se týká generik, tak ty přes reflexi v runtime dostupné jsou. Jen se nedostaneš na konkrétní hodnoty wildcard generik – tam máš k dispozici jen „bounds“. Viz. minulý článek.

  7. 4Otec Fura: Prave ze bude. protze JDK proxy prebira jmena z interace a ne ze tridy. Takze kdyz ti pak do ruky vlitne proxy trida splnujici urcity interace, tak se nikdy nedozvis jake jmena metod na proxovana instance. Naproti tomu CGLIB proxy to dela (pokud vim) jako potomka predka, takze se ke jmenum dostat muzes.

    Problem je v tom, ze tohle muze mit docela nepekne dopady a neni to az tak trivialni, takze se nedivim ze se to odklada. Protoze vzdycky tu bude reseni vyhovujici jednem a nevyhovoujici druhym. Navic tu porad existuje reseni sice ukecane, ale exsituje. A konkretne property, ktere trapi daleko vetsi mnozstvi vyvojaru, porad nenaslo uspokojive resen (pokud teda vim). Podobne je tomu s generikama, ze se k nim nedostanes za behu, to mi prijde taky jako daleko vetsi problem nez jmena parametru.

  8. Ok, to beru jako argument – nicméně pravidlo by mohlo být jednoduché – vrátí se mi to na co se zeptám. Kdy si dám class.getSuperClass().getDeclaredMethod(„blabla“) dostanu se k názvům uvedeným v deklaraci předka, když zavolám class.getDeclaredMethod(„blabla“) dostanu názvy argumentů přetížené metody (stejně tak i v případě interfaců).

    Nezdá se mi to nijak proti srsti. V případě knihoven co jsem jmenoval (iBatis, Grails) by byly zajímavé právě jen ty argumenty té konkrétní „klientské“ třídy – tedy té nejníž v chainu dědičnosti. Co se týká JDK Proxy nebo Cglibu, taky by neměl být problém.

  9. 4Otec Fura. Kde je problem:

    Interface X Class – Ktere jmeno parametru bude mit prednost?
    Predek X Potomek – ktery metodu prekryva, nebo implementuje. – Ktere jmeno bude mit prednost
    2x Interface (stejna metoda, jina jmena promenych) implementovano jednou tridu – Ktere jmeno bude mit prednost?

    A to vsechno jak dopadne kdyz pouzijeme JDK proxy? A kdyz pouzijeme CGLIB proxy? A budou dalsi nekompatibility pri zamene techto proxy?

    Bude nutne aby jmena v implementaci rozhrani byly stejne jaako ve tridach? To ale bude strasne z hlediska zpetne kompatibility. A taky se dostanete do problemu pri immplementaci dvou rozhrani s ruznymi jmeny promenych, ale stejnym jmenem metody.

    Nemyslim, ze je tady pekne reseni.

  10. Maaartin už stihnul odpovědět v duchu, ve kterém bych odpovídal já a proto to nebudu opakovat. Všechny uváděné návrhy jen duplikují informaci, která je již obsažená v původní signatuře metody, v názvech argumentů (a některé tedy dost pracně). A jak všichni dobře víme, zdvojování informací vede pouze k nepřehlednosti a dalším chybám.

    Podle mého názoru stačí pouze jasně říct, v čem je tato technika nebezpečná a že i názvy argumentů jsou součástí rozhraní. Argumentování tím, že jsem se mohl v názvu argumentu uklepnout a chtěl bych to mít možnost bez rizika v dalších verzích opravit je zcestný – stejnou chybu jsem přeci mohl udělat i při psaní anotace nebo názvu metody a v takovém případě mám problém už za současné situace.

    Další věc – schválně se zkuste zamyslet nad tím, jestli v názvech argumentů chybujete častěji než v názvech metod – já tedy ne. Co se týká zmíněných použití (iBatis, Grails atd.) – zde je na první pohled jasné a jasně zdokumentované, že názvy argumentů hrají roli, protože se mapují na nějaká externí data (názvy sloupců v db, názvy paramterů v URL atd.). Řekněte mi, kdo by se mohl v daném případě cítit zmatený? Tady jsou argumenty jasně součástí API, což lze jednoduše prověřit testy – ty také zajistí i rychlé zjištění chyb v případě změny API.

    Osobně v tom vidím jen riziko v případě, že se to někdo bude snažit zneužívat, jenže v takovém případě už máme řadu jiných podobných nástrojů, které se také dají zneužívat a také nám nevadí (například setAccessible(boolean) že?).

    Osobně v tom faktický problém nevidím, a nutnost současný stav obcházet nějakým šíleným oprogramováváním se mi příčí.

  11. Ja sem samozrejme navrhl nekolik reseni. Neznam konkretni problem, ktery se tim resi.

    Co se toho stringu tyce, tak tam je naprd, to ze se neda ze stringu udelat potomek protoze je final jinak by to problem nebyl.

    To s tim ctenim a psanim kodu, s probiralo i u protertie. ja je konkretne pisu takhle:

    public class Trida {
    private String property; public String getProperty() { return property; } public void setProperty(String property) { this.property = property; }
    }

    Aniz bych potreboval menit jazyk JAVA, mam property, ktera je napsana na jednom radku, je to dobre citelne, protoze proste zbytek radku s get a set metodama proste nectu. I tohle je problem spise IDE a formatovani nez jazyka. Preci neni vubec problem si „nepodstatne“ anotace nechat zkryt / sbalit. Navic anotace nad metodou s vyctem jmen promenych kod prilis nezneprehledni.

    Ruku na srdce, je skutecne tohel tak obrovsky a neresitelny problem, aby bylo potreba menit specifikaci jazyka? Preci i nevabne smeti se sklada ze spousty jednotlivych drobnych odpadku, ktere nevabne nejsou.

  12. > Kazdemu sa stane pri pisani kodu, ze niekde
    > na kraji mu nenapadne “dobre” meno nejakeho parametra

    Stejne tak jako u public metody, i kdyz tam ne tak casto. To je ale tim, ze public metody jsou videt zvenku, takze clovek si proste da vic bacha. Se tou specialni anotaci co jsem navrhoval by autor zadeklaroval ze jmeno parametru patri k signature, takze by se nad nim vice zamyslel.

    A o nic vic nejde, chyba se stat muze vzdy, (aspon) jednou se dokonce preklep propracoval do standardu („http-referer“).

    > Tohle je schopne doplnovat rovnou IDE, nebo prave nejaky pridavny predkompilacni tool
    > a tak neni skutecne potreba zasvinovat jazyk necim co je resitelne a
    > pritom v drtive vetsine pripadu nepotrebne.

    Me se zas nelibi nechat si zasvinovat zdrojak pomoci IDE – prece jen se to vickrat cte nez pise.

    > A pak na to nasadit APT…

    To se mi libi, ale nemyslim si ze by to bylo trivialni udelat. S APT snad nic neni trivialni, poptam se na to.

    > Standardem jak tohle resit v Jave, jsou beany.

    Ano, ale ukecany a pracny. Je pak potreba vsude „castovat“ String na Description a zpet, to by slo v C++ automaticky ale v Jave to znamena dost psani. Nekde to muze byt i vyhodou, clovek aspon vi, s cim dela.

    Ty beany maji jeste jednu nevyhodu: Kdyz nekam predam String, tak vim, ze mi ho (bez pomoci Unsafe) nikdo nezmeni, ne tak kdyz pridam Description. Radeji immutables.

  13. Existuje jeste jedna varianta a taky je pomerne prehledna:

    @ParamsNames({„title“, „description“, „author“, „publishedDate“])
    Article createArticle(String title, String description, Author author, Date publishedDate);

    Je to sice trosicku ukecanejsim, ale prehledne stejne jako Vas navrh. Navic tu anotaci stejne musite osetrovat (v nejake podobe), prave proto aby pri zmene jmena parametru se zavyslosti nerozvezly. Tohle je schopne doplnovat rovnou IDE, nebo prave nejaky pridavny predkompilacni tool a tak neni skutecne potreba zasvinovat jazyk necim co je resitelne a pritom v drtive vetsine pripadu nepotrebne.

    Navic zapsat to treba takhle:
    @ParamsNames
    Article createArticle(String title, String description, Author author, Date publishedDate);
    A pak na to nasadit APT (http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html, http://www.javalobby.org/java/forums/t17876.html) vyresi problem taky a nezasvinite si specifikaci kvuli mensinovym problemum.

    A naposled. Standardem jak tohle resit v Jave, jsou beany. Proste do metody nevstoupi pet paramteru stejneoh typu a ruzneho jmena, ale jedna beana (nebo dve, ci tri), jejichz property odpovidaji parametrum puvodni metody.

    Dalsi mozne reseni je definovat pro ruzne typy parametru ruzne potomky stejne tridy napr.
    class StringHolder {
    getString(…); setString(…);
    }

    class Title extends StringHolder{};
    class Description extends StringHolder();
    class PublishDate extends Date();
    atd.

    Uzivatel vaseho frameworku, pak do dane metody necha vstoupit promene takovych typu, jejichz hodnotu potrebuje. Takze vase metoda pak vypada takto:

    Article createArticle(Title title, Description description, Author author, PublishDate publishedDate)

    P.S.: Osobne nemam rad frameworky bazirujici na stringovych jmenech, pri preklepu Vas pak kompilator neopravi. Chapu ze ne vzdy se tomu da vyhnout, ale je-li cesta (napr. generovanim tridyu pro kazdy typ parametru), tak si myslim ze je lepsi.

  14. Na 101 % suhlasim, hlavne co sa tyka tych poslednych bodov a prikladu ACEGI, neskutocne co clovek zazije kym to dostane tam kam chce 🙂

    Treba sa ale pozriet na vec aj inym pohladom. Nemusi to byt nutne „zle“ rozhodnutie. S velkou pravdepodobnostou je za tym kopec studii. Kazdemu sa stane pri pisani kodu, ze niekde
    na kraji mu nenapadne „dobre“ meno nejakeho parametra – pripadne nie je cas riesit
    nazov … meno sa zabudne, necha sa tam (u mena metody si clovek da zalezat o 26 % viac :))… Problem by to nebol ak by za cely zivotny cyklus
    spravoval 1 az dvaja ludia. Prax je vsak casto ina – casti systemov su pouzivane a customizovane
    „kade – tade“ a casto ani autor sa neodvazi zmenit co-i-len nazov public metody, zmazat, ci inak upravit. Nie je to zly management kodu – takto to byva. Neda sa preto povedat – „nechajme to na developerov“ – to ozaj nie. Chapem, preco to tvrdis, lebo vies, ze vies, … lenze … nie kazdy vie.

    Teda nie je zle dat konovi klapky na oci aby siel kam by mal. Poriadok je naozaj potrebny.
    Samozrejme, … o vsetkom sa da polemizovat. Treba to vnimat ako jednu z vyhod jazyka …
    a hned bude svet ruzovejsi 🙂

    Prilisna benevolencia muoze totizto viest k anarchii – a teda treba skuor pozerat na to
    preco je to tak a nie preco to nie je inak … tiez netvrdim, ze je vsetko idealne …

    Keby som mal riesit problem potreby nazvou parametrov ja – urcite raz budem – najprv si uvedomim
    preco vlastne potrebujem nieco take … casto to naznacuje zlu cestu – povedal by som prekrocenie
    urovne abstrakcie za „rozumnu“ hranicu …

  15. No jde pouze o vlastní třídy – typicky metody mého vlastního DAO objektu, v Grails se může jednat o parametry metody opět vlastního controlleru pro automatické injektování parametrů z HTTP requestu a podobně. Tj. skutečně bych řekl, že ve valné většině případů člověk cizí obecně použitelná knihovna má zájem na čtení argumentů „klientského“ kódu – tedy toho co píšu já. Stěží to bude někdo chtít dělat obráceně.

    Ty anotace by byly řešením, věřím, že když by si na to pár mozků dalo ten čas, tak se třeba přijde i s lepším řešením. Ale evidentně není vůle.

  16. Tentokrat se da jen souhlasit. Soucasna situace neni dobra a hned tak se nezlepsi. Zajimalo by me jestli ty jmena pouzivas jen u vlastnich trid nebo i u cizich. Myslim ze pouzivat to u cizich je nebezpecny a zbytecny, mam pravdu?

    Sun ma pravdu v tom, ze timto se jmena parametru stavaji soucasti signatury. No ale kdyz je to potreba, tak s tim mel neco delat. Me by se libilo zavest annotaci (pro metody i pro cely tridy), ktera by rekla, ze tomu tak je a v tom pripade zpristupnit jmena parametru v reflexi. Tim by to bylo jasne dany a namitky Sunu by padly. Nevim jestli by to takhle stacilo, zkusenosti s tim nemam.