furious programming
2017-10-12 01:21

Co jakiś czas ktoś – celowo lub przy okazji – pyta się na forum, czy referencja w Pascalu to wskaźnik, czy nie wskaźnik. Uściślijmy więc.

Tak, referencja instancji klasy to wskaźnik, co prawda traktowany jest w odmienny sposób, jednak to nie zmienia faktu bycia wskaźnikiem. Aby sprawdzić to w praktyce, wystarczy referencję zrzutować na pointer, a ten następnie z powrotem na referencję konkretnej klasy.

Przykład testowej aplikacji poniżej:

uses
  Classes;
var
  ListObj: TStringList;
  ListPtr: Pointer;
begin
  ListObj := TStringList.Create();
  try
    ListObj.Add('free pascal');
 
    ListPtr := Pointer(ListObj);      // przerobienie referencji na wskaźnik
    ListObj := TStringList(ListPtr);  // przerobienie wskaźnika na referencję
 
    Write(ListObj.Text);
  finally
    ListObj.Free();
  end;
end.

Dwa rzutowania i wszystko jasne. Miszung ze wskazaniami nie sprawi, że w linijce z wyświetleniem zawartości listy dostaniemy wyjątek.

Gdzieniegdzie, raczej w starych kodach pisanych np. w Delphi 7, można spotkać konwersję referencji na zwykłą liczbę, w celu jej przesłania w parametrze razem z komunikatem.

Druga sprawa – czasem ktoś wpada na pomysł, aby wykorzystać zwykłą procedurę jako zdarzenie jakiegoś obiektu. I też pojawiają się różne zdania na temat tego, czy da się, czy jednak się nie da. Otóż, bezpośrednio nie da się – zmienna zdarzeniowa nie jest pointerem, więc nie można do niej przypisać adresu zwykłej procedury. A czym jest? Nie jest to jeden wskaźnik, a dwa – jeden przechowuje adres kodu do wykonania, a drugi wskazuje na dodatkowe dane.

Aby móc użyć zwykłej procedury jako zdarzenia, należy przypisać adres tej procedury do pierwszego wskaźnika. A co z drugim, tym na dane? Cóż, można w nim przesłać adres czegokolwiek – wyślijmy więc referencję obiektu, aby dopełnić pierwszą część tego wpisu. ;)

Prosty przykład:

uses
  Classes;
 
  procedure OnListChange(ASender: TObject);  // zwykła procedura, zgodna z TNotifyEvent
  var
    List: TStringList absolute ASender;
  begin
    Write(List.Text);
  end;
 
var
  List: TStringList;
  Method: TMethod;  // TMethod reprezentuje wymaganą strukturę wskaźników
begin
  List := TStringList.Create();
  try
    Method.Code := @OnListChange;  // przypisanie adresu zwykłej procedury
    Method.Data := List;           // przypisanie referencji (ta podana zostanie w parametrze ASender)
 
    List.OnChange := TNotifyEvent(Method);  // ustawienie przygotowanego zdarzenia (rzutowanie konieczne)
    List.Add('free pascal');
  finally
    List.Free();
  end;
end.

Po wywołaniu metody Add, wartość jej parametru zostanie dodana do listy, po czym instancja odpali zdarzenie OnChange, o ile zostało ustawione. My to zrobiliśmy, więc zostanie wykonana procedurka OnListChange – na ekranie konsoli pojawi się zawartość listy, czyli w tym przypadku napis free pascal.

#free-pascal #lazarus #delphi

Azarien

Referencja to referencja. To czy referencja jest samym tylko wskaźnikiem, czy jakimś opakowanym, czy czymś więcej - to szczegół implementacyjny.

furious programming

Owszem, jednak aby wiedzieć z czym ma się do czynienia i co niestandardowego można z referencjami zrobić, warto zagłębić się w temat i podłubać. W razie kolejnego ciekawskiego, będę mógł podlinkować ten wpis, zamiast znów tłumaczyć to samo. :P

furious programming
2015-09-04 14:45

Wczoraj napisałem i opublikowalem w tym sersie artykuł o specyficznej liście dwukierunkowej; Opisuje on sposób implementacji dwukierunkowej listy, korzystającej ze znacznika, czyli wskaźnika pamiętającego ostatnio użyty węzeł listy. Dzięki temu znacznikowi, przeszukiwanie listy jest znacznie szybsze niż jej tradycyjnego odpowiednika;

Artykuł znajduje się pod poniższym adresem:

Jest do druga część cyklu artykułów dotyczących implementacji list wskaźnikowych w języku Free Pascal; Pierwsza część opisywała sposób implementacji listy jednokierunkowej i wyszła spod ręki @babubabu; Artykuł ten znajduje się pod poniższym linkiem:

Mam nadzieję, że artykuł przyda się i ktoś skorzysta z proponowanych implementacji; W każdym razie życzę miłej lektury, a w razie pytań proszę o kontakt, ewentualnie wątki w dziale Newbie lub Delphi i Pascal.

#fpc #lazarus #delphi

furious programming
2015-03-07 00:23

Przed chwilą popełniłem taką linijkę:

tknToken := ATokens[intToken] as TToken;

i może sprawiać wrażenie pokręconej - wszędzie to słowo Token; Jednak wszystkie cztery użyte identyfikatory wskazują na zupełnie inne typy:

  • tknToken - lokalny obiekt klasy TToken (użyta notacja węgierska),
  • ATokens - argument metody jako obiekt klasy TObjectList,
  • intToken - lokalny iterator pętli typu Int32 (także użyta notacja węgierska),
  • TToken - klasa pojedynczego tokenu;

To chyba najlepszy przykład jaki kiedykolwiek "odkryłem", który pokazuje jak przydatne jest stosowanie się do standardów nazewnictwa oraz używanie notacji węgierskiej :)

#pascal #fpc #lazarus #delphi

furious programming

@vpiotr: Nazywaj to jak chcesz - dla mnie jest o wiele bardziej czytelna taka postać, niż jakakolwiek inna ;P

Jednak to nie jest "Smurf Naming", bo notacja węgierska to wyklucza; Poza tym wszystkie identyfikatory dotyczą pojedynczego tokenu lub listy tokenów, więc nie muszę ich nazywać TokenLoop, TokensList, TokenLocal i TTokenClass - każdy to Token, a ich unikalność zapewniają konwencje nazewnictwa.

vpiotr

tknToken := ATokens[intToken] as TToken;

@furious programming: w tym wypadku napisałbym token := ATokens[idx] as TToken;

furious programming
2014-10-09 18:12

Ukończyłem właśnie prace nad komponentem TFuriousLabel, czyli przeznaczonym dla środowisk Delphi projektem etykiety, której zawartość można formatować znacznikami HTML; Może także posiadać klikalne linki, co jest niestandardową funkcją etykiet zawartych w VCL;

Zainteresowanych zapraszam do dedykowanego wątku: http://4programmers.net/Forum/Off-Topic/Oceny_irecenzje/239916-tfuriouslabel-_etykieta_formatowana_znacznikami_html

#delphi #delphi7 #furious-controls #tfuriouslabel

furious programming
2014-06-30 20:57

Wczoraj miałem dość dużo wolnego czasu, więc postanowiłem nieco rozwinąć projekt mojej konsolowej gry SnakeASCII, który rozwijam w ramach rozrywki i odpoczynku od pisania specyfikacji formatu TreeStructInfo;

Udało się wprowadzić wiele sensownych zmian, m.in.:

  • podział kodu na więcej modułów,
  • zaprogramowanie automatycznego ruchu węża, uniezależnionego od wcislanych klawiszy,
  • możliwość przechodzenia przez moduły, w których znajdowało się "złotko",
  • bardziej zaawansowane rysowanie ciała węża (obsługa większej ilości przypadków oraz większego zbioru znaków specjalnych),
  • wprowadzenie schematów kolorów węża, ustalanych w pliku danej planszy,
  • rozbudowane sterowanie wężem - wprowadzenie trybu turbo, zmiana klawiszy sterowania oraz dodanie możliwości zapauzowania gry w dowolnym momencie,
  • zwiększenie palety kolorów dla barierek planszy oraz kępek trawy,
  • inne, mniej ważne funkcje;

Teraz przynajmniej można sobie pograć, bo wąż sam chodzi; Plansze można modyfikować, odpowiednio zmieniając zawartość plików (póki co jest jeden - 0.lvl), znajdujących się w lokalnym katalogu levels;

Gra będzie ciągle rozwijana, w każdej wolnej chwili, tak że można się spodziewać jeszcze wielu nowych rzeczy; Opis wprowadzonych zmian w stosunku do poprzedniej wersji, zawarty jest w dedykowanym wątku SnakeASCII, czyli kultowy "wąż" w specyficznej tekstowej formie; Kod gry jest otwarty, udostępniany na licencji GNU Lesser GPL 3, więc można go wykorzystywać jak kto potrzebuje.

Przykładowy zrzut zapauzowanej gry poniżej.

#SnakeASCII #Pascal #FPC #Lazarus #Delphi

masterO

@furious programming: wlasnie myslalem ze to w srodku to waz bo ten z prawej jest przeciety a waz nie moze się przecinać i mnie zmyliło. Odpalić nie moge bo nie mam windy od dobrych 7 lat :)

furious programming

@masterO: Spróbuj - na uniksach też powinno działać, ewentualnie zamiast poprawnych znaków wyświetlą się kszaki;