Finální třídy v Nette – proč?
- Ondřej Mirtes
- Člen | 1536
Ahoj,
už několikrát jsem narazil na toto nepříjemné omezení a chci se zeptat,
proč tomu tak je – proč jsou některé třídy v Nette označené
jako finální a nelze si je tedy podědit?
Hodilo by se mi např. podědit si Tools, abych pak v kódu nemusel rozlišovat, jestli je daný tool ode mě nebo z Nette – takhle musím přemýšlet, jestli se mám odkazovat na třídu Tools nebo např. MyTools…
Nyní se snažím napsat si skript, který zajišťuje kompatibilitu mezi NPrefixed a non-prefixed verzí Nette, aby člověk při nemilém zjištění, že na serveru běží nějaký HTTP rozšíření, nemusel přepisovat celou svojí aplikaci, ale musel pořešit jen místa, kde se odkazuje přímo na HttpRequest třídu. Nápad je takový (zahlédl jsem ho zde na fóru, psal to myslím Roman Sklenář):
...
class FreezableObject extends NFreezableObject { }
class Image extends NImage { }
class ImageMagick extends NImageMagick { }
class InstanceFilterIterator extends NInstanceFilterIterator { }
...
Jenže ho nelze zrealizovat kvůli tomu, že např. třídy String nebo Environment (na které se člověk v kódu hodně často odkazuje) jsou deklarované jako finální.
- Ondřej Mirtes
- Člen | 1536
sodae napsal(a):
Můžu se zeptat proč tu všichni postujete co vám prostě vadí ? Bud prostě se Davida vyzve k odstranění „problému“ ze všech souborů a bud se tak stane a nebo třeba napíše proč ne.. Takže Davide, bude něco ?
Takovou reakci tu od něj přesně čekáme (jiná snad ani neexistuje) a
mezitím snad můžeme psát důvody, proč chceme ty final
keywords odstranit :)
- Ondřej Brejla
- Člen | 746
Tím „důvody“ asi myslíš „důvod“, že ;-) Podědit si
třídu…:-) Tak Davida zkuste donutit, ať ze stávajících
final
implementací udělá abstract
a teprve z nich
třeba prázdné final
…a vy si můžete beztrestně dědit
abstract
y :-D Fuj…to je ale ošklivé řešení…snad ho nebude
moc lidí brát vážně ;-)))
- David Grudl
- Nette Core | 8227
Nette obecně používá přístup „všechno zakázat a povolit až tehdy, když není jiného zbytí“ ;)
Takže je úplné možné, že to překáží, ale v tom případě se stačí ozvat.
No když už se Ondřej ozval, tak mu budu oponovat.
Hodilo by se mi např. podědit si Tools, abych pak v kódu nemusel rozlišovat, jestli je daný tool ode mě nebo z Nette – takhle musím přemýšlet, jestli se mám odkazovat na třídu Tools nebo např. MyTools…
Statické třídy jako Debug nebo Environment jsou final, protože nejsou navrženy k rozšiřování. Pokud by je bylo potřeba rozšířit, chce to otevřít diskusi na fóru a nějak na to třídy připravit.
Statické třídy jako String nebo Tools jsou final, protože fungují jen jako „namespace“ pro funkce. Je otázka, jestli chování, kdy se nemusí rozlišovat „jestli je daný tool ode mě nebo z Nette“ je správné, ale dejme tomu, tady by se asi dalo final zrušit.
Nyní se snažím napsat si skript, který zajišťuje kompatibilitu mezi NPrefixed a non-prefixed verzí Nette…
Porušit objektový návrh, tj. vhodné používání modifikátorů přístupu, kvůli vyloženému hacku, by těžko šlo udělat s čistým svědomím. Nicméně v tomto případě si myslím, že to stejně nemůže 100% fungovat, i kdyby ve frameworku žádné final nebyly.
- Ondřej Mirtes
- Člen | 1536
Jasně, já na jednu stranu chápu, proč jsou final. Na druhou stranu nijak framework nepoškodí, když si je někdo podědí a bude používat svoji variantu. Ale rozhodně nechci, abys znásilňoval objektový návrh kvůli mým výmyslům :) Ale ostatní tu píšou, že si taky chtějí podědit některé třídy.
Jednoznačná překážka je to ovšem u té kompatibility s NPrefixed
verzí. Nebál bych se, že by to nefungovalo – myšlenka je taková, že
soubor s potomky všech tříd ti vyřeší 99% kódu a zbylé 1% vyřešíš
ručně – např. zakomentuješ
class HttpRequest extends NHttpRequest { }
a ve svém kódu ručně
opravíš místa, kde HttpRequest používáš. (I když si teď uvědomuji,
že se většinou bere přes Environment::getHttpRequest()
a
stačilo by podědit Environment, který je ovšem final, ale to byl jen
příklad :))
Píšu si totiž takový „improved Skeleton“, který bude mít navíc
spoustu featur, které využívám v každé aplikaci, a chci tam mít
pořešené i toto. Nejhorší zjištění je, když zjistím, že na serveru
běží HTTP rozšíření, a já kvůli tomu musím hodinu jak opice přidávat
Nka
do všech zdrojových kódů aplikace :)