Article View: pl.comp.objects
Article #15727Re: Wartości i obiekty
From: Sektor van Skijlen
Date: Sun, 11 Mar 2007 15:29
Date: Sun, 11 Mar 2007 15:29
191 lines
10985 bytes
10985 bytes
Dnia Sun, 11 Mar 2007 00:11:42 +0100, Marcin 'Qrczak' Kowalczyk skrobie: > Dnia 10-03-2007, sob o godzinie 18:47 +0000, Sektor van Skijlen > napisał(a): > > > Jest jeszcze trzecia kategoria leżąca pomiędzy tymi dwiema: > > > wskaźniki na singletony, czyli na jedyne obiekty danego rodzaju, > > > np. true / false / nil. Te obiekty są niezmienialne, ale tożsamość > > > tych obiektów jest dobrze zdefiniowana; rozróżnianie ich po tożsamości > > > jest równoważne rozróżnianiu po cechach wewnętrznych. > > > > Nie tworzyłbym specjalnej kategorii dla tych obiektów. > Zwykle można je traktować razem z wartościowymi. Różnica objawia > się tylko wtedy, kiedy w języku mamy do dyspozycji operację jawnie > porównującą dwa obiekty po tożsamości. Tę operację można uznać za > niskopoziomową i rzadko się jej wprost używa, ale w wielu językach > jest dostępna, bo może być tańsza od domyślnego porównania, a dla > pewnego zbioru obiektów jest mu równoważna (Lisp: EQ, Scheme: eq?, > Python: is, Kogut: Is, OCaml: ==). Na przykład w Pythonie porównanie > "x is None" jest praktyczne, a "x is 5" nie jest. Qrczak - to wszystko prawda, ale to wciąż nie zmienia faktu: Obojętnie, jak mamy zaimplementowany sposób porównania wartości i tożsamości, obojętnie też, czy typ jest wartościowy, czy obiektowy, dla każdego typu istnieje tylko i wyłącznie jeden sensowny sposób porównania. Skoro tak, to nie potrzebujemy osobnych operatorów porównania - powinien być dostępny jeden operator porównania. > > > Jeśli spróbować dopasować do tego modelu C++, to się okaże, że zmienną > > > C++ zawierającą obiekt można rozumieć na dwa sposoby: > > > > > a) Jako zmienialny obiekt, przywiązany na stałe do swojej nazwy. > > > To tłumaczenie jest odpowiednie w przypadku obiektów z tożsamością, > > > zwłaszcza złożonych, bo pozwala wymodelować możliwość zmiany > > > indywidualnych pól obiektu z zachowaniem tożsamości całego obiektu. > > > Takie obiekty są zwykle przekazywane przez referencje C++ albo > > > wskaźniki C++, co odpowiada przekazaniu wskaźnika na obiekt > > > w modelu, a więc odpowiada naturalnemu sposobowi przekazania > > > wartości w modelu. > > > > > b) Jako zmienną zawierającą wartość, która sama jest niezmienialna. > > > To tłumaczenie jest lepsze dla atomowych typów wartościowych, > > > bo pozwala wymodelować wartość wyabstrahowaną od miejsca > > > przechowywania. Takie obiekty są w C++ zwykle kopiowane, > > > co odpowiada przekazaniu odczytanej bieżącej wartości zmiennej > > > w modelu, czyli znowu jest naturalnym sposobem przekazania wartości, > > > mimo że w C++ jest inne niż tamto. > > > > Szczerze mówiąc to nic z tego nie rozumiem. > Bo opisałem odpowiedniki zmiennej w C++ językiem (ludzkim) > przystosowanym do opisywania innych języków (programowania). > Jesteś przyzwyczajony do języka (ludzkiego) przystosowanego > do opisywania C++. Nie do końca się zgodzę, w szczególności nie zgodzę się, że opisałeś to językiem ludzkim :) > Jeśli w C++ mamy zmienną zawierającą obiekt udostępniający jakieś metody > (w tym metody zmieniające jego stan), to w innym języku odpowiednik tej > konstrukcji wygląda z reguły na jeden z dwóch sposobów, zależnie od > stylu, w jakim przeważnie wygodnie jest używać obiektów danego typu: > a) Typowy przykład: tablica. > Zmienna wskazuje na obiekt udostępniający analogiczne operacje jak > w C++. Obiekt jest tworzony na stercie. Do tej zmiennej nie jest > nigdy przypisywany wskaźnik na inny obiekt. Ale mówisz o tablicy surowej, tworzonej jako zmienna lokalna w funkcji. Pomówmy raczej o vectorze. > Tam, gdzie w C++ obiekt jest przekazywany przez referencję, w innym > języku przekazywana jest wartość tej zmiennej (wskazująca na ten > obiekt). Tam, gdzie w C++ obiekt jest przekazywany przez wartość, > w innym języku obiekt jest klonowany (czymś w rodzaju metody Clone). Tak - pod warunkiem, że pozwala się na klonowanie obiektów. > b) Typowy przykład: liczba. > Zmienna wskazuje na niezmienialny obiekt innego języka reprezentujący > bieżący stan obiektu C++. Metodom C++, które zmieniały stan obiektu, > odpowiadają operacje zwracające nowy obiekt, który jest przypisywany > z powrotem tej zmiennej. Pod warunkiem, że mamy możliwość "zakodowania" przypisania do zmiennej trzymającej ten niezmienialny obiekt. Tak zresztą jest to w Javie i Javowe rozwiązanie ma tylko jedną wadę: operator porównania :). > Tam, gdzie w C++ obiekt jest przekazywany przez wartość, w innym > języku przekazywana jest bieżąca wartość zmiennej. Tam, gdzie > w C++ obiekt jest przekazywany przez referencję, w innym języku > przekazywana jest referencja na zmienną. A co z porównywaniem? > > String zawsze powinien być traktowany jak wartość, natomiast wektor zawsze > > jak obiekt. > Zgodzę się, że zazwyczaj. Nie zgadzam się, że zawsze. Zgodzę się co najwyżej, że nie zawsze, tzn. wektor może służyć jako szczegół implementacyjny jakiegoś typu wartościowego. Ale nie sam wektor, bo to jest mniej więcej coś takiego jak void* do przechowywania dynamicznych danych. > A wektor znaków? Z jednej strony to jest wektor. Z drugiej strony to > jest w zasadzie to samo, co string. Różnica polega na tym, czym się różni "to samo" od "w zasadzie to samo" ;) Nie, Qrczak. String to nie jest tablica znaków - jak już się czepiamy skrzywionego myślenia, to i ja się poczepiam: twoje myślenie jest skrzywione przez języki, w których string jest reprezentowany przez listę znaków (jak np. Haskell). String charakteryzuje się tym, że posiada wartość; napis jest po prostu jednym napisem, który może być taki sam jak inny lub różny od niego, napisy możemy też porządkować po wartości (bo mają wartość), "ten sam napis" oznacza nam napis składający się z dokładnie takich samych znaków w tej samej kolejności. Vector natomiast jest zbiorem elementów - ich kolejność nie jest często specjalnie istotna (jeśli już, to najwyżej kwestie uporządkowany-nieuporządkowany), elementy często przestawia się w inne miejsce, wykonuje się często operacje na każdym elemencie po kolei. W przypadku stringa te operacje są w mniejszości, a sortowanie znaków w stringu uważałbym za powiew ezoteryki. To nie jest kwestia implementacji (string, vector), tylko kwestia logiki programu. Jasne, możemy sobie obsługiwać napisy jako vector<char>, ale to będą dla nas i tak napisy (język C przecież i tak obsługuje napisy jako tablice znaków). Implementacja jest więc nieistotna - ważne jest to, co to dla nas oznacza w programie. Dlatego dobre języki programowania pozwalają na stworzenie osobnych typów, które mają nawet wspólne podstawy implementacyjne, ale które logicznie oznaczają zupełnie co innego. Właśnie dlatego, że to narzuca nam sposób operowania takim typem. Można tablicę char'ów używać jako zbiór znaków i jako napis, oczywiście. Ale wtedy trzeba samemu pamiętać o tym, co jest czym i jak co mamy traktować. Jeśli język jest słaby i nie potrafi dać możliwości rozróżnienia tych rzeczy po statycznym typie (jak w C), to musi jakoś zapewnić możliwość alternatywnych sposobów porównań za pomocą osobnych operacji. > Różnice są w dodatkowych metodach, > ale one są raczej poboczne, nie wpływają na istotę rzeczy. Dobrze, Qrczak, niech ci już będzie, bo w tym momencie ręce mi opadły. > > > Pisałem tutaj o zmienialnym stringu, zakładając, że to jest jedyny > > > string w danym języku. Czyli kiedy złożony typ pełniący rolę typu > > > wartościowego jest jednak zmienialny. Taka sytuacja jest kłopotliwa. > > > > Oj... nie bardzo to widzę. > No i właśnie mówię, że to jest kłopotliwe. Lepiej tego unikać. > W to C++ pasuje. Tak, ale w C++ zmiana stringa zmienia tylko tą zmienną, która aktualnie przechowuje wartość. Inaczej mówiąc, nadaje nową wartość zmiennej. Można też odnieść się częściowo do tego, że niektóre implementacje stringa współdzielą tablicę znaków. Więc dwie różne zmienne mogłyby wskazywać na różne tablice, co bardzo przypominałoby wskazywanie na dwa obiekty przez dwie zmienne referencyjne. Ale w takim przypadku przydałoby się też jakieś sprytne COW, które by powodowało, że w razie zmiany przez jedną z tych zmiennych, każda z nich będzie miała od teraz własną kopię. Inaczej mówiąc, nawet jeśli jakaś zmienna współdzieli obiekt tablicy z innymi zmiennymi, to modyfikacja tej zmiennej nie zmienia wartości w pozostałych zmiennych (a jedynie traci z nimi powiązanie). > Przykłady języków, które mają wyłącznie zmienialne stringi mimo > paradygmatu, który do tego nie pasuje: Lisp, Scheme, OCaml, Ruby > (czasem są zmienialne łącznie ze zmianą długości, a czasem nie). Tzn. jak? Musisz jawnie skopiować string, jeśli chcesz, żeby źródłowy się nie zmienił? -- // _ ___ Michal "Sektor" Malecki <sektor(whirl)kis.p.lodz.pl> \\ L_ |/ `| /^\ ,() <ethouris(O)gmail.com> // \_ |\ \/ \_/ /\ C++ bez cholesterolu: http://www.intercon.pl/~sektor/cbx "Java is answer for a question that has never been stated"
Technical Details
Message-ID:
<et178b$f2o$1@kujawiak.man.lodz.pl>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!newsfeed.pionier.net.pl!news.man.lodz.pl!not-for-mailReferences:
<pl-comp-objects-faq-1-1166202604@ict.pwr.wroc.pl> <1172940339.25227.28.camel@qrnik> <escc9e$2h2$1@kujawiak.man.lodz.pl> <esd1k1$9bp$1@bandai.magma-net.pl> <esemb6$2r3$1@kujawiak.man.lodz.pl> <eses6u$8fm$1@inews.gazeta.pl> <esf3am$r52$1@bandai.magma-net.pl> <esfg25$b2m$1@kujawiak.man.lodz.pl> <1173137761.17765.52.camel@qrnik> <esmtmk$ii1$1@kujawiak.man.lodz.pl> <1173310324.15622.77.camel@qrnik> <esuufm$jfv$1@kujawiak.man.lodz.pl> <1173568302.9234.25.camel@qrnik>Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!newsfeed.pionier.net.pl!news.man.lodz.pl!not-for-mail
From: Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
Newsgroups: pl.comp.objects
Subject: Re: Wartości i obiekty
Date: Sun, 11 Mar 2007 15:29:15 +0000 (UTC)
Organization: LODMAN - Metropolitan Area Network in LODZ, Poland
Lines: 191
Sender: Michal Malecki <sektor@zly.kis.p.lodz.pl>
Message-ID: <et178b$f2o$1@kujawiak.man.lodz.pl>
References: <pl-comp-objects-faq-1-1166202604@ict.pwr.wroc.pl> <1172940339.25227.28.camel@qrnik> <escc9e$2h2$1@kujawiak.man.lodz.pl> <esd1k1$9bp$1@bandai.magma-net.pl> <esemb6$2r3$1@kujawiak.man.lodz.pl> <eses6u$8fm$1@inews.gazeta.pl> <esf3am$r52$1@bandai.magma-net.pl> <esfg25$b2m$1@kujawiak.man.lodz.pl> <1173137761.17765.52.camel@qrnik> <esmtmk$ii1$1@kujawiak.man.lodz.pl> <1173310324.15622.77.camel@qrnik> <esuufm$jfv$1@kujawiak.man.lodz.pl> <1173568302.9234.25.camel@qrnik>
NNTP-Posting-Host: zly.kis.p.lodz.pl
Mime-Version: 1.0
X-Trace: kujawiak.man.lodz.pl 1173626955 15448 212.191.89.2 (11 Mar 2007 15:29:15 GMT)
X-Complaints-To: abuse@man.lodz.pl
NNTP-Posting-Date: Sun, 11 Mar 2007 15:29:15 +0000 (UTC)
User-Agent: tin/1.6.2-20030910 ("Pabbay") (UNIX) (SunOS/5.9 (sun4u))
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit