furious programming
2018-11-28 15:03

Pamiętacie mój dawny wpis na blogu, w którym opisałem kilka swoich przemyśleń na temat modernizacji składni Pascala? Traktował on m.in. o fuzji bloków kontrolnych, określeniu skoku iteratora pętli for oraz o deklaracji zmiennych w dowolnym miejscu ciała podprogramu, na wzór najpopularniejszych języków programowania.

No i ostatnia propozycja, czyli punkt B., właśnie wchodzi w życie – dla stałych i zmiennych, ogólnych i dla pętli. ;)

Introducing Inline Variables in the Delphi Language

The coming 10.3 version of Delphi introduces a very handy feature to the language, local inline variables with local scope and type inference.

The Delphi language in 10.3 has a fairly core change in the way it allows far more flexibility in the declaration of local variables, their scope and lifetime. This is a change that breaks a key tenet of the original Pascal language, but offers a significant number of advantages, reducing unneeded code in several cases.

Jeśli o mnie chodzi, to jest to świetna wiadomość.


Przez chwilę miałem nadzieję na to, że może jednak będę miał możliwość używania nowych konstrukcji – w końcu FPC cały czas jest w pełni kompatybilny ze składnią Delphi. Niestety moja nadzieja gaśnie z każdą chwilą, ze względu na wypowiedzi ważnych graczy w tym wątku

Wychodzi na to, że deweloperzy zmian nie doceniają, nie chcą implementować inline'owanych deklaracji zmiennych, a co gorsze (dla całego projektu, nie dla mnie), uznają tę nowość za dobry powód do zerwania kompatybilności z Delphi. Wolą zostać przy pradawnej, zardzewiałej składni oraz twierdzić, że jedyne słuszne i najlepsze rozwiązanie to to obecne. Taki beton, o który rozbija się w drobny mak większość sensownych pomysłów modernizacji składni. :/

Sam w dalszym ciągu uważam, że połączenie wewnętrznych deklaracji lokalnych zmiennych w połączeniu z inferencją typów to funkcjonalność, która powinna zostać dodana do składni już dawno temu i której mi ciągle cholernie brakuje.

#fpc #free-pascal #lazarus #delphi

cerrato

a ja pozwolę się sobie nie zgodzić z tym co piszesz. Tak w ogóle to wątek deklaracji inline był poruszony "kilka blogów" wcześniej - https://4programmers.net/Mikroblogi/View/37057#comment-37063, wywiązała się też tam dyskusja w tym temacie. Napisałem w jej ramach, że totalnie nie czuję tego pomysłu, moim zdaniem psuje on Pascala - czyli dość tradycyjny i sformalizowany język, w którym bardzo cenię sobie jego strukturę, w ramach której wszystko ma swoje miejsce. Odnosząc się do wcześniejszego wpisu, który podlinkowałeś - z większością rzeczy się całkowicie zgadzam, zwłaszcza skok iteratora pętli for czy grupowe przypisywanie wartości moim zdaniem powinny być wprowadzone. Ale deklarowaniu inline zmiennych mówię stanowcze i zdecydowane raczej nie. Ponadto argument, który podałeś we wpisie sprzed dwóch lat, dotyczący alokowania pamięci, jest zupełnie abstrakcyjny - w dobie kilku/kilkunastu albo i kilkudziesięciu GB RAM, te kilka var i:integer; nie robi żadnej różnicy.

furious programming

Nie zapoznawałem się dokładniej z artykułami podanymi w tamtym wpisie, a komentarzy nie czytałem, bo było ich za dużo i nie miałem na to czasu. Dlatego przegapiłem ten z linkiem do dokumentacji. Dokumentacji Delphi też nie czytam, bo i nie mam po co, a na ten wpis na blogu Marco trafiłem przez przypadek, dzięki wskazanemu watkowi na forum Lazarusa.

Tu już nawet nie chodzi o czas kompilacji czy oszczędność pamięci at runtime. Deklarowanie zmiennych w jednym miejscu po dłuższym czasie staje się męczące, bo zmusza do skakania do bloku deklaracji podczas implementowania kodu. Poza tym inline'owanie deklaracji pozwala skrócić kod, w tym przypadku wcale nie obniżając czytelności kodu – wręcz przeciwnie. I nie rozumiem jak można takie rzeczy jak różny zasięg w ten sposób deklarowanych zmiennych uznać za wadę.

furious programming

Pamiętaj też, że nie stworzyłem tego wpisu po to, aby poinformować o nowościach, które zostały podane do publicznej informacji miesiąc temu. Stworzyłem ten wpis głównie po to, aby napisać o niechęci społeczności skupionej wokół Free Pascala i o tym, że najprawdopodobniej FPC nie będzie w tym temacie kompatybilny z Delphi. Co mnie smuci – od dawna wyczekiwałem takiej funkcjonalności i najpewniej będę musiał obejść się smakiem.

cerrato

Tutaj masz rację, że (niezależnie od oceny wprowadzonych zmian) decyzja ekipy FPC zrywa w pewnym zakresie z kompatybilnością z Delphi i to jest smutne. Z drugiej strony, może nie jest to zły krok, bo trochę się odcinając od Delphi, lazarus staje się niezależnym bytem a nie klonem/ubogim krewnym delfina ;)

cerrato

A w temacie deklarowania zmiennych - pisalem o tym tutaj https://4programmers.net/Mikroblogi/View/37057#comment-37066 i nie chcę się powtarzać. Owszem, ograniczony zakres zmiennej jest jakimś plusem, ale bardzo słabym. Jeśli zmienna ma pełnić jakąś funkcje poza byciem zmienna sterującą, to i tak jej zakres powinien wykraczać poza pętle w której została zadeklarowała, a do zastosowań polegających jedynie na kontrolowaniu przebiegu pętli wystarczy jedna czy dwie "recyklingowane" zmienne globalne na cały program.

furious programming

Nie pisałem, że oganiczony zakres inline'owanych zmiennych jest plusem, a o tym, że nie jest twardym minusem. Według mnie jest zaletą, bo daje większą elastyczność.

Z drugiej strony, może nie jest to zły krok, bo trochę się odcinając od Delphi, lazarus staje się niezależnym bytem a nie klonem/ubogim krewnym delfina

Z mojej perspektywy wygląda to tak, że twórcy FPC nie są skłonni do radykalnych zmian i kurczowo trzymają się starego, klasycznego dialektu. To bez sensu, tym bardziej, że owe rozbudowanie składni nie zrywałoby kompatybilności z bieżącą funkcjonalnością i z innymi dialektami (w tym TP i innymi dziadziusiami). Nawet tak dobra propozycja jak fuzja bloków try została odrzucona i zapomniana.

[…] a do zastosowań polegających jedynie na kontrolowaniu przebiegu pętli wystarczy jedna czy dwie "recyklingowane" zmienne globalne na cały program.

Nie no takich rzeczy się nie robi. Owe inline'nowane zmienne pozwoliłyby uniknąć zbędnego deklarowania zmiennych na początku kodu, co znamy z większości innych języków programowania, w tym z tych najpopularniejszych jak C# czy Java. W tej materii Pascal odstaje od innych języków i dziś nie uważam tej odmienności za zaletę.

cerrato

@furious programming: rzeczywiście, przepraszam, czytałem Twój komentarz na szybko na telefonie i coś źle zrozumiałem w temacie zakresu zmiennych. Faktem jest że zakres takich zmiennych zależy od miejsca deklaracji, ale tak naprawdę to nie ma większego znaczenia, bo mówimy o zmiennej, której jedynym celem jest "przelecenie" przez for'a. Zresztą wydaje mi się, że chyba wszystkie opisane w poprzednim poście ulepszenia mają głównie charakter kosmetyczny. Owszem - ułatwiłyby trochę pracę, ale poza tym nie są żadną rewolucją. Nie ma rzeczy, których obecnie nie da się zrobić, a po wprowadzeniu opisanych zmian by się dało. Zamiast jednego bloku try except można (tak, jak sam pisałeś) połączyć dwa i masz to samo. Owszem - nie można przypisać zm1:=zm2:=zm3:=34;, ale możesz zrobić 3 przypisania i wyjdzie na to samo. W razie zmiany przypisanej wartości, żeby nie poprawiać jej 3 razy, można napisać zm1:=34; zm2:=zm1; zm3:=zm1 i właściwie mamy ten sam efekt. Tak samo pętla for - można zrobić step 10 ale można to obejść przez while/repeat albo chociażby w ciele pętli for przemnażać zmienną sterującą przez współczynnik step. Jest z tym trochę kombinowania, ale w mojej ocenie żadna z opisanych zmian nie wprowadza możliwości napisania czegoś, czego obecnie by się nie dało ani nie stwarza "nowej jakości". A biorąc pod uwagę ograniczone moce przerobowe zespołu FPC/Lazarus, nie wiem czy nie lepiej jest poświęcić ich czas na bardziej przydatne tematy. Niedawno na forum była (kolejna) dyskusja z cyklu "delphi śmierdzi i tylko geje tego używają". I padł tam argument o braku wsparcia FPC dla nowoczesnych technologii typu CUDA (było tam więcej rzeczy, ale nie pamiętam i nie chce mi się tego wątku szukać).

furious programming

Zresztą wydaje mi się, że chyba wszystkie opisane w poprzednim poście ulepszenia mają głównie charakter kosmetyczny.

Nie tylko kosmetyczny. Zwróć uwagę na to, że deklaracja wszystkich zmiennych lokalnych przed blokiem kodu powoduje alokację dla nich pamięci bez względu na przepływ sterowania. Dla wszystkich, nawet tych, które w kodzie nie zostaną w ogóle użyte (bo np. wstępny warunek nie został spełniony więc Exit). Traci się więc trochę czasu oraz niepotrzebnie alokuje pamięć. A nie każda funkcja używa wyłącznie zmiennych liczbowych czy logicznych – często deklaruje się statyczne macierze czy struktury, co wymaga więcej pamięci. Tak więc nie jest to kosmetyka.

Druga sprawa to określenie skoku pętli for. Dziś nie da się tego zrobić dla tej pętli – można inkrementować lub dekrementować iterator tylko o 1. W takim przypadku pętla for staje się bezużyteczna i trzeba ją wymienić na while lub repeat, co niepotrzebnie wydłuża kod. Poza tym wymaga ręcznej inkrementacji/dekrementacji iteratora, o czym nie można zapomnieć.

Pozostałe propozycje dotyczą skrócenia składni, która jest dość rozwklekła w Pascalu i co też wielu uznaje za wadę języka. Tak np. jak połączenie bloków try – dzięki temu skróci się ich zapis o dwie linijki, zlikwiduje się dodatkowe wcięcie o jeden poziom oraz ułatwi czytanie takiego bloku. Jedna mała zmiana, a trzy ewidentne plusy.

Jeszcze więcej można zyskać pozwalając na grupowe przypisywanie wartości wielu zmiennym, co powinno również iść w parze z inline'nowanymi deklaracjami zmiennych. To też pozwoliłoby skrócić kod. Im mniej linijek kodu, tym mniej czasu potrzeba na jego analizę, a to przekłada się również na niższe koszty jego utrzymania.


Owszem - ułatwiłyby trochę pracę, ale poza tym nie są żadną rewolucją.

Pamiętaj, że rozwój oprogramowania składa się z 99% zmian kosmetycznych i z 1% zmian rewolucyjnych. To właśnie drobne poprawki i usprawnienia nadają kształt całości. Częste znaczące zmiany utrudniłyby użytkownikowi pracę i zniechęcały do używania. Z biznesowego punktu widzenia to nie jest dobry pomysł.

Tak samo pętla for - można zrobić step 10 ale można to obejść przez while/repeat albo chociażby w ciele pętli for przemnażać zmienną sterującą przez współczynnik step.

Iterator pętli for jest nietykalny – nie można jawnie zmodyfikować jego wartości wewnątrz pętli. Jedyną możliwością manipulacji jest pobranie adresu iteratora i zmodyfikowanie jego wartości poprzez dodatkowy wskaźnik, zobacz – https://ideone.com/rt7MXu. A największym tego minusem jest problem z kontrolą liczby iteracji i wartości iteratora. Taką pętlę:

for I := 1 to 10 do

należałoby przetłumaczyć na C w poniższy sposób:

for(i = 1; i <= 10; i++)

Przy czym jeśli używać wskaźnika-manipulatora, to modyfikować iterator koniecznie na końcu bloku kodu pętli, aby nie wyjść poza zakres. W przeciwnym razie dostaniemy błędne wartości, nawet spoza oczekiwanego zakresu – https://ideone.com/F6hBSO. Za dużo tu kombinacji i ręcznych obliczeń, takie coś się po prostu nie opłaca, więc już lepiej skorzystać z pętli while lub repeat. Cały ten ambaras likwiduje rozwinięcie nagłówka o step n.

karpov

Ogólnie nie jestem zwolennikiem deklaracji zmiennych gdzie się ma ochotę ale zrobienie wyjątku np dla pętli for byłoby świetnym rozwiązaniem for var i := 1 to 10 do writeln(i);

furious programming

Koniecznie z wykorzystaniem inferencji i koniecznie dla obu typów pętli – for to/downto do i for in.

for var Item in Collection do // miodzio

Już nawet tym bym się od biedy zadowolił…