Article View: pl.comp.objects
Article #15758Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
From: Radoslaw Jocz
Date: Tue, 01 Apr 2008 18:39
Date: Tue, 01 Apr 2008 18:39
326 lines
16755 bytes
16755 bytes
Sektor van Skijlen wrote:
> Jasna dupa!
>
> Prawie rok upłynął od tej korespondencji, a tu nagle odpowiedź! Dosłownie
> jakbym znalazł paczkę cukierków miętowych za szafą podczas przedświątecznego
> sprzątania :)
>
> Ale ok - mogę to pociągnąć :)
>
> Dnia Wed, 16 Jan 2008 01:45:20 +0100, SasQ skrobie:
>> Dnia Sun, 18 Mar 2007 23:11:57 +0000, Sektor van Skijlen napisał(a):
>
>>>>> Typ wartościowy jest typem, którego obiekt jest identyfikowany
>>>>> zawsze przez wartość. Więc jeśli portfel z tą samą ilością
>>>>> pieniędzy nie jest tym samym portfelem, to portfel nie jest
>>>>> typem wartościowym.
>>>> Hmm... ale chyba jest dobrym przykładem, że czasami chcemy go
>>>> potraktować jako typ wartościowy, a czasami jako niewartościowy:
>>>> if (portfel1==portfel2) //Czy mają tyle samo pieniędzy?
>>>> if (portfel1 IS portfel2) //Czy to ten sam portfel, czy inny?
>>> Nie.
>>>
>>> if ( portfel1->ilosc_pieniedzy()
>>> == portfel2->ilosc_pieniedzy() ) // czy mają tyle samo
>>> // pieniędzy
>>>
>>> Nie porównujesz "dwóch portfeli", tylko porównujesz stan dwóch
>>> portfeli
>
>> Aaa no to już chyba zaczynam qmać, co masz na myśli :)
>> Jeśli mamy sobie takie coś:
>
>> int x = 2;
>> int y = 2;
>
>> i teraz porównujemy je tak:
>
>> if (x == y) ...
>
>> to obchodzi nas wyłącznie fakt, że wartości obiektów są takie same.
>
> Znów nie do końca zrozumiałeś. Przy takim podejściu to się możemy bujać z tym
> w nieskończoność.
>
> Oczywiście, to co napisałeś powyżej, jest prawdą, jak najbardziej, ale po
> prostu zaczynasz iść z rozumowaniem wciąż w przepaść, tylko po przeciwnej
> stronie.
>
>> Nie obchodzi nas, że są to dwa różne obiekty przechowujące tą samą
>> wartość. Równość wartości traktujemy jako równość obiektów, a
>> wartość utożsamiamy z samym obiektem. O to chodzi? :>
>
> Nie. Nie ma czegoś takiego, jak "równość obiektów".
>
> Jeśli przyjmiemy określenie, że obiekt może być obiektem wartościowym, to
> wtedy stwierdzenie "a jest b" określa nam, że a i b posiadają te same
> wartości. Tylko dlatego, że istnieje pojęcie wartości dla takich obiektów. I
> dlatego właśnie utożsamiamy dane "a" z wartością, jaką obiekt referowany przez
> "a" ("referować" można również przez samą nazwę, tak to nazwijmy) ma aktualnie
> zapisaną w swojej wewnętrznej reprezentacji. Równie dobrze jednak "a" może
> referować do stałej i wtedy symbolicznie utożsamia się to z samą wartością.
> Nadal jednak "a jest b" będzie wyrażać to samo.
>
> Cechą obiektów wartościowych jest identyfikacja po wartości, to znaczy, reguły
> opisujące cokolwiek z użyciem a będą zawsze identyczne, gdy a zastąpisz b, pod
> warunkiem, że a == b.
>
>> Kolor jest typem wartościowym, bo jeśli mamy:
>
>> Kolor pierwszy = czerwony;
>> Kolor drugi = czerwony;
>
>> i porównamy je:
>
>> if (pierwszy == drugi) ...
>
>> to dla nas będzie to "ten sam kolor" [mimo że leży w różnych
>> miejscach].
>
> Zgadza się - a jeśli użyjesz gdzieś koloru pierwszy, to równie dobrze możesz
> użyć koloru drugi i efekt będzie zawsze ten sam.
>
>> Przy takim postawieniu sprawy rzeczywiście portfel nie jest
>> typem wartościowym, bo gdy zrobimy tak:
>
>> Portfel moj = 500; //w moim portfelu śpi 500 zł
>> Portfel twoj = 500; //w twoim portfelu śpi 500 zł
>
>> to kiedy je porównujemy, domyślne rozumienie tego porównania
>> jest inne:
>
>> if (moj == twoj) ...
>
>> bo tym razem wygląda to jak sprawdzenie, czy to są dwa różne
>> portfele, czy może ten sam, i nie obchodzi nas co jest w środku i
>> że oboje mamy tyle samo pieniędzy w swoich portfelach.
>> Tutaj zawartość portfela nie jest utożsamiana z nim samym.
>> Jeśli byśmy chcieli porównywać zawartość portfeli, to musimy
>> to jasno powiedzieć:
>
>> if (moj.zawartosc == twoj.zawartosc) ...
>
> No właśnie.
>
> Wszystko ma mocny związek z tym, co dla ciebie oznacza stwierdzenie "a jest
> b".
>
>>> (pomijając już bezsens porównywania dwóch stanów z dwóch
>>> różnych obiektów, ale to tak na marginesie).
>
>> A tego to nie skumałem :|
>
> Nie no jakieś tam zastosowania do tego można by znaleźć - np. jeśli jeden z
> obiektów "osiągnął" jakąś-tam wartość stanu, którą osiągnął również inny
> obiekt, to coś tam szczególnego można zrobić... po prostu rzadko tego typu
> porównania mają jakikolwiek sens. Zwykle porównuje się to z jakąś stałą, aby
> stwierdzić jakieś warunki nt. tego stanu. Np. jaki ma sens porównanie
> zawartości jednego i drugiego portfela? Można co najwyżej sprawdzić, czy jest
> w nim "wystarczająco pieniędzy" na jakąś transakcję, ewentualnie można na tych
> wartościach wykonywać jakieś operacje, np. zsumować zawartość dwóch portfeli.
> Ale stwierdzanie, czy w jednym portfelu jest tyle samo pieniędzy, co w drugim,
> ma akurat mało sensu.
>
>>> if ( portfel1 == portfel2 ) // czy to ten sam portfel
>
>> No spox, teraz wchodzi do garka ;)
>
>>> Ja wiem, że jak komuś odbija kolba i musi sobie nawymyślać
>>> wypasione definicje operatorów (w tym ==), to nic się na to
>>> nie poradzi, ale to bynajmniej nie powoduje, że portfel
>>> nagle staje się typem wartościowym.
>
>> Hmm... czyli sugerujesz, że w przypadku portfela robienie
>> z niego typu wartościowego jest jakimś kaskaderstwem i
>> lepiej użyć semantyki, w której jego zawartość jest osobnym
>> obiektem składowym?
>
> Tak, dokładnie tak. Niekoniecznie zresztą jako obiekt składowy, zwykle robi
> się do tego odpowiednie metody, które tą wartością operują. Ale ilość
> pieniędzy jest akurat tylko jednym z istniejących stanów portfela.
>
>>> Powtarzam: typ jest wartościowy wtedy (i tylko wtedy), gdy
>>> tożsamość poznajemy po jego wartości.
>
>> No czyli chyba każdy typ podstawowy taki jest.
>
> Niekoniecznie jest to prawda we wszystkich językach, ale w wielu tak.
>
>> Hmm... a jak to jest z referencjami i wskaźnikami?
>
> To też wartości. Jeśli chodzi o referencję w C++ to jest to zrobione trochę
> bardziej jak trik językowy, konkretnie nie ma żadnego dostępu do wartości w
> przypadku referncji.
>
> Wskaźnik jest wartością. To, na co wskaźnik wskazuje, może być obiektem (lub
> funkcją).
>
>> Albo tablice znakowe - ostatnio na pl.comp.lang.c był taki
>> przypadek, że koleś porównywał wskaźniki do takiego samego
>> [ale nie tego samego] ciągu znaków. Coś w stylu:
>
>> char* str1 = "test";
>> ...
>> if (str1 == "test") ...
>
>> i się dziwił, czemu ten warunek mu się nie spełnia, skoro
>> "stringi są te same" ;J Może to jest pole dla twojej
>> teorii? :> Bo tutaj ewidentnie ktoś miał na myśli porównanie
>> wartości, a wyszło mu porównanie tożsamości i to go
>> wpuściło w maliny.
>
> Ale to nie jest kwestia tego, że == porównuje wartości i co z nimi.
>
> To, co w tym porównaniu zostało porównane to wskaźniki na tablice znakowe
> służące do przechowania wartości stringów, a nie "wartości stringów".
>
> char* to nie jest "string". String to może być np. std::string.
>
>>> Jeśli więc ilość pieniędzy w portfelu nie stanowi o tym,
>>> że to ten sam portfel, to nie jest to typ wartościowy.
>
>> Czyli to jest wybór arbitralny, czy jednak podyktowany
>> jakimiś właściwościami?
>
> Czy jesteś w stanie stwierdzić, że istnieje coś takiego jak "wartość" w
> przypadku portfela? Czyli coś takiego, co potrafi portfel jednoznacznie
> określić.
>
>>>> No cóż, ale C++ już taki dziwny jest, że nie ma "gołych"
>>>> wartości [a przynajmniej nic mi o tym nie wiadomo], tylko
>>>> wszystko jest trzymane w jakichś obiektach ;)
>>> A takie coś jak np. 119 to jest gdzie trzymane twoim zdaniem?
>
>> To się zdecyduj. Niedawno jak pytałem czy stałe dosłowne są
>> obiektami stałymi, czy jedynie wartościami "nie opakowanymi" w
>> żadnym obiekcie, to mi odpowiedziałeś:
>> "Są obiektami stałymi. Świadczy o tym fakt, że można nimi
>> inicjalizować stałe referencje."
>> A teraz mi tu siejesz trwogę, że są "gołymi" wartościami
>> nie trzymanymi nigdzie? :P
>
> Same wartości, owszem, nie są trzymane nigdzie. Mogą być w określonych
> warunkach stałymi obiektami, ale stałe obiekty typów wartościowych można
> utożsamiać z samymi wartościami.
>
>> Jakby tego było mało, to mi jeszcze później napisałeś, że
>> "Wszelkie inne stałe dosłowne nie leżą nigdzie w pamięci"
>> No to nie rozumiem: obiekty których nigdzie nie ma? :P
>
> Powiedzmy to w ten sposób: istnieje stały obiekt, jeśli posiada jakąś nadaną
> nazwę w systemie nazw, lokalizację, gdzie mogą się znajdować (bo mogą się
> znajdować np. wewnątrz innego, niekoniecznie stałego obiektu). Samo 119 jest
> tylko symbolicznym określeniem wartości, co nie znaczy, że nie można
> "sztucznie" z tego zrobić obiektu stałego, przypisując do stałej referencji.
>
>>> Najprościej to jest mniej więcej wytłumaczyć tak:
>>>
>>> Typ wartościowy jest identyfikowany przez wartość. To oznacza,
>>> że w przypadku typów wartościowych porównywanie tożsamości
>>> obiektów typów wartościowych (o ile w ogóle jest dostępne w
>>> języku - w Javie np. nie jest dostępne) nie daje żadnej istotnej
>>> informacji, tzn. takiej, na której można w czymś polegać w
>>> programie
>
>> No tak, w sumie masz rację. Ale jest jedno ale: zarządzanie
>> takimi obiektami wartościowymi w pamięci. Użytkownik takich
>> obiektów może je sobie traktować jak wartościowe, przekazywać
>> go mając na myśli jego wartość, porównywać go mając na myśli
>> porównanie wartości, ale wciąż będą pewne części programu,
>> w których chciałby wiedzieć, w jakim miejscu pamięci leży
>> ten obiekt, albo czy dwa obiekty leżą w różnych miejscach
>> pamięci, czy może jest to to samo miejsce pamięci.
>
> Teoretycznie jest to prawda, ale do czego miałoby to służyć?
>
> Sensownym przykładem niezwykłego typu wartościowego jest string. Nikt nie
> zaprzeczy, że jest to wartość - identyfikacja tego, czy jest to "ten sam
> string" polega na sprawdzeniu, czy składa się z tych samych znaków. Natomiast
> co do miejsca w pamięci - cóż, w przypadku stringa z gcc w "pamięci" siedzi
> dokładnie jeden wskaźnik na "jakąś pamięć" (w której upchnięta jest tablica
> znaków i dodatkowe dane). Ta pamięć jest w zupełnie innym miejscu, więc jakie
> ma znaczenie fakt, gdzie akurat siedzi ten jeden wskaźnik do tej pamięci?
>
>>> W językach, w których wszystko jest obiektem, typy wartościowe
>>> są symulowane poprzez niemodyfikowalne obiekty. To znaczy,
>>> każdy obiekt typu wartościowego musi zostać za każdym razem
>>> wyprodukowany na nowo.
>
>> Hmm... coś mi to przypomina...
>> Czy obiekt klasy TrybGraficzny mógłby być typem wartościowym?
>> Chodzi mi o taki obiekt przechowujący informacje o parametrach
>> trybu graficznego. Coś mi się zdaje, że tak, bo tutaj:
>
>> TrybGraficzny pierwszy = { 800, 600, 16 };
>> TrybGraficzny drugi = { 800, 600, 16 };
>> ...
>> if (pierwszy==drugi) ...
>
>> porównanie oznacza porównanie wartości, a nie tożsamości.
>
> Oczywiście, jak najbardziej, ale nie tak całkiem prosto.
>
> Tryb graficzny to typowy przykład typu o ograniczonym zestawie wartości
> (teoretycznie każdy typ wartościowy ma ograniczony zestaw wartości, ale w
> przypadku takich np. BigInteger czy zwykłego float to się nie sprawdza :).
> Powinno się mieć do tego celu:
> - zestaw wartości szybkich w obsłudze (np. liczb całkowitych), które
> przyporządkowuje się danemu trybowi
> - tablicę, gdzie dla każdego z tych trybów przechowuje się jego
> charakterystyki
>
> I teoretycznie mógłby to być nawet typ o zmiennej liście dopuszczalnych
> wartości. Co oznacza, że dysponujesz na starcie PREDEFINIOWANYM zestawem
> trybów, który jest zebrany w określonej tablicy, a zmienna przechowuje tylko
> liczbę całkowitą określającą jego identyfikator.
>
> W takim przypadku pierwszy == drugi wewnętrznie porównuje oczywiście liczby
> całkowite, ale logicznie chodzi tutaj o to, że porównuje się, czy tryb
> "pierwszy" to ten sam tryb, co "drugi". Jest tak, jeśli oba przechowują
> identyfikator tego samego trybu, czyli ten sam identyfikator.
>
>> W moim kodzie chciałem dodatkowo zagwarantować stałość
>> takich obiektów, tzn. żeby były właśnie niemodyfikowalne.
>> Raz utworzone z pewnymi wartościami mają je już do końca
>> życia [bo parametry tego samego trybu graficznego nigdy
>> się nie zmieniają]. Są one produkowane raz, przez obiekt
>> wyciągający je z karty graficznej, i później już się
>> nie zmieniają. Mogą być jedynie kopiowane, ale wykonanie
>> kopii sprawia, że mamy wciąż "ten sam" tryb graficzny,
>> tylko przechowywany w dwóch miejscach ;J
>> [to miało zagwarantować, że nikt niepowołany nie stworzy
>> sobie własnego obiektu klasy TrybGraficzny z dowolnie
>> ustawionymi, nieprawidłowymi wartościami].
>> Czy ten mój TrybGraficzny nie jest przypadkiem idealnym
>> przykładem typu wartościowego? :J [o ile dobrze to zrozumiałem]
>
> Tak, ale właśnie dlatego najlepiej zrealizować go w ten sposób, żeby móc
> dysponować predefiniowanym zestawem wartości, którymi - dla wygody - operujesz
> "behind the scene" odwołując się po identyfikatorach do określonych
> "wartości".
>
>>> W językach, które naturalnie wspierają typy wartościowe
>
>> O jakich językach mowa? Wolałbym to wiedzieć, bo wtedy
>> mógłbym sobie popatrzeć jak tam to jest zrobione i może
>> ułatwiłoby mi to zrozumienie sprawy na przykładach ;)
>
> Na przykład C++ i C#. Java też niby wspiera, ale tylko swoje własne wbudowane.
> W przypadku C# zresztą nie pamiętam jak dokładnie jest z porównywaniem typów
> struct, więc też nie wiem na ile to wsparcie jest naturalne.
>
> C++, w odróżnieniu od wielu innych języków (co jest zresztą cechą
> odziedziczoną z C) postawił na nierozróżnianie typów wartościowych i
> niewartościowych, pozostawiając to użytkownikowi. Konsekwencją tego jednak
> jest konieczność stosowania * i & w przypadku typów niewartościowych. Różni go
> to od C# i Javy, gdzie postawiono na rozróżnianie tych typów, niestety
> paskudną konsekwencją w przypadku Javy (przykładowo) jest fakt, że typów
> wartościowych nie można definiować, a nadomiar złego typ w naturalnie sposób
> wartościowy String jest w Javie zrobiony jako niewartościowy - przez co Java
> jest do dziś chyba jedynym językiem, w którym jedynym bezpiecznym sposobem
> sprawdzenia, czy string s jest niepusty, jest:
>
> if ( !"".equals( s ) )
niekoniecznie lepiej wyglada tak: s.equals("")
albo w ogole s.isEmpty()
Technical Details
Message-ID:
<fstvgr$njs$1@inews.gazeta.pl>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mailReferences:
<pl-comp-objects-faq-1-1166202604@ict.pwr.wroc.pl> <esfchn$t5r$1@kujawiak.man.lodz.pl> <esgboi$8i2$2@bandai.magma-net.pl> <esi2kk$skh$2@kujawiak.man.lodz.pl> <esi6uk$4mt$1@bandai.magma-net.pl> <esmu4p$ii1$2@kujawiak.man.lodz.pl> <esn1nl$7q7$1@bandai.magma-net.pl> <esv08v$o5d$1@kujawiak.man.lodz.pl> <et6pse$eab$1@bandai.magma-net.pl> <et7emm$cf1$1@kujawiak.man.lodz.pl> <etak85$krq$1@bandai.magma-net.pl> <eteh83$he8$1@kujawiak.man.lodz.pl> <pan.2007.03.16.21.49.44.873488@go2.pl> <etkgvt$2b$1@kujawiak.man.lodz.pl> <pan.2007.03.19.01.18.29.79961@go2.pl> <fmm5kd$nt4$1@kujawiak.man.lodz.pl>Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mail From: Radoslaw Jocz <rmjocz@gazeta.pl> Newsgroups: pl.comp.objects Subject: Re: pl.comp.objects FAQ (Frequently Asked Questions and more) Date: Tue, 01 Apr 2008 19:39:25 +0100 Organization: "Portal Gazeta.pl -> http://www.gazeta.pl" Lines: 327 Message-ID: <fstvgr$njs$1@inews.gazeta.pl> References: <pl-comp-objects-faq-1-1166202604@ict.pwr.wroc.pl> <esfchn$t5r$1@kujawiak.man.lodz.pl> <esgboi$8i2$2@bandai.magma-net.pl> <esi2kk$skh$2@kujawiak.man.lodz.pl> <esi6uk$4mt$1@bandai.magma-net.pl> <esmu4p$ii1$2@kujawiak.man.lodz.pl> <esn1nl$7q7$1@bandai.magma-net.pl> <esv08v$o5d$1@kujawiak.man.lodz.pl> <et6pse$eab$1@bandai.magma-net.pl> <et7emm$cf1$1@kujawiak.man.lodz.pl> <etak85$krq$1@bandai.magma-net.pl> <eteh83$he8$1@kujawiak.man.lodz.pl> <pan.2007.03.16.21.49.44.873488@go2.pl> <etkgvt$2b$1@kujawiak.man.lodz.pl> <pan.2007.03.19.01.18.29.79961@go2.pl> <fmm5kd$nt4$1@kujawiak.man.lodz.pl> NNTP-Posting-Host: cpc3-kemp3-0-0-cust860.lutn.cable.ntl.com Mime-Version: 1.0 X-Trace: inews.gazeta.pl 1207075164 24188 86.3.247.93 (1 Apr 2008 18:39:24 GMT) X-Complaints-To: usenet@agora.pl NNTP-Posting-Date: Tue, 1 Apr 2008 18:39:24 +0000 (UTC) X-User: rmjocz In-Reply-To: <fmm5kd$nt4$1@kujawiak.man.lodz.pl> User-Agent: Thunderbird 2.0.0.12 (Windows/20080213) Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit