Czy używacie/czemu nie używacie THIS przy pisaniu OOP?

2

Ja jestem starej daty, niedługo pewnie umrę, ale za moich czasów stosowało się this podczas pisania kodu obiektowego. Pomijam kwestie techniczne, że może 20-30 lat temu języki/kompilatory nie poradziłyby sobie bez takiego jawnego wskazania (piszę w trybie przypuszczającym, po prostu - zastanawiam się, czemu dawniej nikt nie sugerował, żeby ten element ominąć). Tak czy siak - aktualnie nie jest to często wymagane - mimo tego ja staram się stosować. Dla mnie kod z wskazanym jawnie this/self jest czytelniejszy i ładniejszy. Ale np. Android Studio (podczas pisania we Flutter/Dart) mi się sadzi i czuje się nieszczęśliwe z powodu moich dinozaurowych nawyków - co widać na poniższym obrazku.

Co o tym sądzicie?

Jakie są plusy oraz minusy stosowania/braku napisania tego nieszczęsnego this? Czy chodzi jedynie o estetykę (to jest sprawa subiektywna, moim zdaniem z tym dopiskiem kod wygląda lepiej i bardziej intuicyjnie, ale każdy może uważać inaczej) czy są jakieś poważniejsze agrumenty ZA albo PRZECIW?

screenshot-20230805172137.png

2
cerrato napisał(a):

Pomijam kwestie techniczne, że może 20-30 lat temu języki/kompilatory nie poradziłyby sobie bez takiego jawnego wskazania (piszę w trybie przypuszczającym, po prostu - zastanawiam się, czemu dawniej nikt nie sugerował, żeby ten element ominąć).

Czy kompilatory to szersza sprawa, ale IDE lepiej działały po napisaniu this. - zdecydowanie.

W językach są niuanse, np konstruktor z argumentami, który inicjuje pola o takich samych nazwach.
W Javie z tym czuję sie bezpiecznie, ale C++ asekuruję się (tak, śmieszne, nie sprawdzając w referencji jak jest naprawdę). Mglista pamieć popdowiada, że Java tą semantykę zmieniła na lepsze.

Ale i nawet w nowszych jeżykach / IDE napisanie this.pole = daje sytuację jednoznaczną (działa albo błąd kompilacji), a pole = może być "dla naszego dobra" przerobione przez IDE w różny sposób

3

czy są jakieś poważniejsze agrumenty ZA albo PRZECIW?

więcej kilobajtów kodu do utrzymania :) są tacy, co bardzo biadolą jak widzą getxxx() czy setxxx(), ale chętnie dopisują this. tam gdzie to jest zbędne.

2

Ja tutaj widzę kilka różnych perspekty, z których można do tego podejść. Czysto obiektowego podejścia (w kontekście paradygmatu obiektowego), to nie ma to żadnego znaczenia; według mnie.

Myślę, że można to rozpatrzyć z kilku stron.

Najpierw: pola a metody:

  • Przy polach, moim zdaniem to jest kwestia spora. Każdy język jaki znam który ma klasy, ma jakiś zapis na jawny dostęp do memberów tej klasy (zależnie od języka jest to this, @, self, etc.). Nie widzę nic złego w stosowaniu this. jak i niestosowaniu. Czasem, kiedy mamy zmienną i pole nazwane tak samo (np w parametrach konstruktora) to skorzystanie z this jest koniecznością. Nie opowiem się za żadną ze stron, według mnie to nie ma znaczenia.
  • Przy metodach nigdy nie używam this, nie widzę ku temu potrzeby, poza tym nigdy nie zapisuję callbacków w zmiennych, więc nie ma ambiguity do którego obiektu chcemy się odnieść.

Po drugie: dłuższy kod a krótszy kod:

  • Nie sądzę, żeby dopisanie 5 dodatkowych znaków w tym kontekście miało jakieś znaczenie. Jeśli ktoś miałby się opowiadać za albo przeciw this. to powinien podać jakiś lepszy argument niż długość
1

Jak któregoś plusplusowca to irytuje, to zawsze można

#define other this
1

nawet w nowszych jeżykach / IDE napisanie this.pole = daje sytuację jednoznaczną (działa albo błąd kompilacji), a pole = może być "dla naszego dobra" przerobione przez IDE w różny sposób

No właśnie - jeśli w niczym to nie przeszkadza, a może czasem da się uniknąć jakiegoś nałożenia się nazw/jakiś konflikt scope czy namespace to chyba lepiej jednak to dawać. Zwłaszcza, jeśli nie ma żadnych plusów ujemnych - nawet jeśli nic nie zyskasz, to i tak nic nie tracisz, a może kiedyś uniknie się w ten sposób jakiegoś problemu.

więcej kilobajtów kodu do utrzymania :) są tacy, co bardzo biadolą jak widzą getxxx() czy setxxx(), ale chętnie dopisują this. tam gdzie to jest zbędne.

Te kilobajty kodu uznam raczej za żart, a co do reszty - jak @Wibowit zdefiniujesz gdzie jest to zbędne? W sensie (jak napisałem w poprzednim akapicie) - to, że kompilacja pójdzie bez tego nie oznacza, że jest to niepotrzebne, a może się zdarzyć, że dodanie this uratuje komuś tyłek ;)

@Riddle: dla mnie nie ma znaczenia, czy to jest pole, czy metoda. Jeśli odwołuje się do czegokolwiek co jest elementem składowym klasy, to staram się stosować this - żeby było jasne, czy pisząc budzik = getCurrentTime(); chodzi mi o jakąś funkcje z biblioteki podstawowej/jakiegoś frameworka/innego modułu, czy chodzi o metodę wewnątrz obiektu. Oczywiście - są określone zasady widoczności, priorytety itp i da się dojść do tego, co ma zostać wywołane - ale patrząc na taki kod, na pierwszy rzut oka nie wiesz, skąd ten czas ma być pobrany. A przy zapisie budzik = this.getCurrentTime(); od razu wiesz, że do zmiennej ma być podstawiona wartość metody będącej składnikiem obiektu. Za to w pełni się zgadzam, że dodanie tych kilku literek w niczym nie przeszkadza, za to zwiększa czytelność. Zresztą już wiele razy mówiłem, że jestem za tym, żeby dawać więcej kodu (nawet jak można coś skrócić), ale żeby był on bardziej czytelny i opisowy. Dlatego nie lubię różnych hacków, ternary operatorów, postaci skróconych w stylu nawias, średnik, zmienna, znak zapytania, wartość, średnik, krzaczek ;)

1
cerrato napisał(a):

@Riddle: dla mnie nie ma znaczenia, czy to jest pole, czy metoda. Jeśli odwołuje się do czegokolwiek co jest elementem składowym klasy, to staram się stosować this - żeby było jasne, czy pisząc budzik = getCurrentTime(); chodzi mi o jakąś funkcje z biblioteki podstawowej/jakiegoś frameworka/innego modułu, czy chodzi o metodę wewnątrz obiektu. Oczywiście - są określone zasady widoczności, priorytety itp i da się dojść do tego, co ma zostać wywołane - ale patrząc na taki kod, na pierwszy rzut oka nie wiesz, skąd ten czas ma być pobrany. A przy zapisie budzik = this.getCurrentTime(); od razu wiesz, że do zmiennej ma być podstawiona wartość metody będącej składnikiem obiektu.

Jak mówiłem - dla mnie to nie ma takiego znaczenia. IDE i tak inaczej koloruje funkcje instancyjne i globalne albo ze scope'u. Bp w IDE od JetBrains w Javie funkcje instancyjne są pisane normalnie, a funkcje statyczne są pochylone, dla mnie to wystarcza żeby się połapać. Poza tym, pisalem już w takiej ilości języków - i musiałem sobie radzić nie ważne czy this. jest czy nie, że to nie robi mi różnicy specjalnej.

cerrato napisał(a):

Za to w pełni się zgadzam, że dodanie tych kilku literek w niczym nie przeszkadza, za to zwiększa czytelność. Zresztą już wiele razy mówiłem, że jestem za tym, żeby dawać więcej kody (nawet jak można coś skrócić), ale żeby był on bardziej czytelny. Dlatego nie lubię różnych hacków, ternary operatorów, postaci skróconych w stylu nawias, średnik, zmienna, znak zapytania, wartość, średnik, krzaczek ;)

No tak. Argumenty z długością należałoby moim zdaniem całkowicie ignorować; i hacki z nawiasami też są mega słabe.

4
Riddle napisał(a):

Jak mówiłem - dla mnie to nie ma takiego znaczenia. IDE i tak inaczej koloruje funkcje instancyjne i globalne albo ze scope'u. Bp w IDE od JetBrains w Javie funkcje instancyjne są pisane normalnie, a funkcje statyczne są pochylone, dla mnie to wystarcza żeby się połapać. Poza tym, pisalem już w takiej ilości języków - i musiałem sobie radzić nie ważne czy this. jest czy nie, że to nie robi mi różnicy specjalnej.

mam dokładnie takie samo zdanie. podświetlanie pokazuje co i jak, więc jeszcze bardziej to zmniejsza sens dokładania jawnego znacznika zasięgu, z którego chcemy skorzystać.

poza tym na co dzień programuję w scali, a tam jawnej mutowalności jest znacznie mniej niż w językach typowo imperatywnych, więc rzeczy typu pole = nowa wartość robię bardzo rzadko.

cerrato napisał(a):

może się zdarzyć, że dodanie this uratuje komuś tyłek ;)

ja bym raczej szedł w stronę bezpieczniejszych konwencji, np. wszystkie zmienne statyczne są prywatne, linter jest skonfigurowany tak, żeby protestował przy próbie zmiany parametrów metody, itd

gdybym był w sytuacjach, gdzie mam przesłanianie zmiennych i muszę korzystać z this. częściej niż bardzo rzadko (pomijając settery i konstruktory), to zastanawiałbym się czy ktoś przypadkiem nie chce mnie wepchnąć na minę. dlaczego ktoś celowo pcha się w przesłanianie zmiennych w nietrywialnych metodach?

biorąc pod uwagę javkę dla przykładu, zmienne statyczne nazywa się wielkimi literami, a zmienne lokalne to camel case, więc nie da się ich pomylić. zostaje więc pomylenie zmiennej lokalnej, parametru metody i pola w aktualnej klasie. wszystko jest w zasadzie lokalne, więc można się nieco zdyscyplinować i unikać niepotrzebnego przesłaniania zmiennych.

p.s. chyba nie zauważyłem, że temat bardziej o metodach niż polach.

jeśli chodzi o metody, to jeszcze mniej widzę sensu w dopisywaniu tego this., przynajmniej w javce. żeby mieć bezpośredni dostęp do statycznej metody spoza aktualnej klasy to trzeba ją najpierw zaimportować, a chyba się tego specjalnie często nie robi. podobnie jak w przypadku pól, wywołanie metody statycznej jest inaczej renderowane przez np. intellija niż wywołanie metody instancyjnej.

co do samego darta to, jak widzę z pobieżnej analizy przykładów, ma inaczej działające importy niż javka. w przypadku darta byłbym raczej skłonny korzystać z importów takiego typu (tzn. z as):

import 'package:http/http.dart' as http;

wtedy od razu widziałbym z której biblioteki korzystam w miejscach wywołania. importowanie bez prefiksu to jak dla mnie robi śmietnik w aktualnym zasięgu, więc za każdym razem trzeba mieć do tego dobre wytłumaczenie.

3

w php się stosuje this a jak wszyscy wiemy, php to najlepszy język więc ten kto nie stosuje this robi to źle :)

2

Nie piszę this w C# praktycznie w ogóle, nazwy parametrów i pól w klasie nigdy się nie nakładają przez konwencje nazewnicze (i widać co jest polem, a co parametrem), więc nie trzeba jawnie tego wskazywać.

1
cerrato napisał(a):

a może się zdarzyć, że dodanie this uratuje komuś tyłek ;)

Stosuję TDD i mam testy pod dostęp do wszystkich wartości, więc szansa na taki błachy błąd jest u mnie bardzo niska.

1

@Saalin: konwencje nazewnicze nie mają tu nic do tego, tzn to tylko ustalenia wewnątrz projektu i nie jest standardem.

1

@ehhhhh: to chyba w PHP, w .NET konwencje są silne i w każdym projekcie do tej pory nikt nie miał swoich autorskich pomysłów.

1

@Saalin: Pisałem przez kilka lat w C# nikt nie wymagał ode mnie konkretnego nazewnictwa, jeszcze raz to napiszę, wszelkie ustalenia konwencji nazw to tylko ustalenia wewnątrz projektu/zespołu, nic więcej.

0
ehhhhh napisał(a):

@Saalin: Pisałem przez kilka lat w C# nikt nie wymagał ode mnie konkretnego nazewnictwa, jeszcze raz to napiszę, wszelkie ustalenia konwencji nazw to tylko ustalenia wewnątrz projektu/zespołu, nic więcej.

To, że w C# absolutnie wszyscy piszą metody PascalCase to też kwestia ustaleń wewnątrz zespołu? :D
Poza tym wskazałem, że rozwiązuje to problem this przez ostatnie 5 lat u mnie, więc jest to jakiś argument za utrzymywaniem konwencji, choćby po to, żeby nie używać this.

2

@Saalin: jeśli cokolwiek nie jest wymuszone przez kompilator/interpreter to tak. Bo jak napiszesz inaczej to dalej będzie działać.

1

Mi to obojętnie - dopasowuje się do stylu istniejącego kodu. Jak piszę sam to raczej z lenistwa piszę jak jest krócej/szybciej (np. wygenerowane przez copilota tylko czytam poprawność i rzadko poprawiam). Jako że najczęściej piszę w C# to nie używa się zmiennych globalnych a statyczne pola poprzedzam s_ dla czytelności. W pojedynczych przypadkach gdy jest kolizja nazwy albo stwierdzam że może być mniej czytelnie to używam this. Generalnie staram się używać tych zasad ale jeśli na siłę zmniejsza to czytelność to je okazjonalnie łamie (zasady są żeby ułatwiać życie a nie na siłe utrudniać)

1
Saalin napisał(a):
ehhhhh napisał(a):

@Saalin: Pisałem przez kilka lat w C# nikt nie wymagał ode mnie konkretnego nazewnictwa, jeszcze raz to napiszę, wszelkie ustalenia konwencji nazw to tylko ustalenia wewnątrz projektu/zespołu, nic więcej.

To, że w C# absolutnie wszyscy piszą metody PascalCase to też kwestia ustaleń wewnątrz zespołu? :D
Poza tym wskazałem, że rozwiązuje to problem this przez ostatnie 5 lat u mnie, więc jest to jakiś argument za utrzymywaniem konwencji, choćby po to, żeby nie używać this.

Akurat w C# może zdarzyć się this:

public Foo(int a)
{
  this.a = a;
}

I tutaj też czasem mamy konwencję _a, za którą nie przepadam.
Ponadto CamelCase nie jest zawsze jednoznaczne, bo nie wiemy czy coś nie jest np. klasą statyczną. Plus pewnie znajdą się jeszcze inne wyjątki. Niemniej jednak chyba nie ma to aż takiego znaczenia.
Kiedyś używałem this, obecnie jest to mi raczej obojętne - dostosowuje się do panującej konwencji.

2

Dla mnie też to jest czytelniejsze.
Szkoda mi zaprzątać sobie głowy żeby pamiętać jakim krojem jest pisane.
A jak widzę w kodzie szczególnie javowym:

this.metoda()
super.metoda()
metoda()
self.metoda()

to widzę że pierwsza jest z aktualnej klasy druga jest z nad klasy, 3 statyczna a 4 na siebie przez proxy np springowe (najczęsciej taka konwencja w moich projektach).

Ale to jest dyskusja z cyklu czy wolisz otwierać nawias w nowej lini czy w następnej, czy pierwsze pole w metodzie jak dzielisz na linie dajesz po nawiasie czy w kolejnym itd.

Pomijam, że nie wszyscy uzywaja idea + edytory webowe np w gitlabie wyświetlaja składnie inaczej.

0

@mstl: konwencja z underscore jest powszechna, rozwiązuje temat, jak mówiłem do tej pory stosowana w każdym projekcie w jakim byłem. Przekilkalem kilka opensource'ów (Serilog, Automapper, ELSA Workflows) I też jest stosowana. To, że this może się zdarzyć to nic dziwnego, bo to słowo kluczowe istnieje w języku.

1

No ja nie rozumiem po co stosować nadmiarowe this. To moim zdaniem nic nie wnosi, a dziś już każdy edytor inaczej koloruje zmienną lokalną a inaczej pole klasy, więc pomyłka jest niemożliwa.
Dla mnie pisanie zawsze this to trochę tak, jakby w pliku np był dodany import, ale potem bym miał podawać i tak cały namespace nadmiarowo przy każdym użyciu

1

@gajusz800: no tak średnio.
Np github: link
screenshot-20230805221849.png
Po czym rozpoznać że noHeaders() jest static ? Skoro kolor funkcji jest taki sam, czcionka jest taka sama itd. ?

2

@gajusz800: Proszę z edytora:

screenshot-20230805222335.png

1

W niektórych językach nie da się inaczej albo jest to sposób najbardziej standardowy.
w sensie np. w JS można użyć domknięć i wszystkie potrzebne funkcje używane w obiekcie zadeklarować w zasięgu metod:

function createFoo() {
   function hello() {....}
   return {
      bar() { return hello() + 1;}
   }
}

Ale jeśli użyjesz choćby klas z ES6 (czyli obecnie najbardziej standardowe podejście do OOP w JS), to masz this i już.

Z kolei w Pythonie i Rust metody deklarują jawnie zmienną self(w Pythonie można sobie wybrać nazwę zmiennej), więc też musisz użyć kropki.

Ogólnie więc odpowiedź jest zależna od języka. Chociaż ja bym się przychylał do jawnego pisania this/self, jeśli mamy taką możliwość. Bo wtedy od razu widać, że coś jest metodą/polem.

1
Schadoow napisał(a):

Pomijam, że nie wszyscy uzywaja idea + edytory webowe np w gitlabie wyświetlaja składnie inaczej.

Żeby wyświetlić "ciepła woda osobno, zimna woda osobno", odróżnić zmienne a pola trzeba wejść w semantykę, to przekracza syntaktyke (aka składnię). To już znacznie podnosi poprzeczkę i co bardziej proste IDE czy edytorki tego nie robią (lub nie jest możliwe na językach dynamicznych)

1

Kolorowanie w edytorkach odbywa się często przez regexpy czy jakieś inne podobne proste zasady, a te nie wychwycą semantyki.

Dopiero użycie parsera danego języka programowania czy narzędzi wyżej w abstrakcji od zwykłego parsera (np. różnego rodzaju serwery LSP https://microsoft.github.io/language-server-protocol/ ) pozwala na poprawne rozróżnienie semantyki.

Natomiast dałoby się zrobić edytorek w przeglądarce, który będzie analizować to semantycznie. Tyle, że taki edytor mógłby działać wolniej przez koniecznośc parsowania i analizy (chociaż jeśli założymy, że byłoby to readonly, to wystarczyłoby raz zanalizować i już). No i trudniej byłoby dodać wsparcie dla wielu języków programowania naraz (bo do każdego języka programowania należałoby albo znaleźć gotowe narzędzia do analizy, albo samemu taką napisać).

2

@Wibowit:
Temat zszedł z kursu. Ale webowe edytory też zapewniaja wygodną nawigację. jasne jest to prosty search ale wystarczy.:
Przykład:

screenshot-20230806105811.png

Pomijam, że wszyscy tutaj płaczą jak to nie wiązać się do jednego frameworku ale do jednego edytora(zeby kod był czytelny) to juz okaj :p ?

1

@Schadoow: wiem, że zapewniają, ale to nadal bieda. po co mam używać biednego narzędzia, skoro mogę używać porządnego? załadowanie nietrywialnego pull requesta do intellija trwa zwykle duuużo krócej niż jego późniejszy code review.

Pomijam, że wszyscy tutaj płaczą jak to nie wiązać się do jednego frameworku ale do jednego edytora(zeby kod był czytelny) to juz okaj :p ?

bo frameworki wychodzą z mody i stają się legacy crapem, a intellij jest zawsze na czasie :) poza tym zmiana ide jest dużo prostsza niż zmiana frameworka, można nawet używać kilku ide w jednym projekcie. nie wiem czemu miałbym unikać intellija, skoro dzięki niemu mogę uniknąć dziwnego cudowania z wyręczaniem pseudo-edytorków w sematycznej analizie kodu.

p.s. zaznaczę jeszcze, że w powyższym chodzi mi o porządne code review, bo o tym była dyskusja z @Schadoow a także o samo rozwijanie kodu.

do samego przypadkowego przeglądania kodu z przypadkowych repozytoriów te edytorki online mają pewną przydatność.

0

@Wibowit: Ale to nie chodzi o to czego ty używasz.

poza tym zmiana ide jest dużo prostsza niż zmiana frameworka, można nawet używać kilku ide w jednym projekcie.

No jak spawasz czytelność kodu pod idea to tak średnio :p.

0

tak, piszmy kod taki, żeby ludzie piszący lodówką mogli się połapać o co w nim chodzi

co kto lubi

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