Wszechobecny final na zmiennych

0

Hejka, mam zagwozdkę.

Ostatnio przeglądając projekt kolegi z pracy natknąłem się na wszechobecność finali czyli.

void jakasMetoda(){
  final Obiekt cos = createObjekt();
  cos.setPole("haha");
}

OR

void innaMetoda(){
  final Cos qwe = ....
  final Cos2 qwe2 = ....etc

  return obliczCos(qwe,qwe2);
}

etc...

Wszędzie takie coś było w każdej praktycznie metodzie.
Nawet w testach spotkałem się, że był użyty final (na zmiennych).

Nawet spotkałem się z opinią, że powinno się umieszczać wszędzie final w testach (zmienne) w celu optymalizacji.

Czy takie coś jest powszechne i musze się douczyć ?
Czy może z innego względu np. optymalizacji ?
Opinie na temat - Czy warto, po co etc ?

Dzieki !!! ;)

1

Ja pisałem żeby mieć pewność. Pewność że nikt mi nie podmieni referencji (w przypadku obiektów) lub wartości (w przypadku prymitywów). Teraz nie piszę bo wymieniłem Javę na język w domyślnie jest 'final'

Koledze powiedz że jak lubi domyślny 'final' to żeby spojrzał na Scalę (Kotlina?) lub Rusta. Albo Haskella nowym wszystko 'final' i trzeba się trochę nakombinować żeby nie mieć 'final' XD

Co do optymalizacji to jak sprawdzali wygenerowany bytecode to podobno była. Ale czy to dalej działa czy już javac zmądrzał i nie potrzebuje to trzeba by sprawdzić

0

Ja pisałem żeby mieć pewność. Pewność że nikt mi nie podmieni referencji (w przypadku obiektów) lub wartości (w przypadku prymitywów).

Ale kto miałby to robić i dlaczego? :)

4
twoj_stary_pijany napisał(a):

Ja pisałem żeby mieć pewność. Pewność że nikt mi nie podmieni referencji (w przypadku obiektów) lub wartości (w przypadku prymitywów).

Ale kto miałby to robić i dlaczego? :)

Inny programista. Ja po pijaku. Zło czai się wszędzie

8

Znam to - final bierze się z obrzydzenia do zmiennych. ale żadnej optymalizacji nie wnosi.

Dla mnie to oznacza, że kolega już dojrzał do tego, że java do pisania kodu się nie nadaje i stara się tymi finalami jakoś naprawić, ale to bezsensowna praca.
Kotlin, albo Scala.

3

czasem lepiej przekazać intencję czymś takim:

final int zmienna = cośtam;

niż kombinować bez finala:

int zmiennaBezFinalaAleITakNieWolnoJejRuszać = możecośinnego;

:)
ale i tak słabo te wszędobylskie finale wyglądają.

co do optymalizacji to bardzo wątpliwe by dla zmiennych lokalnych final cokolwiek zmieniał w wydajności. kompilator i tak zamienia wszystkie operacje na lokalnych zmiennych na https://en.wikipedia.org/wiki/Static_single-assignment_form . co innego np. pola w klasach. tam dodanie final może wpłynąć na optymalizację.

1

@ArturoS159:

jednym z powodów do final jest pewnego rodzaj wymóg formalny przy metodach w klasach anonimowych, i to na pewno podnosi statystykę tego, co widzisz.
To da się na chłopski rozsądek wytłumaczyć, nie jest to całkiem głupie, ale teraz w krótkim poście się nie podejmuję.

Co znów podnosi wypowiedź @jarekr000000 , czy charakterystyczne dla Javy klasy anonimowe więcej pozytywnego, czy negatywnego wnoszą ... byłem ich gorącym zwolennikiem, po romansie z C# zobaczyłem, jak można to chyba fajniej zrobić, entuzjazm osłabł. Nie przekreślam, ale ..

Na pewno elementy funkcyjne w J>=8 nieco znoszą k.a (a naprawdę pod maską, znów nimi są, choć w innym sensie)

1

Dla mnie final przy argumentach i zmiennych nie ma żadnego sensu.

Jeśli ktokolwiek (ja albo ktoś inny) uzna żeby zmienić zmienną, to niech to zrobi, nie ważne czy jest final. Jeśli uzna że powinna nie zostać zmieniona, to nie będzie. Takie final w kodzie oznacza kilka rzeczy:

  • nie masz testów na tyle dobrych, które dałyby Ci pewność że aplikacja działa
  • dodawanie kawałków kodu które niby mają pilnować czegoś, ale tak na prawdę nie pilnują nic, bo jak ktokolwiek zobaczy "cannot modifiy final variable", to po prostu zabierze tego finala.
  • nic nie dodają, bo w takich projektach są dwie strony: albo każda zmienna ma final (przez co final traci swoje "informacyjne" moce), albo żadna nie ma - co ma w sumie najwięcej sensu.

Nie zrozumcie mnie źle, jestem jaknajbardziej za tym żeby nie redefiniować zmiennych, żeby raz przypisana wartość do zmiennej już taka została, a jak ma się zmienić, to lepiej zrobić inną zmienną - staram się tak pisać kod praktycznie zawsze. Ale to nie znaczy że potrzebuje keyworda żeby mnie do tego pilnował, no szanujmy się.

Jedyny final jaki ma dla mnie sens, to ten przy polach klas, ale to jednak coś zupełnie innego niż final na zmiennych lokalnych, klasach czy argumentach.

0

podsumowując: final kosztuje
:D

1

@Korges: Albo wcześniej powiedział, że chodzi o optymalizację na poziomie kompilatora i wykonywania na JVM, albo p...bzdety.

Klasa finalna - to akurat naiwne podejście Java. Właściwie każda klasa powinna być final, chyba, że autor pisząc ją naprawdę przemyślał jej budowę pod kątem bezpiecznego przeciążania składników. Jeżeli masz jakąkolwiek logikę w metodach publicznych klasy, to właściwie z automatu dziedziczenie bezpieczne nie jest. Pochodną tego jest final na metodzie.

Pole klasy - wiadomo, że zostało zainicjalizowane przy tworzeniu obiektu, wiadomo, że ta wartość tam jest. To, że można je nadpisać jakąś magią nie ma znaczenia, jak używasz java.unsafe to powinieneś się domyślić, że tam jest coś "unsafe". Jak piszesz w C++,. odwołasz się pointerem, przeskoczysz parę bajtów i coś nadpiszesz, to też powinieneś zdawać sobie sprawę, że robisz to na własne ryzyko.

Zmienna - ja staram się pisać. to final, bo później jasno widzę, że wartość nie została zmieniona, nie może zostać normalnie zmieniona, jak mi przyjdzie ją zmienić, to kompilator mnie ochrzani i będę mieć okazję się zastanowić. Jak ktoś inny będzie w tym kodzie grzebać, to też dostanie te same wskazówki.

Parametry - tutaj nie stosuję z lenistwa. Zakładam, że nie jestem dość szalony, żeby nadpisywać wartość parametru metody. Ale uważam też, że sam fakt, że parametry metody nie są final nienajlepiej świadczy o projektantach języka.

Gdyby OP, jak to było już napisane korzystał z bardziej współczesnego języka, to problemu by nie dostrzegł, bo np. zawsze trzeba wprost określić, czy zmienna/pole ma być final, czy nie, klasy są domyślnie final, parametry też. A w Javie wiadomo- gdyby chcieć zrobić normalnie, to połowa kodu zamieniłaby się w final.

0
piotrpo napisał(a):

@Korges: Albo wcześniej powiedział, że chodzi o optymalizację na poziomie kompilatora i wykonywania na JVM, albo p...bzdety.

Klasa finalna - to akurat naiwne podejście Java. Właściwie każda klasa powinna być final, chyba, że autor pisząc ją naprawdę przemyślał jej budowę pod kątem bezpiecznego przeciążania składników. Jeżeli masz jakąkolwiek logikę w metodach publicznych klasy, to właściwie z automatu dziedziczenie bezpieczne nie jest. Pochodną tego jest final na metodzie.

To by nie miało sensu, nie w javie.

0

@Riddle: Przykład z Effective Java:
Próbujemy się dowiedzieć ile razy dodawano element do listy:

public class ListWithCounter<T> extends ArrayList<T>{

  @Override
  public boolean add(T element){
      counter ++;
      super.add(element);
    }

  public boolean addAll(Collection<T> elements){
    counter += elements.size();
    super.addAll(elements);
  }
  
}

I niby proste, tylko w klasie ArrayList możesz mieć tak:

public boolean addAll(Collection<T> elements){
  elements.forEach((e) -> this.add(e));
}

W efekcie, twoja metoda addAll() będzie zliczać nieprawidłowo.

2
Riddle napisał(a):

To by nie miało sensu, nie w javie.

Akurat właśnie w javie ma to sens. Jasno wskazujesz, które klasy są przewidziane do rozszerzania, a które nie (i defaultowo wszystkie nie), bo raczej nie masz czasu myśleć nad tym co się może stać jak ktoś źle podziewiczy.

0
jarekr000000 napisał(a):
Riddle napisał(a):

To by nie miało sensu, nie w javie.

Akurat właśnie w javie ma to sens. Jasno wskazujesz, które klasy są przewidziane do rozszerzania, a które nie (i defaultowo wszystkie nie), bo raczej nie masz czasu myśleć nad tym co się może stać jak ktoś źle podziewiczy.

To co mówisz jest prawdą, jak kompilujesz wszystkie klasy na raz.

Ale jak masz system, w którym różne moduły są kompilowane osobno, i podczas runtime'u linkuje się różne jar'y, wtedy to byłby kłopot. Nikt Ci nie broni dodać do każdej klasy final jak potrzebujesz, ale robienie tego z defaulta moim zdaniem to bardzo słaby pomysł.

Poza tym, nie za wiele byś zyskał teraz, bo nadal programiści mają trzy stany: "klasa może być rozszerzana", "klasa nie może być rozszerzana", "nie wiem/wszystko jedno/nie pomyślałem o tym". Dodanie finala, oznacza drugie, niedodanie go oznacza pierwszy lub ostatni.

Teraz, jeśli klasy z defaulta byłyby final, i ktoś dodałby słówko typu open, żeby zrobić że byłaby rozszerzalna, nadal mamy te trzy stany, i wtedy open oznacza to pierwsze, a brak open oznacza jedno z dwóch ostatnich.

6

@Riddle: Klasa albo się nadaje do dziedziczenia, albo się nie nadaje. To nie fizyka kwantowa, żeby tu wciskać nieoznaczoność. Żeby się nadawała, ktoś musi ją do tego przygotować, albo chociaż przejrzeć i sprawdzić czy nie ma oczywistych problemów. Jak to zrobi, to może wrzucić "open" i wiadomo. Jak nie zrobi, to możesz bez żadnego ryzyka ją enkapsulować. W praktyce pisząc jakąś klasę nie myślisz o tym, że ktoś będzie chciał ją rozszerzać, więc sensownie jest założyć, że jest to związane z ryzykiem.

0
piotrpo napisał(a):

@Riddle: Klasa albo się nadaje do dziedziczenia, albo się nie nadaje. To nie fizyka kwantowa, żeby tu wciskać nieoznaczoność. Żeby się nadawała, ktoś musi ją do tego przygotować, albo chociaż przejrzeć i sprawdzić czy nie ma oczywistych problemów. Jak to zrobi, to może wrzucić "open" i wiadomo. Jak nie zrobi, to możesz bez żadnego ryzyka ją enkapsulować. W praktyce pisząc jakąś klasę nie myślisz o tym, że ktoś będzie chciał ją rozszerzać, więc sensownie jest założyć, że jest to związane z ryzykiem.

Albo się nadaje albo nie, to prawda, ale to czy się nadaje czy nie - ktoś to musi ocenić. Większość ludzi jednak tego nie robi, i zostawia je w takim "nie określonym stanie" (czyli nie dodaje ani final w javie ani open w kotlinie). W większości projektów jednak klasy raczej mają tendencję że nic złego się nie stanie kiedy się je rozszerzy. Większość projektów składa się z tysięcy klas, nikt kto je programuje nie zastanawia się "czy tą klasę można rozszerzyć czy nie można". W świecie w którym każdy kto dodaje nową klasę zastanawia się czy tą klasę można rozszerzyć czy nie, Twój argument miały sens - ale tak nie jest. Jak wejdziesz do dowolnego projektu w kotlinie, gdzie używa się open, to jakiś mały procent z klas jest open. Dlatego ze tylko ten mały procent jest faktycznie rozszerzalny, a pozostałe 99% nie jest? Nie - tylko dlatego że w pozostałych 99% przypadkach nikt się nad tym nie zastanawiał, tylko problem z tym jest taki, że chcą potem użyć jakiekolwiek z tych klas w innym jarze który będzie kompilowany później, to będzie rodziło kłopoty.

Mało rzeczy zyskujemy dodając automatycznie final do klasy - jedyne co zyskujemy, to "ochronę" przed dziedziczeniem czegoś tam gdzie nie trzeba, co i tak nie ma znaczenia bo dobry programista raczej nie będzie dziedziczył tam gdzie nie trzeba. To jest taka ochrona przed samym sobą, kiedy ktoś nie wie co robi.

Nie mówię że dziedziczenie to dobre rozwiązanie, żę trzeba zrobić żeby każda klasa się dała rozszerzać - to co mówię, to po co sobie samemu wrzucać kłody pod nogi, takim automatycznym final.

2

@Riddle: Chyba zaczynamy dyskutować o gustach, co trochę nie ma sensu, bo ja wolałbym, żeby przypadkowych klas nie dało się rozszerzać, ty wolałbyś odwrotnie. Patrząc na języki, które powstały po Javie, to raczej mój gust jest w maintreamie (co nie znaczy, że jest dobry). C# - musisz wprost wskazać którą metodę możesz rozszerzyć. Scala, Kotlin podobnie. Podpierając się autorytetami, Bloch też się ze mną zgadza https://ahdak.github.io/blog/effective-java-part-3/ (item 19).

0
piotrpo napisał(a):

@Riddle: Chyba zaczynamy dyskutować o gustach, co trochę nie ma sensu, bo ja wolałbym, żeby przypadkowych klas nie dało się rozszerzać, ty wolałbyś odwrotnie.

Nie, też wolałbym żeby się nie dało.

Ale niestety widzę jaką to ma konsekwencję, w przypadku rozszerzania klas z innych .jarów, które się kompiluje osobno i dołącza w runtime'ie. I utrudnienie tego, to za duży koszt względem potencjalnie małego zysku.

1

@Riddle: Trochę tego argumentu nie kupuję. Jeżeli dołączam do projektu jakąś bibliotekę, to zakładam, mam nadzieję, że słusznie, że jej autor przez chwilę pomyślał, jak będę jej używał. Java ma raczej mało możliwości robienia tego za pomocą self-documenting code. Dostęp pakietowy - mało użyteczny, bo wymusza wrzucanie wszystkiego do jednego pakietu, a i tak da się to obejść. Klasy abstrakcyjne z template methods - nie modne. Problem jaki jest w Javie, to praktyka - nikt nigdy się nad tym nie zastanawiał i teraz jesteśmy w sytuacji, że dziedziczenie jest ogólnie złe, bo łatwo się wpakować w kłopoty. Tylko ta sytuacja wynika ze składni języka, w którym wszystko da się rozszerzyć i włamać do każdego pakietu na legalu. Nie znaczy to, że ta sytuacja jest dobra ;)

0
piotrpo napisał(a):

@Riddle: Trochę tego argumentu nie kupuję. Jeżeli dołączam do projektu jakąś bibliotekę, to zakładam, mam nadzieję, że słusznie, że jej autor przez chwilę pomyślał, jak będę jej używał. Java ma raczej mało możliwości robienia tego za pomocą self-documenting code. Dostęp pakietowy - mało użyteczny, bo wymusza wrzucanie wszystkiego do jednego pakietu, a i tak da się to obejść. Klasy abstrakcyjne z template methods - nie modne. Problem jaki jest w Javie, to praktyka - nikt nigdy się nad tym nie zastanawiał i teraz jesteśmy w sytuacji, że dziedziczenie jest ogólnie złe, bo łatwo się wpakować w kłopoty. Tylko ta sytuacja wynika ze składni języka, w którym wszystko da się rozszerzyć i włamać do każdego pakietu na legalu. Nie znaczy to, że ta sytuacja jest dobra ;)

No taka możliwość włamania się do pakietu to jest coś, co pozwala nie upaść wielu projektom. Czy dobrze byłoby mieć wszystkie klasy od początku pozamykane? Możliwe. Czy warto to dodać dodatkowym kosztem potencjalnie zwiększenia sobie pracy poprzez takie automatyczne dodawanie final w miejscu gdzie to nie ma zalet - no moim zdaniem ten koszt jest zbyt duży.

2

@Riddle: No ok, ja rozumiem argument, że używamy kiepskich bibliotek, albo w projekcie obok piszą niechlujny kod. Tylko moim zdaniem piszą tak, bo mogą, bo tak ich uczy język. W Scali, Kotlinie, C# też się pisze software i jakoś dają radę. Zresztą mając lekkiego świra na punkcie testów (w pozytywnym znaczeniu), powinieneś doceniać konieczność świadomego kreowania zewnętrznego API "jednostki", a do tego to się właśnie sprowadza - trzeba pomyśleć o przypadkach użycia.

0
piotrpo napisał(a):

@Riddle: No ok, ja rozumiem argument, że używamy kiepskich bibliotek, albo w projekcie obok piszą niechlujny kod.

Nie chodzi o niechlujny kod w bibliotece.

Możliwość nadpisania klasy w .jarze który dołączasz, który był skompilowany wcześniej, nawet w najlepiej napisanym kodzie czasem jest bardzo pomocne.

Akceptowalnym kompromisem, byłoby możliwość ustalenia podczasa uruchamiania kodu coś w stylu "classes without keyword behave as: final/open", żeby ten kto używa tego .jara, mógł sobie to ustalic - jak chce, to może nadpisać te klasy, jak nie to nie. Ale zrobić żeby każda klasa z defaulta była nienadpisywalna w takim dynamicznym .jare - rozumiem do czego zmierzasz, faktycznie klasy z defaulta final są delikatnym dobrym krokiem w stronę lepiej przemyślanych klas, ale to jest bardzo duży konstraint. podobym constraintem byłoby zrobić że każda funkcja jest final i nie można jej nadpisać. albo to że interfejsu nie może rozszerzyć inny interfejs.

Jak już mówiłem - zgadzam się że klasy które domyślnie są final byłyby pomocne w pisaniu kapkę lepszej jakości kodu - że jeśli ktoś jest nie ogarem, i nie wie które klasy są rozszerzalne a które nie, to dobrym pomysłem byłoby myśleć za niego i zrobić większość klas final. Gdyby to można było wprowadzić zerowym kosztem, to I'm all for it. Ale nie można,

1

@Riddle: Ale ja nie proponuję zmiany w Javie, że nagle dodajemy open, final robi się deprecated, a za parę wersji wszystko co nie jest jawnie open jest closed. Jedynie piszę, że dobrze jest przyjąć konwencję, w której zamyka się wszystkie klasy, z wyjątkiem tych, które chce się umyślnie zrobić otwartymi. Zresztą z tego co pamiętam, piszesz też w Kotlinie - dorzucasz tam z automatu open do każdej klasy?

2
piotrpo napisał(a):

@Riddle:Dostęp pakietowy - mało użyteczny, bo wymusza wrzucanie wszystkiego do jednego pakietu

Widziałeś te prezentacje?

albo tę:

Niby widzę te zalety package scope ale i tak jakoś tego nie kupuje. Bordel się robi

0
piotrpo napisał(a):

@Riddle: Ale ja nie proponuję zmiany w Javie, że nagle dodajemy open, final robi się deprecated, a za parę wersji wszystko co nie jest jawnie open jest closed. Jedynie piszę, że dobrze jest przyjąć konwencję, w której zamyka się wszystkie klasy, z wyjątkiem tych, które chce się umyślnie zrobić otwartymi. Zresztą z tego co pamiętam, piszesz też w Kotlinie - dorzucasz tam z automatu open do każdej klasy?

Mówię Ci, że klasy nie dzielą się na final i open - są jeszcze klasy (znakomita większość), które albo nie ma znaczenia co maja, albo nikt nie poświęca wysiłku na nie. Mniej więcej 5% klas powinno być final, 5% powinno być open, pozostałe 90% są w szarej stronie o której nikt nie myśli, i nikt nie nadaje jej żadnych keywordów dodatkowych - bo to nie ma znaczenia. Pytanie brzmi - co powinien zrobić język w takiej sytuacji.

Moim zdaniem mniejszym złem jest, pozwolić żeby język był bardziej liberalny i pozwolił robić programistom to co uważają za słuszne, a nie rzucać kłody pod nogi.

PS: Pamiętaj - to nie jest tak że się nie zgadzam. Gdyby automatycznie finalowanie klas nie dodawały takich problemów jak właśnie te z dynamicznymi .jarami, to byłbym za tym żeby klas

PS: Bardzo proszę nie pinguj mnie już w tej rozmowie.
PS2: Właśnie byłem na spacerze, i mnie olśniło. @piotrpo Tak na prawde to problemem jest dziedziczenie, nie final na klasach. Aktualne dziedziczenie w wielu językach jest słabo zrobione, ma wady, które próbujemy ogarnąć np final, takiego jakie jest to moim zdaniem w ogóle nie powinno się używać.

0

nie ma to sensu, chyba, że masz metody na 50 linii kodu to dla czytelności możesz dać, jeśli seniorzy od Javy 5 nie pozwalają Ci podzielić tego na mniejsze.

final ma sens tylko przy final class i w atrybutach klasy

2

Wiem że mnie nikt nie pytał, ale ja tam jestem za tym żeby w ogóle nie dało się dziedziczyć a zamiast tego tylko implementować interfejsy. Takie sprytne wpinanie się w jakąś bibliotekę/framework i podmienianie ich wnętrzności już widziałem i skończyło się to tym że nie mogliśmy ich później zaktualizować - a bez tego nie mogliśmy podbić wersji javy itd.
Pewnie że to skrajna opinia, ale zdecydowanie zbyt często dziedziczymy i założenie że programiści dziedziczą i robią tak żeby było dobrze jest wg. mnie naiwne bo w 90% przypadków nie wiedzą albo i nawet się nie zastanawiają nad tym co robią.
Scope pakietowy może pomóc itd, ale co z modułami? Java 9 już jest z nami jakiś czas i w sumie to nie widziałem żeby ktoś tego używał a mam wrażenie że mogłyby kilka problemów rozwiązywać.

1
orchowskia napisał(a):

Wiem że mnie nikt nie pytał, ale ja tam jestem za tym żeby w ogóle nie dało się dziedziczyć a zamiast tego tylko implementować interfejsy.

I cząstka, i fala.
Są klasy, które powinno się rozszerzać przez dziedziczenie, i są klasy, które powinno się rozszerzać przez kompozycję.

Takie sprytne wpinanie się w jakąś bibliotekę/framework i podmienianie ich wnętrzności już widziałem i skończyło się to tym że nie mogliśmy ich później zaktualizować - a bez tego nie mogliśmy podbić wersji javy itd.

Tyle tylko, że podmiana dziedziczenia na kompozycję przed takim czymś cię nie uchroni. Wystarczy, że pomiędzy wersjami bibliotek zmieni się sygnatura interfejsu i masz to samo. Chyba, że bawiliście się w hackowanie frameworków przez dziedziczenie.

IMO główną zaletą kompozycji jest testowalność (bo łatwiej dostarczyć jakąś testową implementację interfejsu) i czytelność (od razu widać, co pochodzi z zewnątrz, a co jest wewnętrzną częścią klasy). Faktycznie dziedziczenia od dłuższego czasu używam dużo mniej, co wcale nie znaczy, że ono nie ma sensu w niektórych miejscach.

0
wartek01 napisał(a):
orchowskia napisał(a):

Są klasy, które powinno się rozszerzać przez dziedziczenie

możesz podać przykład poza wzorcem projektowym Template, który w sumie i tak może być zastąpiony przez kompozycję.

1
wartek01 napisał(a):
orchowskia napisał(a):

Wiem że mnie nikt nie pytał, ale ja tam jestem za tym żeby w ogóle nie dało się dziedziczyć a zamiast tego tylko implementować interfejsy.

I cząstka, i fala.
Są klasy, które powinno się rozszerzać przez dziedziczenie, i są klasy, które powinno się rozszerzać przez kompozycję.
...
Faktycznie dziedziczenia od dłuższego czasu używam dużo mniej, co wcale nie znaczy, że ono nie ma sensu w niektórych miejscach.

+1

Taka magiczna wiara, że narzucony/zabnroniony dyktatorsko ficzer języka da wyższą jakoś kodu niezależnie od stopnia myślenia programisty.

Kiedyś w innym moim wątku pojawiała się dyskusja, że mutowalnośc jest złem, i język nie powinien mieć możliwości seterów.
No nie, jak podoba mi się elegancja niemutowalnych roziwązań, to nie można jej odebrać na poziomie jezyka.

Taki wykastrowany język w projektach większej złożoności tylko spowoduje wiecej syfu, przestanie być "turing-complete" (w luźnym sensie) bo ludzie będą emulować dziedziczenie / mutowalność / wstaw friczer jaki lubisz. Jakaś proteza w postaci wyniesienia poza jezyk (XML-programming, lubi ktoś ?), przeniesienie kontroli z kompilatora na runtime itd ...

Java nie definiuje syntaktycznie property / getera / setera, jest to tylko dane przez konwencję. Jeszcze nie spotkałem dwóch libek analizujacych property, które by to robiły na 200% powtarzalnie (tylko seter, brak pola wiodącego dla property itd .. )
C# zrobiło coś fantastycznego, sformalizowało to. W częściach gdzie to jest niewłaściwe, nie używa się property / seterów, ale perfekcyjnie i niezawodnie się analizuje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1