Wszechobecny final na zmiennych

Wszechobecny final na zmiennych
AS
  • Rejestracja:około 4 lata
  • Ostatnio:26 dni
  • Postów:19
0

Hejka, mam zagwozdkę.

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

Kopiuj
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 !!! ;)

RequiredNickname
Kiedyś jak się pisało dłuuuugie metody to takie final zabezpieczało przed podmianą referencji kilkaset linii niżej. Aktualnie długie metody to antypattern i osobiście nie widzę sensu robienia z lokalnych zmiennych finalnych jeżeli metoda ma sensowną długość.
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:12 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
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ć


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 6x, ostatnio: KamilAdam
TS
  • Rejestracja:ponad 5 lat
  • Ostatnio:5 minut
  • Postów:853
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? :)

Zobacz pozostałe 6 komentarzy
TS
Chodzi o to, że jak wprowadzisz buga w dzieleniu przez zero to rozwiązaniem jest fix kodu. A w tym abstrakcyjnym przypadku z finalem bronimy się przed potencjalnym wprowadzeniem buga. W obu przypadkach możesz wykryć bugi testami.
stivens
Mozesz poswiecic 5 sekund na ubranie kurtki albo tydzien na odchorowanie przeziebienia. Zrobisz jak chcesz. Ja Ci kurtki ubierac nie kaze.
TS
Gdybym programował defensywnie to bym miał asercje w co drugiej linijce i kod by był kompletnie nieczytelny. Gdzie jest ta granica? Pomijam już fakt, że i bez tego Java jest nieczytelna.
stivens
Na szczescie nie musze sie nad tym zastanawiac bo pracuje w Scali.
stivens
Ale Twoje pierwotne pytanie bylo bardziej w dtylu "skad sie biora bledy w programach? Przez przypadek? Ale jaki przypadek?!"
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:12 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
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


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
TS
Właśnie dlatego używa się gita :) Po pijaku można równie dobrze usunąć to final.
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4706
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.


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 1x, ostatnio: jarekr000000
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 5 godzin
3

czasem lepiej przekazać intencję czymś takim:

Kopiuj
final int zmienna = cośtam;

niż kombinować bez finala:

Kopiuj
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ę.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
Manna5
Wygląda jak dopisek NIE USUWAĆ do nazw katalogów na współdzielonym komputerze.
Wibowit
hmm, final to bardziej jak atrybut tylko-do-odczytu
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
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)


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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.

edytowany 1x, ostatnio: Riddle
Korges
  • Rejestracja:prawie 5 lat
  • Ostatnio:11 minut
  • Postów:549
0

podsumowując: final kosztuje
:D

edytowany 1x, ostatnio: Korges
Zobacz pozostałe 7 komentarzy
Wibowit
@Riddle: no ten filmik brzmi jakby o tym wiedział i wyciągał z tego wnioski
Riddle
@Wibowit: No nie wiem. Dla mnie brzmi jakby gość mówił o języku w kontekście mikrooptymalizacji. Poza tym final na klasach to jest coś zupełnie innego niż final na zmiennych, gość je miesza ze sobą.
Wibowit
@jarekr000000: z tej dyskusji https://github.com/dotnet/runtime/issues/7183 na moje oko wynika, że .net nie ma :]
Wibowit
@Riddle: jak miesza, skoro omawia je oddzielnie? jak dla mnie jego wywód brzmi jak ocenianie wydajności docelowej (czyli charakteryzacja jita), a nie optymalizacji wygenerowanego bajtkodu. class hierarchy analysis jest robione przez jita, a nie przez javac, no chyba, że mówimy o jawnym sealed, ale nie o tym mowa w filmiku.
Riddle
@Wibowit: No racja. Pomyliłem się.
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
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.

Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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.

piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
0

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

Kopiuj
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:

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

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

Wibowit
public boolean addAll(Collection<T> elements){ var beforeCounter = counter; var beforeSize = elements.size(); var result = super.addAll(elements); counter = beforeCounter + elements.size() - beforeSize; return result; } :P
piotrpo
oj, no dobra...
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4706
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.


jeden i pół terabajta powinno wystarczyć każdemu
Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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.

edytowany 3x, ostatnio: Riddle
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
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.

Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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.

edytowany 1x, ostatnio: Riddle
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
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).

Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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.

edytowany 1x, ostatnio: Riddle
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
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 ;)

Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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.

piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
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.

Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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,

piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
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?

Korges
  • Rejestracja:prawie 5 lat
  • Ostatnio:11 minut
  • Postów:549
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

edytowany 1x, ostatnio: Korges
piotrpo
Zerknę przy okazji.
jarekr000000
Generalnie internal w kotlinie jest ileś razy lepsze od gównianego pakietowego dostępu w javie - zresztą poniekąd ten internal jest filozoficznie zgodne z java module system (choć chyba tylko filozoficznie).
piotrpo
Kotlinowe internal jest dużo lepsze, wadą jest pewna upierdliwość stosowania i tworzenia takiego nowego modułu. Ale może to kwestia oswojenia się.
jarekr000000
Nie widze tych wad. Jeśli chodzi Ci o to, że tworzy sie tony modułów, to z gradle da sie z tym żyć całkiem dobrze (ale mogłoby być lepiej)
Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10035
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ć.

edytowany 4x, ostatnio: Riddle
Korges
Ja dziedziczenia nie lubię. Nawet w DTOsach/POJO wole przepisać pola niż się bawić w supermana. Tak szczerze mówiąc to nie pamiętam żebym w pakiecie javowym chociaż raz użył dziedziczenia przez ostatni rok.
LitwinWileński
  • Rejestracja:prawie 3 lata
  • Ostatnio:dzień
  • Postów:734
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

edytowany 2x, ostatnio: LitwinWileński
orchowskia
  • Rejestracja:około 6 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Zielona Góra
  • Postów:83
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ć.

W0
  • Rejestracja:ponad 12 lat
  • Ostatnio:8 minut
  • Postów:3520
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.

LitwinWileński
  • Rejestracja:prawie 3 lata
  • Ostatnio:dzień
  • Postów:734
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ę.

SZ
AbstractProcessor, AbstractExecutorService, AbstractCollection - skeletal implementations. Chyba zależy dla kogo się pisze.
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
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.


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
edytowany 1x, ostatnio: ZrobieDobrze
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)