🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.objects
79 messages
79 total messages Page 2 of 2 Started by Kamil Konieczny Fri, 15 Dec 2006 17:10
Page 2 of 2 • 79 total messages
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15745
Author: Mariusz Lotko
Date: Wed, 07 Mar 2007 18:59
132 lines
7235 bytes
Sektor van Skijlen wrote:

> Dnia Mon, 05 Mar 2007 23:58:08 +0100, Mariusz Lotko skrobie:
>> Sektor van Skijlen wrote:
> 
>> > Dnia Mon, 05 Mar 2007 07:07:55 +0100, Mariusz Lotko skrobie:
>> >> > No właśnie o to chodzi, że nie. Jeśli określamy dany typ jako
>> >> > wartościowy, to tożsamość przechowującego ją obiektu nie powinna nas
>> >> > interesować w ogóle.
>> > 
>> >> A zatem powszechnie stosowany "trik" polegający na sprawdzeniu
>> >> tożsamości obiektu w pierszej linijce operatora == uważasz za błędny?
>> > 
>> > Tak.
> 
>> Wybacz, ale powyższym stwierdzeniem skłaniasz mnie do stwierdzenia u
>> Ciebie paranoi... Przecież stosowanie tego jest oczywiste. Po co mam
>> sprawdzać, czy mam tyle samo pieniędzy w swoim portfelu co... w swoim?
> 
> Portfel nie jest typem wartościowym.
> 
> Ilość pieniędzy w portfelu jest jedynie jednym ze stanów tego obiektu,
> podobnie jak ilość kart kredytowych w środku, kolor portfela i materiał, z
> którego go wykonano.

I w _każdym_ systemie tak to modelujesz? Z pełną otoczką? Piękny przykład
wzorca "swiss army knife".

> Typem wartościowym może być kolor. Porównanie dwóch obiektów typu kolor
> można porównać ze sprawdzeniem, czy na dwóch kartkach papieru zapisany tam
> kod koloru jest ten sam. Ty chcesz, żeby przed odczytaniem numeru z każdej
> kartki najpierw sprawdzić, czy te obie kartki to czasem nie jest jedna i
> ta sama kartka. Jaki to ma sens?

Idąc Twoją logiką: niekoniecznie. Obiekt kolor ma jeszcze atrybuty: data
naniesienia, technika wykonania i stopień nasłonecznienia, które pozwalają
obliczyć rzeczywisty kolor w czasie :> Wtedy nie da się porównać dwóch
"czerwonych". Odsyłam do ekspertów - lakierników samochodowych.

>> >> Podobnie w operatorze =, w którym zapobiega to przypisania obiektu
>> >> samemu sobie?
>> > 
>> > Tu już nie, ale to jest związane z tzw. kwestią językową. W przypadku
>> > C++ jest to konieczne, jeżeli obiekt podawany jako argument operatora =
>> > jest przekazywany przez referencję.
>> > 
>> > Nie byłoby natomiast tego problemu w przypadku, gdyby ten obiekt był
>> > tam przekazywany przez wartość.
>> > 
>> > Gdyby hipotetycznie w Javie była możliwość zrobienia czegoś podobnego,
>> > to tam też nie ma konieczności dodawania takiego sprawdzenia:
> 
>> Z tym, że w obu przypadkach nie chodzi o "przykrą konieczność", a
>> o "wspaniałą możliwość" szybkiego stwierdzenia, że chodzi o "te same"
>> a więc na pewno "takie same" obiekty.
> 
> To jest przykra konieczność. Musisz to po prostu zrobić, bo inaczej będzie
> wylot.

W operatorze porównania? Nie sądzę...

> Ta "wspaniała możliwość" z kolei powoduje droższe porównanie.

W pewnych przypadkach może tak być. Implementując operator warto
oszacować prawdopodobieństwo porównywania tych samych obiektów.
Generalnie jednak - nie zgadzam się.

>> >> > Zauważ, po co w C++ stosuje się wskaźniki i referencje do takich
>> >> > typów jak int, czy std::string. Jeśli już, to stosuje się albo
>> >> > uogólnienie przekazywania (const T&), albo przekazuje się do
>> >> > zmodyfikowania (T&, T*). Czy widziałeś kiedykolwiek w jakimś
>> >> > rzeczywistym programie, żeby ktoś porównywał dwa wskaźniki do int
>> >> > (pomijając przypadek, gdy wskaźnik do int jest używany jako iterator
>> >> > do tablicy int-ów - czyli zastosowanie jest inne, niż wartość
>> >> > referencji)?
>> > 
>> >> Tak, w dowolnej konkretyzacji szablonu int'em. Nie każdemu chce się
>> >> robić specjalne implementacje dla typów prostych.
>> > 
>> > Przy uogólnianiu oczywiście jest to prawda, z tą tylko różnicą, że tam
>> > typ parametryczny T traktuje się prawdopodobnie zawsze jak typ
>> > obiektowy, więc sprawa konkretyzacji na int nie ma i tak znaczenia.
> 
>> "Prawdopodobnie" to dla mnie trochę za mało. Szczególnie w przypadku
>> szablonów, które według mojej praktyki z reguły są po prostu przeznaczone
>> dla obiektów oferujących określony interfejs. I innych ograniczeń w ich
>> użyciu właściwie nie ma.
> 
> Tak, dokładnie. Ale typy wartościowe zwykle mają inny interfejs, niż typy
> obiektowe.

Znowu ogólnik: "zwykle"... "Sprzedajesz" nam teorię, która ma działać w
praktyce, ułatwiać ją. Chciałbyś, żeby Twój samochód "zwykle" działał?

> 
>> > Jeśli mówimy już o rzeczywistości - podaj mi przykład obiektu z
>> > rzeczywistości, który posiada jednocześnie wartość i tożsamość.
> 
>> Konto bankowe. Tożsamość: numer, wartość: saldo.
> 
> Oraz wartość: właściciel (można go potem kiedyś zmienić)
> Oraz obiekt: historia transakcji
> Oraz...

Jak wyżej: zależy od kontekstu. Możemy nie wiązać obiektów transakcji do
konta, a zrobić wiązanie odwrotne: każda transakcja ma referencję do konta.
I podobnie z właścicielem. Krótko mówiąc "konto jest anonimowe" i
przechowuje jedynie swoje saldo (wartość) oraz numer (tożsamość).
Nie wiem, czy to ma sens, ale nie możesz chyba wykluczyć, że w jakimś
tam systemie może mieć.

> Czy ty w ogóle wiesz, co to jest "wartość"?

Element ze zbioru (tu: typ, klasa).

>> Nie chciałbym mieć konta w banku, który ma kłopot z odróżnieniem
>> wartości mojego konta od jego tożsamości.
> 
> Na razie to masz problem z odróżnieniem wartości od stanu.

Hmm, mam na ten temat "swoją teorię". Na razie przyjmijmy, że jestem
betonem zamkniętym na Twoją światłą myśl. Na pocieszenie powiem Ci, że jeśli
Twoja teoria się przyjmie i w kilku książkach pojawią się
sformułowania w rodzaju "słynny obiektolog prof. van Skijlen opisuje to w
swojej pracy...", to zgłoszę się do Ciebie po autograf :-)

A tymczasem pozwolę sobie zakończyć, bo już chyba nikt nas nie czyta, 
a i argumenty jakby zaczęły się powtarzać.


-- 
Mariusz Lotko
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15746
Author: Sektor van Skijlen
Date: Sat, 10 Mar 2007 19:17
206 lines
10732 bytes
Dnia Wed, 07 Mar 2007 19:59:52 +0100, Mariusz Lotko skrobie:
> Sektor van Skijlen wrote:

> > Dnia Mon, 05 Mar 2007 23:58:08 +0100, Mariusz Lotko skrobie:
> >> Sektor van Skijlen wrote:
> > 
> >> > Dnia Mon, 05 Mar 2007 07:07:55 +0100, Mariusz Lotko skrobie:
> >> >> > No właśnie o to chodzi, że nie. Jeśli określamy dany typ jako
> >> >> > wartościowy, to tożsamość przechowującego ją obiektu nie powinna nas
> >> >> > interesować w ogóle.
> >> > 
> >> >> A zatem powszechnie stosowany "trik" polegający na sprawdzeniu
> >> >> tożsamości obiektu w pierszej linijce operatora == uważasz za błędny?
> >> > 
> >> > Tak.
> > 
> >> Wybacz, ale powyższym stwierdzeniem skłaniasz mnie do stwierdzenia u
> >> Ciebie paranoi... Przecież stosowanie tego jest oczywiste. Po co mam
> >> sprawdzać, czy mam tyle samo pieniędzy w swoim portfelu co... w swoim?
> > 
> > Portfel nie jest typem wartościowym.
> > 
> > Ilość pieniędzy w portfelu jest jedynie jednym ze stanów tego obiektu,
> > podobnie jak ilość kart kredytowych w środku, kolor portfela i materiał, z
> > którego go wykonano.

> I w _każdym_ systemie tak to modelujesz? Z pełną otoczką? Piękny przykład
> wzorca "swiss army knife".

Nie używaj pojęć, których znaczenia nie rozumiesz.

Swiss army knife to by było, gdyby ten portfel mógł przechowywać pieniądze,
laptopy, meble, samochody, kontenery i elektrownie.

Ilość pieniędzy nie jest wartością portfela. Jest jego stanem. Portfel nie
może mieć wartości - i to nie dlatego, że poza tym może mieć jeszcze wiele
innych stanów i atrytbutów.

> > Typem wartościowym może być kolor. Porównanie dwóch obiektów typu kolor
> > można porównać ze sprawdzeniem, czy na dwóch kartkach papieru zapisany tam
> > kod koloru jest ten sam. Ty chcesz, żeby przed odczytaniem numeru z każdej
> > kartki najpierw sprawdzić, czy te obie kartki to czasem nie jest jedna i
> > ta sama kartka. Jaki to ma sens?

> Idąc Twoją logiką: niekoniecznie. Obiekt kolor ma jeszcze atrybuty: data
> naniesienia, technika wykonania i stopień nasłonecznienia, które pozwalają
> obliczyć rzeczywisty kolor w czasie :> Wtedy nie da się porównać dwóch
> "czerwonych". Odsyłam do ekspertów - lakierników samochodowych.

Nie przypominam sobie, żebym mówił o lakierze samochodowym. Mówiłem o kolorze.
Kolor może być również atrybutem (a nie wartością, acz przypadkiem też nie
stanem) lakieru.

No to jak, zrozumiałeś już, co to takiego jest wartość, czy douczysz się i
zgłosisz za tydzień?

> >> Z tym, że w obu przypadkach nie chodzi o "przykrą konieczność", a
> >> o "wspaniałą możliwość" szybkiego stwierdzenia, że chodzi o "te same"
> >> a więc na pewno "takie same" obiekty.
> > 
> > To jest przykra konieczność. Musisz to po prostu zrobić, bo inaczej będzie
> > wylot.

> W operatorze porównania? Nie sądzę...

W operatorze przypisania.

> > Ta "wspaniała możliwość" z kolei powoduje droższe porównanie.

> W pewnych przypadkach może tak być.

Statystycznie jest to 99% przypadków.

> Implementując operator warto
> oszacować prawdopodobieństwo porównywania tych samych obiektów.

Zrób sobie małą statystykę użycia takiego typu i ilość porównań, dla których
trafiasz na równość i dla których trafiasz na nierówność.

Prosty przykład - iteratory. Masz pętlę, w której przechodzisz przez wszystkie
iteratory w zakresie od jednego do drugiego. Ile masz w tym momencie porównań,
które wyjdą równe, a ile, które wyjdą nierówne? Tu policzyć bardzo łatwo:

Dla zakresu o długości N, będziesz miał N-1 porównań, które się okażą
nierównością, i jedno, które okaże sie równością. Różnica rośnie wraz z
długością zakresu i tylko w przypadku gdy zakres ma 1 element porównanie jest
szybsze. Dla dwóch elemmentów jest już mniej więcej tak samo kosztowne, wraz z
powiększaniem się długości zakresu porównanie, które najpierw sprawdza
tożsamość, jest kosztowniejsze.

Podałem ci tylko przykład, jak należy prowadzić taką analizę - to, że ten
przykład jest negatywny dla twojej tezy, nie ma znaczenia. Myślę, że dałoby
się znaleźć przykład, który by twoją tezę potwierdzał, ale to nie ma większego
znaczenia.

W odróżnieniu od ciebie jednak, ja rozumiem konieczność wykonania analizy,
która dowiedzie, czy to się nam opłaca, czy nie. Ty przyjmujesz "w ciemno", że
sprawdzanie najpierw tożsamości będzie zawsze bardziej opłacalne. W
ostateczności zgadzasz się nawet, że "najczęściej".

No to podaj mi przykład typu wartościowego, w którym to się opłaca, i oszacuj
ilość porównań trafionych i nietrafionych w typowych algorytmach, które go
używają. Wtedy będziemy wiedzieli, o czym rozmawiamy.

> Generalnie jednak - nie zgadzam się.

Ależ masz pełne prawo się nie zgadzać. Ja w odróżnieniu od ciebie potrafię to
uzasadnić.

> >> >> > Zauważ, po co w C++ stosuje się wskaźniki i referencje do takich
> >> >> > typów jak int, czy std::string. Jeśli już, to stosuje się albo
> >> >> > uogólnienie przekazywania (const T&), albo przekazuje się do
> >> >> > zmodyfikowania (T&, T*). Czy widziałeś kiedykolwiek w jakimś
> >> >> > rzeczywistym programie, żeby ktoś porównywał dwa wskaźniki do int
> >> >> > (pomijając przypadek, gdy wskaźnik do int jest używany jako iterator
> >> >> > do tablicy int-ów - czyli zastosowanie jest inne, niż wartość
> >> >> > referencji)?
> >> > 
> >> >> Tak, w dowolnej konkretyzacji szablonu int'em. Nie każdemu chce się
> >> >> robić specjalne implementacje dla typów prostych.
> >> > 
> >> > Przy uogólnianiu oczywiście jest to prawda, z tą tylko różnicą, że tam
> >> > typ parametryczny T traktuje się prawdopodobnie zawsze jak typ
> >> > obiektowy, więc sprawa konkretyzacji na int nie ma i tak znaczenia.
> > 
> >> "Prawdopodobnie" to dla mnie trochę za mało. Szczególnie w przypadku
> >> szablonów, które według mojej praktyki z reguły są po prostu przeznaczone
> >> dla obiektów oferujących określony interfejs. I innych ograniczeń w ich
> >> użyciu właściwie nie ma.
> > 
> > Tak, dokładnie. Ale typy wartościowe zwykle mają inny interfejs, niż typy
> > obiektowe.

> Znowu ogólnik: "zwykle"... "Sprzedajesz" nam teorię, która ma działać w
> praktyce, ułatwiać ją. Chciałbyś, żeby Twój samochód "zwykle" działał?

Oczywiście teoretycznie może istnieć taki wzorzec, który typom nie stawia
żadnych wymagań, ale w praktyce nie spotkałem się z takim.

Wymagania co do typów zawsze określają poszczególne operacje, które na typie
można wykonać. I te operacje świadczą też o tym, czy typ jest wartościowy, czy
nie.

Przykładowo, typ przechowywany w std::list musi być typem wartościowym.
Niestety, tak jest skonstruowany szablon std::list. Świadczą o tym następujące
wymagania względem typu:
 - przypisywalny
 - kopiowalny
 - domyślnie-konstruowalny

Poza tym wiele algorytmów STL, które mogłyby pracować również na zakresie
wziętym z listy, wymagają dodatkowo, żeby był porównywalny.

Dostarczając do swojego typu wszystkie możliwe rzeczy, żeby spełnić wymagania,
de facto czynisz z niego typ wartościowy - co może się niekoniecznie zgadzać z
logiką twojego programu.

> >> > Jeśli mówimy już o rzeczywistości - podaj mi przykład obiektu z
> >> > rzeczywistości, który posiada jednocześnie wartość i tożsamość.
> > 
> >> Konto bankowe. Tożsamość: numer, wartość: saldo.
> > 
> > Oraz wartość: właściciel (można go potem kiedyś zmienić)
> > Oraz obiekt: historia transakcji
> > Oraz...

> Jak wyżej: zależy od kontekstu.

Nic nie zależy od żadnego kontekstu.

Saldo jest stanem (cząstkowym) konta. Saldo jest wartością. Konto jest
obiektem.

> Możemy nie wiązać obiektów transakcji do
> konta, a zrobić wiązanie odwrotne: każda transakcja ma referencję do konta.

Ale co to ma do rzeczy?

Transakcja też jest obiektem, tzw. "wartość transakcji" jest atrybutem obiektu
transakcji, a ilość pieniędzy, na którą opiewa transakcja, jest wartością.

> I podobnie z właścicielem. Krótko mówiąc "konto jest anonimowe" i
> przechowuje jedynie swoje saldo (wartość) oraz numer (tożsamość).

Numer jest atrybutem obiektu (unikalnym, więc jest ściśle związany z
tożsamością), właściciel też jest obiektem (w bazie banku jest osobnym
obiektem, który może być podmapowany do kilku kont). Saldo jest stanem konta,
a wartość salda to ilość pieniędzy znajdujących się na koncie.

> Nie wiem, czy to ma sens, ale nie możesz chyba wykluczyć, że w jakimś
> tam systemie może mieć.

Niestety nie. Przykro mi.

> > Czy ty w ogóle wiesz, co to jest "wartość"?

> Element ze zbioru (tu: typ, klasa).

To znaczy?


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15747
Author: Marcin 'Qrczak' Kowalczyk
Date: Sun, 11 Mar 2007 00:40
91 lines
6171 bytes
Dnia 10-03-2007, sob o godzinie 19:17 +0000, Sektor van Skijlen
napisał(a):

> Zrób sobie małą statystykę użycia takiego typu i ilość porównań, dla których
> trafiasz na równość i dla których trafiasz na nierówność.

Zrób statystykę, ile można stracić i ile można zaoszczędzić.

Sprawa nie jest oczywista. Jest wiele czynników wpływających na
opłacalność: statyczne bądź dynamiczne typowanie, statyczna wiedza
kompilatora niekoniecznie wynikająca z systemu typów, reprezentacja
obiektów czy zgoła wymagania semantyki operacji porównania w danym
języku.

Przykład. W OCamlu jest funkcja =, która porównuje zawartość dwóch
obiektów tego samego, dowolnego typu. Porównuje głęboko, nie zważając na
to, które fragmenty są zmienialne. Kompilator generuje specjalny kod dla
pewnych typów (np. liczby różnego rodzaju albo typy wyliczeniowe). Jest
też zmaterializowana w jednym miejscu uniwersalna funkcja porównująca,
zaimplementowana w C, używana dla różnych złożonych typów oraz tam,
gdzie typ nie jest statycznie znany (bo kod jest parametryzowany typem).

Ta funkcja do niedawna zaczynała od porównania fizycznej reprezentacji
argumentów, czyli albo wartości bezpośrednich, albo wskaźników. Jeśli
były równe, to zwracała true bez wchodzenia do środka, a jeśli nie były
równe, to dopiero sprawdzała, czy oba są wartościami bezpośrednimi albo
oba wskaźnikami i czy mają ten sam numer konstruktora. Z punktu widzenia
efektywności uznano, że warto.

Zostało to zmienione z powodu typu float, który jest porównywany przez =
zgodnie z arytmetyką IEEE: nan jest różne od samego siebie. Z tego
wynika, że dowolna struktura zawierająca nan, np. lista [1.0; nan; 2.0],
jest różna od samej siebie. Tymczasem w starej implementacji była równa
albo różna w zależności od tego, czy była zaalokowana osobno, czy nie,
co w przypadku listy nie powinno było mieć znaczenia. Co śmieszniejsze,
ta sama samodzielna wartość nan była równa sobie albo nierówna
w zależności od tego, czy miejsce aplikacji funkcji = było kompilowane
ze świadomością, że argumenty są typu float (wtedy było generowane tylko
zmiennoprzecinkowe porównanie zawartości), czy nie (wtedy używana była
wspomniana uniwersalna implementacja, która najpierw porównywała adres).

Tak więc zarzucono to z powodów semantycznych.

Inny przykład. W Kogucie jest funkcja Is, która porównuje dwie wartości
i z założenia jest najmniejszą relacją równoważności, która nie bierze
pod uwagę fizycznej tożsamości tam gdzie nie musi (czyli przy większości
obiektów niezmienialnych).

Problemu z NaN nie ma, bo równość arytmetyczna, w której NaN jest różne
od siebie, to osobna funkcja.

Reprezentacja wartości jest taka, że małe liczby całkowite są oznaczone
najmłodszym bitem równym 1, a wszystkie pozostałe wartości są
wskaźnikami na obiekt, którego pierwsze słowo jest wskaźnikiem na
tzw. deskryptor, którego jednym z pól jest wskaźnik na typ.

Kompilator generuje specjalny kod dla aplikacji Is, jeśli jeden
z argumentów jest znaną mu stałą. Poza tym jest jedna uniwersalna
implementacja Is, która robi co następuje:

1. Jeśli wartości są fizycznie równe (taka sama mała liczba całkowita
   albo taki sam wskaźnik), to wynikiem jest True.

2. Jeśli któryś z argumentów jest małą liczbą całkowitą, to wynikiem
   jest False.

3. Jeśli wartości są różnych typów, to wynikiem jest False.

4. Wybierana i wykonywana jest implementacja Is zależna od typu
   (wspólnego dla obu argumentów), wyszukiwana w słowniku (standardowy
   mechanizm funkcji generycznych).

Zauważmy, że 3 nie wprowadza dodatkowego kosztu, skoro tak czy siak
czeka nas 4 (dzięki 3 w 4 wystarczy wziąć jeden typ), a 2 nie wprowadza
dodatkowego kosztu, skoro czeka nas 3 (trzeba sprawdzić, czy dana
wartość nie jest małą liczbą całkowitą, zanim sprawdzi się jej typ).

W tej sytuacji punkt 1 narzuca się w sposób naturalny. Porównanie
równych liczb całkowitych jest szybsze (wystarczy pierwszy punkt).
Porównanie różnych liczb całkowitych jest tak samo szybkie (dwa proste
punkty potrzebne tak czy siak). Porównanie innych wartości jest albo
nieznacznie wolniejsze (jedno dodatkowe porównanie, kiedy są już co
najmniej dwa inne), albo znacznie szybsze (oszczędzenie punktów od 2
do 4 przy porównaniu np. Null z Null albo równych znaków mieszczących
się w ISO-8859-1, a czasem i równych innych stringów, jeśli to ten sam
obiekt).

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15748
Author: Mariusz Lotko
Date: Tue, 13 Mar 2007 18:24
221 lines
10052 bytes
Sektor van Skijlen wrote:

>> > Portfel nie jest typem wartościowym.
>> > 
>> > Ilość pieniędzy w portfelu jest jedynie jednym ze stanów tego obiektu,
>> > podobnie jak ilość kart kredytowych w środku, kolor portfela i
>> > materiał, z którego go wykonano.
> 
>> I w _każdym_ systemie tak to modelujesz? Z pełną otoczką? Piękny przykład
>> wzorca "swiss army knife".
> 
> Nie używaj pojęć, których znaczenia nie rozumiesz.

Nie czyń założeń, na które nie masz dowodów.

> Swiss army knife to by było, gdyby ten portfel mógł przechowywać
> pieniądze, laptopy, meble, samochody, kontenery i elektrownie.

Nie. Swiss army knife oznacza, że modelujesz wszystkie elementy
rzeczywistości czy tego wymaga system czy nie. Dlatego nie ma np.
uniwersalnej implementacji portfela, która jest dobra w każdym
systemie.
Gdyby tak było, jak grzyby po deszczu powstawałyby biblioteki, które
implementują obiekty naszej codzienności.

> Ilość pieniędzy nie jest wartością portfela. Jest jego stanem. Portfel nie
> może mieć wartości - i to nie dlatego, że poza tym może mieć jeszcze wiele
> innych stanów i atrytbutów.

Wychodząc z tego założenia stanem "obiektu" "klasy" int jest np. 2. Stan
ten można zmienić "funkcją" zmiany stanu, np. ++.
Kto z nas nie rozróżnia wartości od stanu?

> 
>> > Typem wartościowym może być kolor. Porównanie dwóch obiektów typu kolor
>> > można porównać ze sprawdzeniem, czy na dwóch kartkach papieru zapisany
>> > tam kod koloru jest ten sam. Ty chcesz, żeby przed odczytaniem numeru z
>> > każdej kartki najpierw sprawdzić, czy te obie kartki to czasem nie jest
>> > jedna i ta sama kartka. Jaki to ma sens?
> 
>> Idąc Twoją logiką: niekoniecznie. Obiekt kolor ma jeszcze atrybuty: data
>> naniesienia, technika wykonania i stopień nasłonecznienia, które
>> pozwalają obliczyć rzeczywisty kolor w czasie :> Wtedy nie da się
>> porównać dwóch "czerwonych". Odsyłam do ekspertów - lakierników
>> samochodowych.
> 
> Nie przypominam sobie, żebym mówił o lakierze samochodowym. Mówiłem o
> kolorze. Kolor może być również atrybutem (a nie wartością, acz
> przypadkiem też nie stanem) lakieru.

Ja tylko poszedłem Twoją logiką. Zważ, że w systemie, o którym pisałem
przy portfelu nie wspominałem o istnieniu kart kredytowych.

> No to jak, zrozumiałeś już, co to takiego jest wartość, czy douczysz się i
> zgłosisz za tydzień?

Do kogo miałbym się zgłosić?

> 
>> >> Z tym, że w obu przypadkach nie chodzi o "przykrą konieczność", a
>> >> o "wspaniałą możliwość" szybkiego stwierdzenia, że chodzi o "te same"
>> >> a więc na pewno "takie same" obiekty.
>> > 
>> > To jest przykra konieczność. Musisz to po prostu zrobić, bo inaczej
>> > będzie wylot.
> 
>> W operatorze porównania? Nie sądzę...
> 
> W operatorze przypisania.

Co miałoby sprawić "wylot" w operatorze przypisania?

>> > Ta "wspaniała możliwość" z kolei powoduje droższe porównanie.
> 
>> W pewnych przypadkach może tak być.
> 
> Statystycznie jest to 99% przypadków.

Statystycznie, to ja biję swoją żonę co miesiąc. Ty, jeśli jesteś żonaty
również. Takie szacunki trzeba robić dla konkretnych klas a nie
generalizować.

>> Implementując operator warto
>> oszacować prawdopodobieństwo porównywania tych samych obiektów.
> 
> Zrób sobie małą statystykę użycia takiego typu i ilość porównań, dla
> których trafiasz na równość i dla których trafiasz na nierówność.
> 
> Prosty przykład - iteratory. Masz pętlę, w której przechodzisz przez
(...)
> 
> Podałem ci tylko przykład, jak należy prowadzić taką analizę - to, że ten
> przykład jest negatywny dla twojej tezy, nie ma znaczenia. Myślę, że
> dałoby się znaleźć przykład, który by twoją tezę potwierdzał, ale to nie
> ma większego znaczenia.

Nie będę ani analizował Twojego przykładu, ani mu zaprzeczał. Zakładam,
że jest słuszny. To jednak tylko przykład, z którego do sformułowania
reguły jeszcze daleko.

> W odróżnieniu od ciebie jednak, ja rozumiem konieczność wykonania analizy,
> która dowiedzie, czy to się nam opłaca, czy nie. Ty przyjmujesz "w
> ciemno", że sprawdzanie najpierw tożsamości będzie zawsze bardziej
> opłacalne. W ostateczności zgadzasz się nawet, że "najczęściej".

Ty dla odmiany uważasz, że najczęściej nie. Na razie jednak nie potrafisz
udowodnić dlaczego Twoja teza jest lepsza od mojej.

> No to podaj mi przykład typu wartościowego, w którym to się opłaca, i
> oszacuj ilość porównań trafionych i nietrafionych w typowych algorytmach,
> które go używają. Wtedy będziemy wiedzieli, o czym rozmawiamy.

Nie chodzi o sam typ, tylko kontekst użycia.

> 
>> Generalnie jednak - nie zgadzam się.
> 
> Ależ masz pełne prawo się nie zgadzać. Ja w odróżnieniu od ciebie potrafię
> to uzasadnić.

W odróżnieniu od Ciebie unikam jednoznacznych stwierdzeń na temat swoich
umiejętności. Pozwalam to ocenić innym. Również Tobie, choć przyznam, że 
nie odbieram tych ocen zbyt serio.

Daj szansę innym pochwalić Twoje umiejętności. Może kiedyś to nastąpi.

>> >> "Prawdopodobnie" to dla mnie trochę za mało. Szczególnie w przypadku
>> >> szablonów, które według mojej praktyki z reguły są po prostu
>> >> przeznaczone dla obiektów oferujących określony interfejs. I innych
>> >> ograniczeń w ich użyciu właściwie nie ma.
>> > 
>> > Tak, dokładnie. Ale typy wartościowe zwykle mają inny interfejs, niż
>> > typy obiektowe.
> 
>> Znowu ogólnik: "zwykle"... "Sprzedajesz" nam teorię, która ma działać w
>> praktyce, ułatwiać ją. Chciałbyś, żeby Twój samochód "zwykle" działał?
> 
> Oczywiście teoretycznie może istnieć taki wzorzec, który typom nie stawia
> żadnych wymagań, ale w praktyce nie spotkałem się z takim.
> 
> Wymagania co do typów zawsze określają poszczególne operacje, które na
> typie można wykonać. I te operacje świadczą też o tym, czy typ jest
> wartościowy, czy nie.
> 
> Przykładowo, typ przechowywany w std::list musi być typem wartościowym.
> Niestety, tak jest skonstruowany szablon std::list. Świadczą o tym
> następujące wymagania względem typu:
>  - przypisywalny
>  - kopiowalny
>  - domyślnie-konstruowalny

Rozumiem, że jeśli stworzę sobie jakiś widget, powiedzmy combo-box, który
spełnia powyższe wymagania, to nie będę mógł, go przechowywać w std::list,
bo pogwałcę Twoją teorię?

>> >> > Jeśli mówimy już o rzeczywistości - podaj mi przykład obiektu z
>> >> > rzeczywistości, który posiada jednocześnie wartość i tożsamość.
>> > 
>> >> Konto bankowe. Tożsamość: numer, wartość: saldo.
>> > 
>> > Oraz wartość: właściciel (można go potem kiedyś zmienić)
>> > Oraz obiekt: historia transakcji
>> > Oraz...
> 
>> Jak wyżej: zależy od kontekstu.
> 
> Nic nie zależy od żadnego kontekstu.
> 
> Saldo jest stanem (cząstkowym) konta. Saldo jest wartością. Konto jest
> obiektem.

Niepotrzebnie wiążesz terminy z życia (stan konta) z terminami
informatycznymi (stan obiektu). Osobom z małym doświadczeniem to się
często zdarza, nie przejmuj się.

> 
>> Możemy nie wiązać obiektów transakcji do
>> konta, a zrobić wiązanie odwrotne: każda transakcja ma referencję do
>> konta.
> 
> Ale co to ma do rzeczy?

To, że obiekt konto nie musi przechowywać historii, jeśli tylko zechcę tak
to zamodelować.

> 
> Transakcja też jest obiektem, tzw. "wartość transakcji" jest atrybutem
> obiektu transakcji, a ilość pieniędzy, na którą opiewa transakcja, jest
> wartością.

Otóż to!

> 
>> I podobnie z właścicielem. Krótko mówiąc "konto jest anonimowe" i
>> przechowuje jedynie swoje saldo (wartość) oraz numer (tożsamość).
> 
> Numer jest atrybutem obiektu (unikalnym, więc jest ściśle związany z
> tożsamością), właściciel też jest obiektem (w bazie banku jest osobnym
> obiektem, który może być podmapowany do kilku kont). Saldo jest stanem
> konta, a wartość salda to ilość pieniędzy znajdujących się na koncie.

Dlaczego "ilość" nie jest według Ciebie "wartością"?

>> Nie wiem, czy to ma sens, ale nie możesz chyba wykluczyć, że w jakimś
>> tam systemie może mieć.
> 
> Niestety nie. Przykro mi.

Cieszę się, że choć raz przyznajesz mi rację i nie próbujesz tego wykluczyć.

> 
>> > Czy ty w ogóle wiesz, co to jest "wartość"?
> 
>> Element ze zbioru (tu: typ, klasa).
> 
> To znaczy?

Odsyłam do książki "Matematyka dla klas drugich".

-- 
Mariusz Lotko
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15749
Author: Sektor van Skijlen
Date: Wed, 14 Mar 2007 00:13
300 lines
14246 bytes
Dnia Tue, 13 Mar 2007 19:24:26 +0100, Mariusz Lotko skrobie:
> Sektor van Skijlen wrote:

> >> > Portfel nie jest typem wartościowym.
> >> > 
> >> > Ilość pieniędzy w portfelu jest jedynie jednym ze stanów tego obiektu,
> >> > podobnie jak ilość kart kredytowych w środku, kolor portfela i
> >> > materiał, z którego go wykonano.
> > 
> >> I w _każdym_ systemie tak to modelujesz? Z pełną otoczką? Piękny przykład
> >> wzorca "swiss army knife".
> > 
> > Nie używaj pojęć, których znaczenia nie rozumiesz.

> Nie czyń założeń, na które nie masz dowodów.

> > Swiss army knife to by było, gdyby ten portfel mógł przechowywać
> > pieniądze, laptopy, meble, samochody, kontenery i elektrownie.

> Nie. Swiss army knife oznacza, że modelujesz wszystkie elementy
> rzeczywistości czy tego wymaga system czy nie.

Nie wiem, jak ty, ale ja pojęcie "swiss army knife" znam jako jeden z błędów
OO, który polega na stworzeniu klasy o zbyt dużym zakresie odpowiedzialności.

Dokładność modelowania to zupełnie inna sprawa.

Zresztą, jeśli dla ciebie programowanie obiektowe jest modelowaniem
rzeczywistości, to obawiam się, że możemy naszą dyskusję wznowić za parę lat,
jak będziesz już mówił językiem własnego doświadczenia, a nie książkowym.

(Na marginesie: to bardzo dobrze, że literatura do OO twierdzi, że
programowanie obiektowe jest modelowaniem rzeczywistości. Tak bowiem należy tą
sprawę tłumaczyć początkującym. Im więcej jednak człowiek programuje
obiektowo, tym bardziej się przekonuje, że to nie ma nic wspólnego z prawdą.
To jest jeden ze znaków rozpoznawczych, czy ktoś potrafi myśleć samodzielnie
rzeczywiście dysponuje doświadczeniem zawodowym, czy recytuje z pamięci wiedzę
książkową.)

Cofając jednak tą całą dygresję, którą nie wiem po co wprowadziłeś - podałem
ci tylko przykład, dlaczego portfel nie może być typem wartościowym.

Jeśli nie zrozumiałeś nadal, to wytłumaczę ci bardziej łopatologicznie:
portfel zawierający tyle samo pieniędzy, to nie ten sam portfel (mówię tak, bo
twierdziłeś, że ilość pieniędzy może być wartością potrfela).

> > Ilość pieniędzy nie jest wartością portfela. Jest jego stanem. Portfel nie
> > może mieć wartości - i to nie dlatego, że poza tym może mieć jeszcze wiele
> > innych stanów i atrytbutów.

> Wychodząc z tego założenia stanem "obiektu" "klasy" int jest np. 2. Stan
> ten można zmienić "funkcją" zmiany stanu, np. ++.
> Kto z nas nie rozróżnia wartości od stanu?

int x = 2;
int y = 2;

Powiedz mi teraz, czy "x jest y".

> >> > Typem wartościowym może być kolor. Porównanie dwóch obiektów typu kolor
> >> > można porównać ze sprawdzeniem, czy na dwóch kartkach papieru zapisany
> >> > tam kod koloru jest ten sam. Ty chcesz, żeby przed odczytaniem numeru z
> >> > każdej kartki najpierw sprawdzić, czy te obie kartki to czasem nie jest
> >> > jedna i ta sama kartka. Jaki to ma sens?
> > 
> >> Idąc Twoją logiką: niekoniecznie. Obiekt kolor ma jeszcze atrybuty: data
> >> naniesienia, technika wykonania i stopień nasłonecznienia, które
> >> pozwalają obliczyć rzeczywisty kolor w czasie :> Wtedy nie da się
> >> porównać dwóch "czerwonych". Odsyłam do ekspertów - lakierników
> >> samochodowych.
> > 
> > Nie przypominam sobie, żebym mówił o lakierze samochodowym. Mówiłem o
> > kolorze. Kolor może być również atrybutem (a nie wartością, acz
> > przypadkiem też nie stanem) lakieru.

> Ja tylko poszedłem Twoją logiką. Zważ, że w systemie, o którym pisałem
> przy portfelu nie wspominałem o istnieniu kart kredytowych.

Nie poszedłeś moją logiką. Mówiłem o kolorze, a ty wziąłeś sobie nie wiem po
co lakier samochodowy.

Podobnie typem wartościowym mogą być "pieniądze". Ale nie kieszeń, portfel,
konto, sejf, czy gdzie to tam jeszcze chcesz przechowywać.

> > No to jak, zrozumiałeś już, co to takiego jest wartość, czy douczysz się i
> > zgłosisz za tydzień?

> Do kogo miałbym się zgłosić?

No cóż, wydawało mi się, że każdy, kto studiował, słyszał to słynne
określenie. W czymś się widać pomyliłem.

> >> >> Z tym, że w obu przypadkach nie chodzi o "przykrą konieczność", a
> >> >> o "wspaniałą możliwość" szybkiego stwierdzenia, że chodzi o "te same"
> >> >> a więc na pewno "takie same" obiekty.
> >> > 
> >> > To jest przykra konieczność. Musisz to po prostu zrobić, bo inaczej
> >> > będzie wylot.
> > 
> >> W operatorze porównania? Nie sądzę...
> > 
> > W operatorze przypisania.

> Co miałoby sprawić "wylot" w operatorze przypisania?

Sprawdzenie, czy nie przypisujemy samego siebie. Fakt, że musisz użyć
operatora porównania dla tożsamości jest przykrą koniecznością, bo bez tego
usunąłbyś część obiektu, z którego za chwilę masz zamiar czytać.

> >> > Ta "wspaniała możliwość" z kolei powoduje droższe porównanie.
> > 
> >> W pewnych przypadkach może tak być.
> > 
> > Statystycznie jest to 99% przypadków.

> Statystycznie, to ja biję swoją żonę co miesiąc. Ty, jeśli jesteś żonaty
> również. Takie szacunki trzeba robić dla konkretnych klas a nie
> generalizować.

No widzisz. A ja mogę sobie pozwolić na generalizację.

Chodzi o bardzo prostą rzecz: jakiej wielkości jest zwykle typ wartościowy?
Niewielkiej. Musi być niewielki, bo im większy, tym więcej zasobów zajmuje
jego wartość, dłużej się kopiuje, a i porównanie wartości - dosć częsta
operacja - trwa dość długo. Dlatego właśnie typy wartościowe robi się z
założenia JAK NAJMNIEJSZE - właśnie po to, żeby te operacje były jak
najszybsze. Skoro istnieje taka presja na obiekty wartościowe, to gdzie masz w
takim razie pole dla obiektów, w których porównanie można "przyspieszyć"
poprzez najpierw sprawdzanie tożsamości?

> >> Implementując operator warto
> >> oszacować prawdopodobieństwo porównywania tych samych obiektów.
> > 
> > Zrób sobie małą statystykę użycia takiego typu i ilość porównań, dla
> > których trafiasz na równość i dla których trafiasz na nierówność.
> > 
> > Prosty przykład - iteratory. Masz pętlę, w której przechodzisz przez
> (...)
> > 
> > Podałem ci tylko przykład, jak należy prowadzić taką analizę - to, że ten
> > przykład jest negatywny dla twojej tezy, nie ma znaczenia. Myślę, że
> > dałoby się znaleźć przykład, który by twoją tezę potwierdzał, ale to nie
> > ma większego znaczenia.

> Nie będę ani analizował Twojego przykładu, ani mu zaprzeczał. Zakładam,
> że jest słuszny. To jednak tylko przykład, z którego do sformułowania
> reguły jeszcze daleko.

To był przykład wykonania analizy, który pokazał, że się nie opłaca. Czy
jesteśw stanie podać mi kontrprzykład - czyli taki, który udowodni, że się
opłaca?

> > W odróżnieniu od ciebie jednak, ja rozumiem konieczność wykonania analizy,
> > która dowiedzie, czy to się nam opłaca, czy nie. Ty przyjmujesz "w
> > ciemno", że sprawdzanie najpierw tożsamości będzie zawsze bardziej
> > opłacalne. W ostateczności zgadzasz się nawet, że "najczęściej".

> Ty dla odmiany uważasz, że najczęściej nie. Na razie jednak nie potrafisz
> udowodnić dlaczego Twoja teza jest lepsza od mojej.

Potrafię, tylko ty nie potrafisz jej zrozumieć, albo uparcie zaprzeczasz
faktom.

Moja teza jest lepsza, bo jest oparta na rzetelnej analizie (nb. analiza
Qrczaka również). Twoja teza, że to jest "oczywiste, że tak się powinno zawsze
robić" nie jest poparta niczym.

> > No to podaj mi przykład typu wartościowego, w którym to się opłaca, i
> > oszacuj ilość porównań trafionych i nietrafionych w typowych algorytmach,
> > które go używają. Wtedy będziemy wiedzieli, o czym rozmawiamy.

> Nie chodzi o sam typ, tylko kontekst użycia.

Brawo! Zatem słucham.

> >> Generalnie jednak - nie zgadzam się.
> > 
> > Ależ masz pełne prawo się nie zgadzać. Ja w odróżnieniu od ciebie potrafię
> > to uzasadnić.

> W odróżnieniu od Ciebie unikam jednoznacznych stwierdzeń na temat swoich
> umiejętności.

Z tą "oczywistością", że operator porównania powinien najpierw sprawdzić
tożsamość, niespecjalnie ci to wyszło.

> Pozwalam to ocenić innym. Również Tobie, choć przyznam, że 
> nie odbieram tych ocen zbyt serio.

> Daj szansę innym pochwalić Twoje umiejętności. Może kiedyś to nastąpi.

Już nastąpiło, o to się nie martw.

> >> >> "Prawdopodobnie" to dla mnie trochę za mało. Szczególnie w przypadku
> >> >> szablonów, które według mojej praktyki z reguły są po prostu
> >> >> przeznaczone dla obiektów oferujących określony interfejs. I innych
> >> >> ograniczeń w ich użyciu właściwie nie ma.
> >> > 
> >> > Tak, dokładnie. Ale typy wartościowe zwykle mają inny interfejs, niż
> >> > typy obiektowe.
> > 
> >> Znowu ogólnik: "zwykle"... "Sprzedajesz" nam teorię, która ma działać w
> >> praktyce, ułatwiać ją. Chciałbyś, żeby Twój samochód "zwykle" działał?
> > 
> > Oczywiście teoretycznie może istnieć taki wzorzec, który typom nie stawia
> > żadnych wymagań, ale w praktyce nie spotkałem się z takim.
> > 
> > Wymagania co do typów zawsze określają poszczególne operacje, które na
> > typie można wykonać. I te operacje świadczą też o tym, czy typ jest
> > wartościowy, czy nie.
> > 
> > Przykładowo, typ przechowywany w std::list musi być typem wartościowym.
> > Niestety, tak jest skonstruowany szablon std::list. Świadczą o tym
> > następujące wymagania względem typu:
> >  - przypisywalny
> >  - kopiowalny
> >  - domyślnie-konstruowalny

> Rozumiem, że jeśli stworzę sobie jakiś widget, powiedzmy combo-box, który
> spełnia powyższe wymagania, to nie będę mógł, go przechowywać w std::list,
> bo pogwałcę Twoją teorię?

Nie. Bo jak wykonasz na nim algorytm std::remove, to zdrowo się zdziwisz, co
po tym powstało.

> >> >> > Jeśli mówimy już o rzeczywistości - podaj mi przykład obiektu z
> >> >> > rzeczywistości, który posiada jednocześnie wartość i tożsamość.
> >> > 
> >> >> Konto bankowe. Tożsamość: numer, wartość: saldo.
> >> > 
> >> > Oraz wartość: właściciel (można go potem kiedyś zmienić)
> >> > Oraz obiekt: historia transakcji
> >> > Oraz...
> > 
> >> Jak wyżej: zależy od kontekstu.
> > 
> > Nic nie zależy od żadnego kontekstu.
> > 
> > Saldo jest stanem (cząstkowym) konta. Saldo jest wartością. Konto jest
> > obiektem.

> Niepotrzebnie wiążesz terminy z życia (stan konta) z terminami
> informatycznymi (stan obiektu). Osobom z małym doświadczeniem to się
> często zdarza, nie przejmuj się.

Parafrazując, "Skończył się czas argumentów. Teraz jest czas inwektyw".

A może tak coś do tematu?

> >> Możemy nie wiązać obiektów transakcji do
> >> konta, a zrobić wiązanie odwrotne: każda transakcja ma referencję do
> >> konta.
> > 
> > Ale co to ma do rzeczy?

> To, że obiekt konto nie musi przechowywać historii, jeśli tylko zechcę tak
> to zamodelować.

No może, i nadal, co z tego?

> > 
> > Transakcja też jest obiektem, tzw. "wartość transakcji" jest atrybutem
> > obiektu transakcji, a ilość pieniędzy, na którą opiewa transakcja, jest
> > wartością.

> Otóż to!

No właśnie. Więc co tu może, a co nie może być wartością?

> >> I podobnie z właścicielem. Krótko mówiąc "konto jest anonimowe" i
> >> przechowuje jedynie swoje saldo (wartość) oraz numer (tożsamość).
> > 
> > Numer jest atrybutem obiektu (unikalnym, więc jest ściśle związany z
> > tożsamością), właściciel też jest obiektem (w bazie banku jest osobnym
> > obiektem, który może być podmapowany do kilku kont). Saldo jest stanem
> > konta, a wartość salda to ilość pieniędzy znajdujących się na koncie.

> Dlaczego "ilość" nie jest według Ciebie "wartością"?

Widzę, że całkiem się już pogubiłeś ;)

Oczywiście, że jest.

> >> > Czy ty w ogóle wiesz, co to jest "wartość"?
> > 
> >> Element ze zbioru (tu: typ, klasa).
> > 
> > To znaczy?

> Odsyłam do książki "Matematyka dla klas drugich".

Cóż, osobliwy masz wybór literatury do nauki programowania, ale to już nie
moja sprawa.


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15750
Author: Mariusz Lotko
Date: Thu, 15 Mar 2007 05:12
323 lines
14593 bytes
Sektor van Skijlen wrote:

>> > Swiss army knife to by było, gdyby ten portfel mógł przechowywać
>> > pieniądze, laptopy, meble, samochody, kontenery i elektrownie.
> 
>> Nie. Swiss army knife oznacza, że modelujesz wszystkie elementy
>> rzeczywistości czy tego wymaga system czy nie.
> 
> Nie wiem, jak ty, ale ja pojęcie "swiss army knife" znam jako jeden z
> błędów OO, który polega na stworzeniu klasy o zbyt dużym zakresie
> odpowiedzialności.

Ja też. Dlaczego uważasz, że modelowanie większej części rzeczywistości
od wymaganej nie jest "zbyt dużym zakresem odpowiedzialności"?

> Dokładność modelowania to zupełnie inna sprawa.

Inny będzie poziom szczegółowości klasy Samochód w kartotece
samochodów w Urzędzie Miasta, a inny w kartotece warsztatu
samochodowego.

Mój kolega jakiś czas temu wymyślił dobry polski odpowiednik
swiss army knife: "przydaś". Bierze się to z podejścia "przyda się,
zaimplementuję".

> Zresztą, jeśli dla ciebie programowanie obiektowe jest modelowaniem
> rzeczywistości, to obawiam się, że możemy naszą dyskusję wznowić za parę
> lat, jak będziesz już mówił językiem własnego doświadczenia, a nie
> książkowym.

I znowu założenia... Załóż przez chwilę, że nie jesteś jednak
nieomylny.

> (Na marginesie: to bardzo dobrze, że literatura do OO twierdzi, że
> programowanie obiektowe jest modelowaniem rzeczywistości. Tak bowiem
> należy tą sprawę tłumaczyć początkującym. Im więcej jednak człowiek
> programuje obiektowo, tym bardziej się przekonuje, że to nie ma nic
> wspólnego z prawdą. To jest jeden ze znaków rozpoznawczych, czy ktoś
> potrafi myśleć samodzielnie rzeczywiście dysponuje doświadczeniem
> zawodowym, czy recytuje z pamięci wiedzę książkową.)

Dla mnie odnoszenie się do rzeczywistości jest wygodną praktyką
w takich bezsensownych dyskusjach jak ta. Podobnie jak to się czyni
w literaturze. Niektórzy jednak przyjmują książkowe przykłady
za pewnik: "tak należy modelować rzeczywiste systemy". I to jest
rzeczywiście smutne.

> 
> Cofając jednak tą całą dygresję, którą nie wiem po co wprowadziłeś -
> podałem ci tylko przykład, dlaczego portfel nie może być typem
> wartościowym.
> 
> Jeśli nie zrozumiałeś nadal, to wytłumaczę ci bardziej łopatologicznie:
> portfel zawierający tyle samo pieniędzy, to nie ten sam portfel (mówię
> tak, bo twierdziłeś, że ilość pieniędzy może być wartością potrfela).

Może być. Jeśli zastanawiałbym się "czy to ten sam portfel" to rozważałbym
tożsamość a nie wartość portfela. Rozumiesz?

>> > Ilość pieniędzy nie jest wartością portfela. Jest jego stanem. Portfel
>> > nie może mieć wartości - i to nie dlatego, że poza tym może mieć
>> > jeszcze wiele innych stanów i atrytbutów.

Taki podałeś wcześniej argument. Dla mnie podział na obiekty wartościowe
i niewartościowe jest sztuczny, żeby nie powiedzieć nieistniejący, więc
nie dziw się, że opornie podążam za tą teorią.

>> Wychodząc z tego założenia stanem "obiektu" "klasy" int jest np. 2. Stan
>> ten można zmienić "funkcją" zmiany stanu, np. ++.
>> Kto z nas nie rozróżnia wartości od stanu?
> 
> int x = 2;
> int y = 2;
> 
> Powiedz mi teraz, czy "x jest y".

W C++? Nie. Odsyłam do Stroustrupa jakie mechanizmy tego języka tutaj
zadziałały, a przestaniesz zadawać takie pytania.

>> >> > Typem wartościowym może być kolor. Porównanie dwóch obiektów typu
>> >> > kolor można porównać ze sprawdzeniem, czy na dwóch kartkach papieru
>> >> > zapisany tam kod koloru jest ten sam. Ty chcesz, żeby przed
>> >> > odczytaniem numeru z każdej kartki najpierw sprawdzić, czy te obie
>> >> > kartki to czasem nie jest jedna i ta sama kartka. Jaki to ma sens?
>> > 
>> >> Idąc Twoją logiką: niekoniecznie. Obiekt kolor ma jeszcze atrybuty:
>> >> data naniesienia, technika wykonania i stopień nasłonecznienia, które
>> >> pozwalają obliczyć rzeczywisty kolor w czasie :> Wtedy nie da się
>> >> porównać dwóch "czerwonych". Odsyłam do ekspertów - lakierników
>> >> samochodowych.
>> > 
>> > Nie przypominam sobie, żebym mówił o lakierze samochodowym. Mówiłem o
>> > kolorze. Kolor może być również atrybutem (a nie wartością, acz
>> > przypadkiem też nie stanem) lakieru.
> 
>> Ja tylko poszedłem Twoją logiką. Zważ, że w systemie, o którym pisałem
>> przy portfelu nie wspominałem o istnieniu kart kredytowych.
> 
> Nie poszedłeś moją logiką. Mówiłem o kolorze, a ty wziąłeś sobie nie wiem
> po co lakier samochodowy.

Oj, lakier to już była taka wisienka na torcie. Każdy kolor płowieje
w rzeczywistości, a więc... (odsyłam parę akapitów wyżej).

> Podobnie typem wartościowym mogą być "pieniądze". Ale nie kieszeń,
> portfel, konto, sejf, czy gdzie to tam jeszcze chcesz przechowywać.
> 
>> > No to jak, zrozumiałeś już, co to takiego jest wartość, czy douczysz
>> > się i zgłosisz za tydzień?
> 
>> Do kogo miałbym się zgłosić?
> 
> No cóż, wydawało mi się, że każdy, kto studiował, słyszał to słynne
> określenie. W czymś się widać pomyliłem.

Nie mierz innych swoją miarą. Nie przypominam sobie, żeby któryś z
wykładowców musiał się w ten sposób nade mną litować.

> 
>> >> >> Z tym, że w obu przypadkach nie chodzi o "przykrą konieczność", a
>> >> >> o "wspaniałą możliwość" szybkiego stwierdzenia, że chodzi o "te
>> >> >> same" a więc na pewno "takie same" obiekty.
>> >> > 
>> >> > To jest przykra konieczność. Musisz to po prostu zrobić, bo inaczej
>> >> > będzie wylot.
>> > 
>> >> W operatorze porównania? Nie sądzę...
>> > 
>> > W operatorze przypisania.
> 
>> Co miałoby sprawić "wylot" w operatorze przypisania?
> 
> Sprawdzenie, czy nie przypisujemy samego siebie. Fakt, że musisz użyć
> operatora porównania dla tożsamości jest przykrą koniecznością, bo bez
> tego usunąłbyś część obiektu, z którego za chwilę masz zamiar czytać.

Zagadnienie pomocnicze

int a;

a = a;

Pytanie: co nastąpi wcześniej odczyt czy zapis wartości a?
Ponawiam pytanie podstawowe: jaki wylot masz na myśli?

> 
>> >> > Ta "wspaniała możliwość" z kolei powoduje droższe porównanie.
>> > 
>> >> W pewnych przypadkach może tak być.
>> > 
>> > Statystycznie jest to 99% przypadków.
> 
>> Statystycznie, to ja biję swoją żonę co miesiąc. Ty, jeśli jesteś żonaty
>> również. Takie szacunki trzeba robić dla konkretnych klas a nie
>> generalizować.
> 
> No widzisz. A ja mogę sobie pozwolić na generalizację.

Możesz. Ale nie wpieraj, że jest ona poprawna.

> Chodzi o bardzo prostą rzecz: jakiej wielkości jest zwykle typ
> wartościowy? Niewielkiej. Musi być niewielki, bo im większy, tym więcej
> zasobów zajmuje jego wartość, dłużej się kopiuje, a i porównanie wartości
> - dosć częsta operacja - trwa dość długo. Dlatego właśnie typy wartościowe
> robi się z założenia JAK NAJMNIEJSZE - właśnie po to, żeby te operacje
> były jak najszybsze. Skoro istnieje taka presja na obiekty wartościowe, to
> gdzie masz w takim razie pole dla obiektów, w których porównanie można
> "przyspieszyć" poprzez najpierw sprawdzanie tożsamości?

To jest przypadek szczególny a nie ogólny. Nie twierdzę jednak, że przypadek
odwrotny, czyli taki jest ogólny, uniwersalny i najlepszy.

> 
>> >> Implementując operator warto
>> >> oszacować prawdopodobieństwo porównywania tych samych obiektów.
>> > 
>> > Zrób sobie małą statystykę użycia takiego typu i ilość porównań, dla
>> > których trafiasz na równość i dla których trafiasz na nierówność.
>> > 
>> > Prosty przykład - iteratory. Masz pętlę, w której przechodzisz przez
>> (...)
>> > 
>> > Podałem ci tylko przykład, jak należy prowadzić taką analizę - to, że
>> > ten przykład jest negatywny dla twojej tezy, nie ma znaczenia. Myślę,
>> > że dałoby się znaleźć przykład, który by twoją tezę potwierdzał, ale to
>> > nie ma większego znaczenia.
> 
>> Nie będę ani analizował Twojego przykładu, ani mu zaprzeczał. Zakładam,
>> że jest słuszny. To jednak tylko przykład, z którego do sformułowania
>> reguły jeszcze daleko.
> 
> To był przykład wykonania analizy, który pokazał, że się nie opłaca. Czy
> jesteśw stanie podać mi kontrprzykład - czyli taki, który udowodni, że się
> opłaca?

Proponuję przypomnieć sobie na czym polegał _dowód_, a nie przykład
potwierdzający słuszność danego twierdzenia.

>> > W odróżnieniu od ciebie jednak, ja rozumiem konieczność wykonania
>> > analizy, która dowiedzie, czy to się nam opłaca, czy nie. Ty
>> > przyjmujesz "w ciemno", że sprawdzanie najpierw tożsamości będzie
>> > zawsze bardziej opłacalne. W ostateczności zgadzasz się nawet, że
>> > "najczęściej".

Jeśli przyjmowanie w ciemno to f(n), to jesteś zaledwie na etapie f(n)-1.
Warto było się napracować?

>> Ty dla odmiany uważasz, że najczęściej nie. Na razie jednak nie potrafisz
>> udowodnić dlaczego Twoja teza jest lepsza od mojej.
> 
> Potrafię, tylko ty nie potrafisz jej zrozumieć, albo uparcie zaprzeczasz
> faktom.

Nie zaprzeczam, tylko wskazuję, że są to zaledwie pojedyncze fakty, a nie
ogólna zależność. Nawet nie: nie zaprzeczam zależności, ale Twojemu
sposobowi pseudodowodzenia.

> Moja teza jest lepsza, bo jest oparta na rzetelnej analizie (nb. analiza
> Qrczaka również). Twoja teza, że to jest "oczywiste, że tak się powinno
> zawsze robić" nie jest poparta niczym.

Nic takiego nie napisałem. Oczywiste jest dla mnie, że nie zawsze powinno
się robić tak jak Ty piszesz.

>> > No to podaj mi przykład typu wartościowego, w którym to się opłaca, i
>> > oszacuj ilość porównań trafionych i nietrafionych w typowych
>> > algorytmach, które go używają. Wtedy będziemy wiedzieli, o czym
>> > rozmawiamy.
> 
>> Nie chodzi o sam typ, tylko kontekst użycia.
> 
> Brawo! Zatem słucham.

Użycie typu jako klucza w hash mapie.

>> >> Generalnie jednak - nie zgadzam się.
>> > 
>> > Ależ masz pełne prawo się nie zgadzać. Ja w odróżnieniu od ciebie
>> > potrafię to uzasadnić.
> 
>> W odróżnieniu od Ciebie unikam jednoznacznych stwierdzeń na temat swoich
>> umiejętności.
> 
> Z tą "oczywistością", że operator porównania powinien najpierw sprawdzić
> tożsamość, niespecjalnie ci to wyszło.

W większości przypadków, jeśli analiza wykaże, że się opłaca. Nie przekręcaj
moich słów.

>> > Przykładowo, typ przechowywany w std::list musi być typem wartościowym.
>> > Niestety, tak jest skonstruowany szablon std::list. Świadczą o tym
>> > następujące wymagania względem typu:
>> >  - przypisywalny
>> >  - kopiowalny
>> >  - domyślnie-konstruowalny
> 
>> Rozumiem, że jeśli stworzę sobie jakiś widget, powiedzmy combo-box, który
>> spełnia powyższe wymagania, to nie będę mógł, go przechowywać w
>> std::list, bo pogwałcę Twoją teorię?
> 
> Nie. Bo jak wykonasz na nim algorytm std::remove, to zdrowo się zdziwisz,
> co po tym powstało.

Nie pisałem nic o chęci użycia któregokolwiek z algorytmów.

>> >> >> > Jeśli mówimy już o rzeczywistości - podaj mi przykład obiektu z
>> >> >> > rzeczywistości, który posiada jednocześnie wartość i tożsamość.
>> >> > 
>> >> >> Konto bankowe. Tożsamość: numer, wartość: saldo.
>> >> > 
>> >> > Oraz wartość: właściciel (można go potem kiedyś zmienić)
>> >> > Oraz obiekt: historia transakcji
>> >> > Oraz...
>> > 
>> >> Jak wyżej: zależy od kontekstu.
>> > 
>> > Nic nie zależy od żadnego kontekstu.
>> > 
>> > Saldo jest stanem (cząstkowym) konta. Saldo jest wartością. Konto jest
>> > obiektem.
> 
>> Niepotrzebnie wiążesz terminy z życia (stan konta) z terminami
>> informatycznymi (stan obiektu). Osobom z małym doświadczeniem to się
>> często zdarza, nie przejmuj się.
> 
> Parafrazując, "Skończył się czas argumentów. Teraz jest czas inwektyw".

Trafiłem widzę na wrażliwca.

> A może tak coś do tematu?
> 
>> >> Możemy nie wiązać obiektów transakcji do
>> >> konta, a zrobić wiązanie odwrotne: każda transakcja ma referencję do
>> >> konta.
>> > 
>> > Ale co to ma do rzeczy?
> 
>> To, że obiekt konto nie musi przechowywać historii, jeśli tylko zechcę
>> tak to zamodelować.
> 
> No może, i nadal, co z tego?

Guzik. Polecam lecytynkę, bo nie pamiętasz już co napisałeś kilka postów
temu i dlaczego staram się uwalić pomysł, że konto _musi_ przechowywać to
tamto i sramto.

> 
>> >> > Czy ty w ogóle wiesz, co to jest "wartość"?
>> > 
>> >> Element ze zbioru (tu: typ, klasa).
>> > 
>> > To znaczy?
> 
>> Odsyłam do książki "Matematyka dla klas drugich".
> 
> Cóż, osobliwy masz wybór literatury do nauki programowania, ale to już nie
> moja sprawa.

Widzę, że pozycja, o której wspomniałem jest Ci obca. W przeciwnym razie
wiedziałbyś, że nie ma tam słowa o programowaniu.

-- 
Mariusz Lotko
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15751
Author: Sektor van Skijlen
Date: Fri, 16 Mar 2007 16:39
436 lines
20230 bytes
Dnia Thu, 15 Mar 2007 06:12:44 +0100, Mariusz Lotko skrobie:
> Sektor van Skijlen wrote:

> >> > Swiss army knife to by było, gdyby ten portfel mógł przechowywać
> >> > pieniądze, laptopy, meble, samochody, kontenery i elektrownie.
> > 
> >> Nie. Swiss army knife oznacza, że modelujesz wszystkie elementy
> >> rzeczywistości czy tego wymaga system czy nie.
> > 
> > Nie wiem, jak ty, ale ja pojęcie "swiss army knife" znam jako jeden z
> > błędów OO, który polega na stworzeniu klasy o zbyt dużym zakresie
> > odpowiedzialności.

> Ja też. Dlaczego uważasz, że modelowanie większej części rzeczywistości
> od wymaganej nie jest "zbyt dużym zakresem odpowiedzialności"?

Bo odpowiedzialność jest jedna, niezależnie od dokładności modelowania.

> > Dokładność modelowania to zupełnie inna sprawa.

> Inny będzie poziom szczegółowości klasy Samochód w kartotece
> samochodów w Urzędzie Miasta, a inny w kartotece warsztatu
> samochodowego.

To nie ma znaczenia.

> > Zresztą, jeśli dla ciebie programowanie obiektowe jest modelowaniem
> > rzeczywistości, to obawiam się, że możemy naszą dyskusję wznowić za parę
> > lat, jak będziesz już mówił językiem własnego doświadczenia, a nie
> > książkowym.

> I znowu założenia... Załóż przez chwilę, że nie jesteś jednak
> nieomylny.

Ja tylko stwierdzam fakt.

> > (Na marginesie: to bardzo dobrze, że literatura do OO twierdzi, że
> > programowanie obiektowe jest modelowaniem rzeczywistości. Tak bowiem
> > należy tą sprawę tłumaczyć początkującym. Im więcej jednak człowiek
> > programuje obiektowo, tym bardziej się przekonuje, że to nie ma nic
> > wspólnego z prawdą. To jest jeden ze znaków rozpoznawczych, czy ktoś
> > potrafi myśleć samodzielnie rzeczywiście dysponuje doświadczeniem
> > zawodowym, czy recytuje z pamięci wiedzę książkową.)

> Dla mnie odnoszenie się do rzeczywistości jest wygodną praktyką
> w takich bezsensownych dyskusjach jak ta.

Wygodną, ale niekoniecznie właściwą. Bo wiele systemów i szczegółów
definicyjnych nie posiada odniesienia w rzeczywistości. Można więc
rzeczywistość przywoływać dla porównania ("przypowieści"), ale nie do
dowodzenia.

> > Cofając jednak tą całą dygresję, którą nie wiem po co wprowadziłeś -
> > podałem ci tylko przykład, dlaczego portfel nie może być typem
> > wartościowym.
> > 
> > Jeśli nie zrozumiałeś nadal, to wytłumaczę ci bardziej łopatologicznie:
> > portfel zawierający tyle samo pieniędzy, to nie ten sam portfel (mówię
> > tak, bo twierdziłeś, że ilość pieniędzy może być wartością potrfela).

> Może być. Jeśli zastanawiałbym się "czy to ten sam portfel" to rozważałbym
> tożsamość a nie wartość portfela. Rozumiesz?

To ty nie rozumiesz.

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.

> >> > Ilość pieniędzy nie jest wartością portfela. Jest jego stanem. Portfel
> >> > nie może mieć wartości - i to nie dlatego, że poza tym może mieć
> >> > jeszcze wiele innych stanów i atrytbutów.

> Taki podałeś wcześniej argument. Dla mnie podział na obiekty wartościowe
> i niewartościowe jest sztuczny, żeby nie powiedzieć nieistniejący, więc
> nie dziw się, że opornie podążam za tą teorią.

To jest wyjaśnienie, nie argument. Jeśli jesteś betonowy na tą teorię, to ja
ci nic nie poradzę. Nie powiem, żeby mnie to martwiło.

> >> Wychodząc z tego założenia stanem "obiektu" "klasy" int jest np. 2. Stan
> >> ten można zmienić "funkcją" zmiany stanu, np. ++.
> >> Kto z nas nie rozróżnia wartości od stanu?
> > 
> > int x = 2;
> > int y = 2;
> > 
> > Powiedz mi teraz, czy "x jest y".

> W C++? Nie. Odsyłam do Stroustrupa jakie mechanizmy tego języka tutaj
> zadziałały, a przestaniesz zadawać takie pytania.

No i jakie twoim zdaniem mechanizmy języka tu zadziałały?

Oczywiście, że x to jest y. Dowód:

int f( int ); // dowolna funkcja deterministyczna i bezstanowa
f( x ) == f( y ) // zawsze prawdziwe

> >> >> > Typem wartościowym może być kolor. Porównanie dwóch obiektów typu
> >> >> > kolor można porównać ze sprawdzeniem, czy na dwóch kartkach papieru
> >> >> > zapisany tam kod koloru jest ten sam. Ty chcesz, żeby przed
> >> >> > odczytaniem numeru z każdej kartki najpierw sprawdzić, czy te obie
> >> >> > kartki to czasem nie jest jedna i ta sama kartka. Jaki to ma sens?
> >> > 
> >> >> Idąc Twoją logiką: niekoniecznie. Obiekt kolor ma jeszcze atrybuty:
> >> >> data naniesienia, technika wykonania i stopień nasłonecznienia, które
> >> >> pozwalają obliczyć rzeczywisty kolor w czasie :> Wtedy nie da się
> >> >> porównać dwóch "czerwonych". Odsyłam do ekspertów - lakierników
> >> >> samochodowych.
> >> > 
> >> > Nie przypominam sobie, żebym mówił o lakierze samochodowym. Mówiłem o
> >> > kolorze. Kolor może być również atrybutem (a nie wartością, acz
> >> > przypadkiem też nie stanem) lakieru.
> > 
> >> Ja tylko poszedłem Twoją logiką. Zważ, że w systemie, o którym pisałem
> >> przy portfelu nie wspominałem o istnieniu kart kredytowych.
> > 
> > Nie poszedłeś moją logiką. Mówiłem o kolorze, a ty wziąłeś sobie nie wiem
> > po co lakier samochodowy.

> Oj, lakier to już była taka wisienka na torcie.

Jasne, bagatelizuj i konfabuluj, bo żadne argumenty ci już nie zostały.

> Każdy kolor płowieje
> w rzeczywistości, a więc... (odsyłam parę akapitów wyżej).

Kolory nie płowieją. Płowieją substancje kolorujące, czyli zmieniają one
kolory.

Już widzę, z czym masz problem. Ty przede wszystkim nie wiesz, czym jest
kolor, albo czym jest liczba. Skoro tak, to nigdy nie zrozumiesz, co to
takiego typ wartościowy.

> > Podobnie typem wartościowym mogą być "pieniądze". Ale nie kieszeń,
> > portfel, konto, sejf, czy gdzie to tam jeszcze chcesz przechowywać.
> > 
> >> > No to jak, zrozumiałeś już, co to takiego jest wartość, czy douczysz
> >> > się i zgłosisz za tydzień?
> > 
> >> Do kogo miałbym się zgłosić?
> > 
> > No cóż, wydawało mi się, że każdy, kto studiował, słyszał to słynne
> > określenie. W czymś się widać pomyliłem.

> Nie mierz innych swoją miarą. Nie przypominam sobie, żeby któryś z
> wykładowców musiał się w ten sposób nade mną litować.

Zależy na jakiej uczelni studiowałeś.

> >> >> >> Z tym, że w obu przypadkach nie chodzi o "przykrą konieczność", a
> >> >> >> o "wspaniałą możliwość" szybkiego stwierdzenia, że chodzi o "te
> >> >> >> same" a więc na pewno "takie same" obiekty.
> >> >> > 
> >> >> > To jest przykra konieczność. Musisz to po prostu zrobić, bo inaczej
> >> >> > będzie wylot.
> >> > 
> >> >> W operatorze porównania? Nie sądzę...
> >> > 
> >> > W operatorze przypisania.
> > 
> >> Co miałoby sprawić "wylot" w operatorze przypisania?
> > 
> > Sprawdzenie, czy nie przypisujemy samego siebie. Fakt, że musisz użyć
> > operatora porównania dla tożsamości jest przykrą koniecznością, bo bez
> > tego usunąłbyś część obiektu, z którego za chwilę masz zamiar czytać.

> Zagadnienie pomocnicze

> int a;

> a = a;

> Pytanie: co nastąpi wcześniej odczyt czy zapis wartości a?
> Ponawiam pytanie podstawowe: jaki wylot masz na myśli?

W ogólności zależy to od definicji operatora przypisania.

W przypadku int argument przyjmowany jest przez wartość. Ale to nie musi być
reguła, nawet dla typów wartościowych. Np. std::string jest typem
wartościowym, a jego operator przypisania przyjmuje argument przez referencję.
I wtedy musisz sprawdzić.

> >> >> > Ta "wspaniała możliwość" z kolei powoduje droższe porównanie.
> >> > 
> >> >> W pewnych przypadkach może tak być.
> >> > 
> >> > Statystycznie jest to 99% przypadków.
> > 
> >> Statystycznie, to ja biję swoją żonę co miesiąc. Ty, jeśli jesteś żonaty
> >> również. Takie szacunki trzeba robić dla konkretnych klas a nie
> >> generalizować.
> > 
> > No widzisz. A ja mogę sobie pozwolić na generalizację.

> Możesz. Ale nie wpieraj, że jest ona poprawna.

Nie wpieram, tylko twierdzę.

> > Chodzi o bardzo prostą rzecz: jakiej wielkości jest zwykle typ
> > wartościowy? Niewielkiej. Musi być niewielki, bo im większy, tym więcej
> > zasobów zajmuje jego wartość, dłużej się kopiuje, a i porównanie wartości
> > - dosć częsta operacja - trwa dość długo. Dlatego właśnie typy wartościowe
> > robi się z założenia JAK NAJMNIEJSZE - właśnie po to, żeby te operacje
> > były jak najszybsze. Skoro istnieje taka presja na obiekty wartościowe, to
> > gdzie masz w takim razie pole dla obiektów, w których porównanie można
> > "przyspieszyć" poprzez najpierw sprawdzanie tożsamości?

> To jest przypadek szczególny a nie ogólny. Nie twierdzę jednak, że przypadek
> odwrotny, czyli taki jest ogólny, uniwersalny i najlepszy.

Zgadza się - bo takiego tutaj nie ma. Wszystkie przypadki tutaj są szczególne.

Ale przypadek, o którym ja wspomniałem, mimo szczególności, występuje w
przeważającej większości sytuacji, a to, co ty podałeś, jest akurat do niego
odwrotny - co w zupełności nie przeszkadza ci twierdzić, że jest przypadkiem
ogólnym.

> >> >> Implementując operator warto
> >> >> oszacować prawdopodobieństwo porównywania tych samych obiektów.
> >> > 
> >> > Zrób sobie małą statystykę użycia takiego typu i ilość porównań, dla
> >> > których trafiasz na równość i dla których trafiasz na nierówność.
> >> > 
> >> > Prosty przykład - iteratory. Masz pętlę, w której przechodzisz przez
> >> (...)
> >> > 
> >> > Podałem ci tylko przykład, jak należy prowadzić taką analizę - to, że
> >> > ten przykład jest negatywny dla twojej tezy, nie ma znaczenia. Myślę,
> >> > że dałoby się znaleźć przykład, który by twoją tezę potwierdzał, ale to
> >> > nie ma większego znaczenia.
> > 
> >> Nie będę ani analizował Twojego przykładu, ani mu zaprzeczał. Zakładam,
> >> że jest słuszny. To jednak tylko przykład, z którego do sformułowania
> >> reguły jeszcze daleko.
> > 
> > To był przykład wykonania analizy, który pokazał, że się nie opłaca. Czy
> > jesteśw stanie podać mi kontrprzykład - czyli taki, który udowodni, że się
> > opłaca?

> Proponuję przypomnieć sobie na czym polegał _dowód_, a nie przykład
> potwierdzający słuszność danego twierdzenia.

Nie przypominam sobie żadnego dowodu.

> >> > W odróżnieniu od ciebie jednak, ja rozumiem konieczność wykonania
> >> > analizy, która dowiedzie, czy to się nam opłaca, czy nie. Ty
> >> > przyjmujesz "w ciemno", że sprawdzanie najpierw tożsamości będzie
> >> > zawsze bardziej opłacalne. W ostateczności zgadzasz się nawet, że
> >> > "najczęściej".

> Jeśli przyjmowanie w ciemno to f(n), to jesteś zaledwie na etapie f(n)-1.
> Warto było się napracować?

A jesteś w stanie to udowodnić? To słucham.

> >> Ty dla odmiany uważasz, że najczęściej nie. Na razie jednak nie potrafisz
> >> udowodnić dlaczego Twoja teza jest lepsza od mojej.
> > 
> > Potrafię, tylko ty nie potrafisz jej zrozumieć, albo uparcie zaprzeczasz
> > faktom.

> Nie zaprzeczam, tylko wskazuję, że są to zaledwie pojedyncze fakty, a nie
> ogólna zależność. Nawet nie: nie zaprzeczam zależności, ale Twojemu
> sposobowi pseudodowodzenia.

To nie jest dowód, a przedstawiona teoria nie jest zależnością.

Jest to tylko stwierdzenie poprawne w statystycznej większości przypadków -
ale to nie ma znaczenia. Ty uparcie twierdzisz, że odwrotne postępowanie jest
przypadkiem ogólnym, więc w ogólności żeby twoje bzdury obalić wystarczy mi
podać jeden przykład. Fakt, że ten przykład reprezentuje większość
statystyczną nie ma tu nawet znaczenia.

> > Moja teza jest lepsza, bo jest oparta na rzetelnej analizie (nb. analiza
> > Qrczaka również). Twoja teza, że to jest "oczywiste, że tak się powinno
> > zawsze robić" nie jest poparta niczym.

> Nic takiego nie napisałem. Oczywiste jest dla mnie, że nie zawsze powinno
> się robić tak jak Ty piszesz.

Dobra, dyskusja zaczyna mi się nudzić, skoro zaczynasz zaprzeczać swoim
niedawnym stanowczym wypowiedziom (równie stanowczo zresztą).

> >> > No to podaj mi przykład typu wartościowego, w którym to się opłaca, i
> >> > oszacuj ilość porównań trafionych i nietrafionych w typowych
> >> > algorytmach, które go używają. Wtedy będziemy wiedzieli, o czym
> >> > rozmawiamy.
> > 
> >> Nie chodzi o sam typ, tylko kontekst użycia.
> > 
> > Brawo! Zatem słucham.

> Użycie typu jako klucza w hash mapie.

No fajnie - czyli, jak rozumiem, masz taki klucz, którego porównanie z
istniejącym zaczynasz od sprawdzenia tożsamości klucza? No dobrze. Jak zatem
wygląda definicja typu klucza?

> >> >> Generalnie jednak - nie zgadzam się.
> >> > 
> >> > Ależ masz pełne prawo się nie zgadzać. Ja w odróżnieniu od ciebie
> >> > potrafię to uzasadnić.
> > 
> >> W odróżnieniu od Ciebie unikam jednoznacznych stwierdzeń na temat swoich
> >> umiejętności.
> > 
> > Z tą "oczywistością", że operator porównania powinien najpierw sprawdzić
> > tożsamość, niespecjalnie ci to wyszło.

> W większości przypadków, jeśli analiza wykaże, że się opłaca. Nie przekręcaj
> moich słów.

O analizie to dopiero ja zacząłem mówić, więc nie wmawiaj, że cokolwiek
takiego twierdziłeś.

Jestem i tak za leniwy, żeby zajrzeć do wcześniejszych wiadomości i
skompromitować cię twoimi wcześniejszymi wypowiedziami.

Poza tym, podoba mi się to: w większości przypadków, jeśli analiza wykaże, że
się opłaca. Super. Analiza może wykazać, że w 90% przypadków się nie opłaca,
ale to i tak te 10% to będzie dla ciebie większość.

> >> > Przykładowo, typ przechowywany w std::list musi być typem wartościowym.
> >> > Niestety, tak jest skonstruowany szablon std::list. Świadczą o tym
> >> > następujące wymagania względem typu:
> >> >  - przypisywalny
> >> >  - kopiowalny
> >> >  - domyślnie-konstruowalny
> > 
> >> Rozumiem, że jeśli stworzę sobie jakiś widget, powiedzmy combo-box, który
> >> spełnia powyższe wymagania, to nie będę mógł, go przechowywać w
> >> std::list, bo pogwałcę Twoją teorię?
> > 
> > Nie. Bo jak wykonasz na nim algorytm std::remove, to zdrowo się zdziwisz,
> > co po tym powstało.

> Nie pisałem nic o chęci użycia któregokolwiek z algorytmów.

Dobrze, zrób sobie cokolwiek - nawet sortowanie (sortowanie listy jest
algorytmem wewnętrznym listy, a nie ogólnym), scalanie z inną listą, czy
cokolwiek innego.

Pomijając już fakt, jak zamierzasz określić "kopiowalność" widżetu, oraz jak
zamierzasz określić jego porównywalność (potrzebną do find) i porządkowalność
(potrzebną do sort).

W różnych przypadkach, przy różnych operacjach, funkcje operujące na liście
potrafią ci skopiować określony obiekt, przechować kopię w obiekcie
tymczasowym i wrzucić do listy, a stary usunąć - tak właśnie działa np.
sortowanie, czy odwracanie (w szczególności wszystkie algorytmy zmieniające, w
tym również algorytmy zaimplementowane jako metody listy).

> >> >> >> > Jeśli mówimy już o rzeczywistości - podaj mi przykład obiektu z
> >> >> >> > rzeczywistości, który posiada jednocześnie wartość i tożsamość.
> >> >> > 
> >> >> >> Konto bankowe. Tożsamość: numer, wartość: saldo.
> >> >> > 
> >> >> > Oraz wartość: właściciel (można go potem kiedyś zmienić)
> >> >> > Oraz obiekt: historia transakcji
> >> >> > Oraz...
> >> > 
> >> >> Jak wyżej: zależy od kontekstu.
> >> > 
> >> > Nic nie zależy od żadnego kontekstu.
> >> > 
> >> > Saldo jest stanem (cząstkowym) konta. Saldo jest wartością. Konto jest
> >> > obiektem.
> > 
> >> Niepotrzebnie wiążesz terminy z życia (stan konta) z terminami
> >> informatycznymi (stan obiektu). Osobom z małym doświadczeniem to się
> >> często zdarza, nie przejmuj się.
> > 
> > Parafrazując, "Skończył się czas argumentów. Teraz jest czas inwektyw".

> Trafiłem widzę na wrażliwca.

A ja, jak widzę, trafiłem na kogoś zakompleksionego, kto musi się
dowartościować przez pomiatanie innymi.

> > A może tak coś do tematu?

Czyli, jak rozumiem, nie masz nic do powiedzenia "do tematu"?

> >> >> Możemy nie wiązać obiektów transakcji do
> >> >> konta, a zrobić wiązanie odwrotne: każda transakcja ma referencję do
> >> >> konta.
> >> > 
> >> > Ale co to ma do rzeczy?
> > 
> >> To, że obiekt konto nie musi przechowywać historii, jeśli tylko zechcę
> >> tak to zamodelować.
> > 
> > No może, i nadal, co z tego?

> Guzik. Polecam lecytynkę, bo nie pamiętasz już co napisałeś kilka postów
> temu i dlaczego staram się uwalić pomysł, że konto _musi_ przechowywać to
> tamto i sramto.

No ok. I nadal, co z tego?

Czy chcesz może dojść do tego, żeby konto nie przechowywało niczego, co nie
jest niezbędne, żeby mogło być typem wartościowym? Już ci powiedziałem: konto
nie będzie nigdy typem wartościowym, żebyś się nawet zesrał.

> >> >> > Czy ty w ogóle wiesz, co to jest "wartość"?
> >> > 
> >> >> Element ze zbioru (tu: typ, klasa).
> >> > 
> >> > To znaczy?
> > 
> >> Odsyłam do książki "Matematyka dla klas drugich".
> > 
> > Cóż, osobliwy masz wybór literatury do nauki programowania, ale to już nie
> > moja sprawa.

> Widzę, że pozycja, o której wspomniałem jest Ci obca. W przeciwnym razie
> wiedziałbyś, że nie ma tam słowa o programowaniu.

Jest mi, owszem, obca. Kiedy ja chodziłem do "klasy drugiej", ta pozycja
nazywała się inaczej.


Mógłbym się jeszcze trochę na tobie powyżywać, bo póki co rozmowa z tobą nadal
mnie bawi, ale spróbujmy wrócić do tematu - im bliżej tematu tym zawsze się
bardziej kompromitujesz.

No więc, co to takiego jest "wartość"?


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15752
Author: SasQ
Date: Fri, 16 Mar 2007 21:49
52 lines
3102 bytes
Dnia Fri, 16 Mar 2007 16:39:31 +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?

> Nic nie zależy od żadnego kontekstu.
>
> Saldo jest stanem (cząstkowym) konta. Saldo jest wartością.
> Konto jest obiektem.

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 ;) W przypadku tego konta to akurat
da się sprawy rozdzielić:

   if (konto1.saldo==konto2.saldo) //porównanie wartości
   if (konto1==konto2) //porównanie tożsamości

chyba że ktoś dla wygody przeładuje sobie operator== żeby
działał jako porównanie składników saldo ;)
Ale już np. dla typu int z twojego przykładu:

>   int x = 2;
>   int y = 2;
>
> Powiedz mi teraz, czy "x jest y".

sprawa nie jest taka prosta ;)  bo tutaj porównując x i y
w taki sposób:

   if (x==y) ...

porównujesz wartości. Jeśli chodzi ci o tożsamość, to już
trzeba by zapisać to np. tak:

   if (&x == &y) ...

i wtedy już wiadomo, czy "x jest y" ;)

Nie wiem tylko, czy dobrze rozumiem to, co próbujesz
wytłumaczyć, bo już się pogubiłem w tej całej dyskusji... :/

-- 
SasQ
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15753
Author: Sektor van Skijlen
Date: Sun, 18 Mar 2007 23:11
161 lines
7940 bytes
Dnia Fri, 16 Mar 2007 22:49:45 +0100, SasQ skrobie:
> Dnia Fri, 16 Mar 2007 16:39:31 +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
(pomijając już bezsens porównywania dwóch stanów z dwóch różnych obiektów, ale
to tak na marginesie).

if ( portfel1 == portfel2 ) // czy to ten sam portfel

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.

Powtarzam: typ jest wartościowy wtedy (i tylko wtedy), gdy tożsamość poznajemy
po jego wartości. 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.

> > Nic nie zależy od żadnego kontekstu.
> >
> > Saldo jest stanem (cząstkowym) konta. Saldo jest wartością.
> > Konto jest obiektem.

> 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?

> W przypadku tego konta to akurat
> da się sprawy rozdzielić:

>    if (konto1.saldo==konto2.saldo) //porównanie wartości
>    if (konto1==konto2) //porównanie tożsamości

Zgadza się - z drobną poprawką: pierwsze to porównanie wartości salda obu kont
(a nie porównanie wartości obu kont).

> chyba że ktoś dla wygody przeładuje sobie operator== żeby
> działał jako porównanie składników saldo ;)

Za takie PRZEŁADOWANIE to chętnie bym komuś PRZYŁADOWAŁ.

Ale nawet to nie spowodowałoby, że nagle konto staje się typem wartościowym.

Typ wartościowy zyskuje tożsamość przez wartość. Przypisanie zatem powoduje,
że obiekt po lewej staje się tym samym, co obiekt o poprawej, co można też
sprawdzić operatorem ==. Przekazanie obiektu jest również przekazaniem
warości.

> Ale już np. dla typu int z twojego przykładu:

> >   int x = 2;
> >   int y = 2;
> >
> > Powiedz mi teraz, czy "x jest y".

> sprawa nie jest taka prosta ;)  bo tutaj porównując x i y
> w taki sposób:

>    if (x==y) ...

> porównujesz wartości.

Zgadza się!

> Jeśli chodzi ci o tożsamość,

Tożsamość w typach wartościowych określamy jako tożsamość wartości.

> to już trzeba by zapisać to np. tak:

>    if (&x == &y) ...

> i wtedy już wiadomo, czy "x jest y" ;)

I w których operacjach wynik tego porównania ma znaczenie, a w których nie ma?

> Nie wiem tylko, czy dobrze rozumiem to, co próbujesz
> wytłumaczyć, bo już się pogubiłem w tej całej dyskusji... :/

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 (jeśli już, to jest to kwestia ściśle techniczna określonego
języka).

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.

Cała istota sprawy polega na tym, co się dzieje, jeśli obiekt jest
modyfikowany. Jeśli np. mamy dwa identyfikatory a i b:

a = get(1);
b = a;

Fakt, że a == b po czymś takim jest spełniony zarówno dla typów wartościowych,
jak i obiektowych (z tym, że w przypadku typów obiektowych a i b są
referencjami, a więc również typami wartościowymi).

Ale jeśli nastąpi modyfikacja obiektu poprzez 'b', to wtedy:
 - w przypadku obiektów wartościowych, 'a' pozostaje przy starej wartości
 - w przypadku obiektów niewartościowych, obiekt określany przez 'a' zmieni
   się również, jest bowiem tym samym obiektem, co 'b'

W językach, które naturalnie wspierają typy wartościowe, obiekty typów
wartościowych mogą mieć taki interfejs, który albo zawsze tworzy oddzielną
kopię w przypadku przypisania, albo jeśli współdzieli jakiś obiekt z innym
obiektem tego typu, to modyfikacja powoduje zakończenie współdzielenia i
wykonanie własnej, oddzielnej kopii. Tylko w takich językach mogą istnieć
modyfikowalne typy wartościowe; w innych językach mogą istnieć tylko
niezmienialne obiekty wartościowe, więc modyfikacja może polegać tylko na
stworzeniu nowej wartości.


Oczywiście teorię typów wartościowych i niewartościowych (co ciekawe, te
terminy pojawiają się w coraz większej ilości różnych niezwiązanych ze sobą
dokumentacji, ostatnio widziałem bodajże w dokumentacji do Qt) można olać,
jeśli ktoś uważa, że mu nie pasuje. Tylko że alternatywą jest stwierdzenie, że
mamy kilka różnych definicji porównania, kopiowanie płytkie i głębokie itd. -
jeśli komuś to bardziej odpowiada, to proszę bardzo.

Nawiasem mówiąc, w Rubym spierdzielili sprawę ze stringami totalnie. String w
ogólności jest typem wartościowym - niestety w Rubym jest on ehm... takim
dziwnie-hybrydowym. To znaczy, modyfikacje przenoszą się na inne obiekty
oznaczane identyfikatorami:

a = "dupa"
b = a
b[0] = "p"
print a

Ciekaw jestem, czy istnieje w Rubym jakaś możliwość wymuszenia skopiowania.

Ale porównanie z kolei porównuje zawartość stringa.


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15754
Author: SasQ
Date: Mon, 19 Mar 2007 01:18
222 lines
9875 bytes
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.
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? :>

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].
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) ...

> (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 :|

> 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?

> 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.

Hmm... a jak to jest z referencjami i wskaźnikami?
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.

> 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?

>> 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
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

>> Jeśli chodzi ci o tożsamość, to już trzeba by zapisać to
>> np. tak:
>>
>>    if (&x == &y) ...
>>
>> i wtedy już wiadomo, czy "x jest y" ;)
>
> I w których operacjach wynik tego porównania ma znaczenie,
> a w których nie ma?

Nie rozumiem pytania :|

> 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.

> 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.
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]

> 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 ;)

> Oczywiście teorię typów wartościowych i niewartościowych [...]
> można olać, jeśli ktoś uważa, że mu nie pasuje. Tylko że
> alternatywą jest stwierdzenie, że mamy kilka różnych definicji
> porównania, kopiowanie płytkie i głębokie itd.

Mógłbyś uściślić na czym polega związek typów wartościowych
z płytkim/głębokim kopiowaniem?

> Nawiasem mówiąc, w Rubym spierdzielili sprawę ze stringami
> totalnie. String w ogólności jest typem wartościowym - niestety
> w Rubym jest on ehm... takim dziwnie-hybrydowym. To znaczy,
> modyfikacje przenoszą się na inne obiekty oznaczane
> identyfikatorami:
>
> a = "dupa"
> b = a
> b[0] = "p"
> print a

A czy w Javie przypadkiem nie jest tak samo?
No chyba że tam się wtedy robi kopia przy modyfikacji przez b.
Już nie pamiętam...

-- 
SasQ
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15755
Author: Sektor van Skijlen
Date: Tue, 20 Mar 2007 18:03
352 lines
17093 bytes
Dnia Mon, 19 Mar 2007 02:18:29 +0100, SasQ skrobie:
> > 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 :)

No, mniej więcej o to chodzi.

Oczywiście i tak w efekcie wszystko można po części sprowadzić do absurdu, ale
jedna rzecz i tak zawsze będzie zachowana: obiekty typów wartościowych zawsze
mają swoją własną kopię zawartości.

>   if (moj.zawartosc == twoj.zawartosc) ...

> > (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 :|

Jaki jest sens sprawdzania, czy dwa portfele zawierają tyle samo pieniędzy?

Można, tylko po co? Jeśli już, to chcemy sprawdzić, czy np. w portfelu jest
"wystarczająca ilość" pieniędzy.

Możemy nawet na upartego zrobić coś takiego (opiszę to już bardziej
abstrakcyjnie): chcemy "zbalansować" jakieś stany z dwóch obiektów, pod
warunkiem, że opisująone jakąś ilość. Chcemy więc sprawdzić, czy któryś z nich
ma wartość większą niż drugi. Ale robimy to w tym celu, że chcemy wykonać
równomierne rozłożenie wartości w obu obiektach, więc i tak zamiast robić
jakieś porównania, to odejmujemy wartości od siebie.

W większości przypadków zaś, sprawdzenie stanu polega na porównaniu go z jakąś
istniejącą wartością, może stałą, może też z innym stanem, który wyznacza,
powiedzmy, wymagany "poziom" stanów - chociaż też tam zwykle się używa
operatora <, a nie ==.

Ja wiem, że teoretycznie może taka sytuacja istnieć, ale skoro jest ona taka
unikalna, to nie ma co mówić o typowości takiego porównania - jest ono właśnie
czymś bardzo nietypowym.

> > 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?

I tak zwykle tak właśnie jest. I nawet opłaca się takie coś opakować w
strukturę z bardzo istotnego powodu: w ten sposób można dostosować do takiego
konta różne inne elementy definicji typu. W przeciwnym razie za każdym razem
trzeba pamiętać, żeby operację wykonać poprawnie.

> > 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.

Ciepło, ale to stwierdzenie jest nieprecyzyjne. Bo co uważamy za typ
podstawowy?

> Hmm... a jak to jest z referencjami i wskaźnikami?

Referencje - jeśli chodzi o C++ - to jest akurat taki dość wyjątkowy typ. W
zasadzie to nawet nie powinien być uważany za oddzielny typ. Jest to
podstawowa forma, w jakiej istnieje każdy obiekt określany symbolem i oznacza
coś, co ma swoje odwzorowanie w pamięci. Wskaźnik na to coś wskazuje.
I wskaźnik już jest typem wartościowym.

> 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.

No właśnie... widzisz, chodzi tutaj o to, że string w sposób naturalny jest
typem wartościowym i jak się porównuje stringi, to nigdy nikomu nie chodzi o
porównanie ich tożsamości.

Tu problem polega na tym, że w C nie myślano o specjalizowanym zastosowaniu
operatora ==, a tekst w cudzysłowiu jest tylko uproszczonym zapisem tablicy z
zerem na końcu (a po nim przejął to tak C++).

> > 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?

No, gdyby portfel z tą samą ilością pieniędzy był zawsze tym samym
portfelem... tyle że wtedy portfel byłby powiązany z wartością.

W Smalltalku na przykład istnieje coś takiego jak "symbol", który jest
specjalną formą napisu. Niby to samo, ale różni się tym, że każdy symbol jest
unikalny. To oznacza, że jak napiszesz nazwę symbolu, który już istnieje, to
ten istniejący zostanie znaleziony i zwrócony. W takim przypadku nie ma w
całym systemie dwóch obiektów typu symbol o tej samej zawartości. W takiej
sytuacji - zauważ - porównanie tożsamości daje zawsze ten sam wynik, co
porównanie zawartości.

Ale ogólnie jest to podyktowane odpowiednimi właściwościami, szczególnie
pojęć, jakie tworzysz w projekcie programu.

Podawałem przykład "salda" i "koloru" jako typów wartościowych. Chodzi o
podobieństwo do tych typów, i co np. jest dla ciebie tym samym. Co to znaczy,
że "kolor jest ten sam", co znaczy "saldo jest to samo", a co znaczy z kolei
"portfel jest ten sam"?

A jeśli i tak nie wiesz, to najprościej stwierdzić to w ten sposób:

Utwórz a
b = a
Zmodyfikuj b

Jeśli spodziewasz się, że po takim czymś 'a' powinno zostać zmodyfikowane, to
jest to typ obiektowy.

Typy obiektowe poza tym często posiadają powiązania. Powiązania te często
powodują nawet, że nie da się ich klonować. Typy wartościowe nigdy nie
posiadają powiązań.

> >> 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."

Względem języka tak. Ale fizycznie one nie muszą istnieć.

> A teraz mi tu siejesz trwogę, że są "gołymi" wartościami
> nie trzymanymi nigdzie? :P

W praktyce tak :)

Nie no, formalnie to one oczywiście są obiektami stałymi, a także jest prawdą,
że do przechowywania wartości jakiś obiekt musi być. Ale ten obiekt jest
traktowany wyłącznie instrumeentalnie.

> 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

No są. W programie ;)

Tzn. dokładnie to jest tak: formalnie, to są obiekty stałe. Tzn. jeszcze
inaczej: to MOGĄ BYĆ obiekty stałe. Problem po prostu polega na tym, że co
prawda C++ pozwala ci zrobić tak:

const int& a = 5, & b = 5;

A nawet tak:

if ( &a == &b )

Ale to porównanie nie zwróci ci żadnej sensownej informacji. Może ci zwrócić
true, może ci zwrócić false. No dobrze, jeśli tym stałym nadasz różne
wartości, to wtedy powinno ci zawsze zwrócić false ;)

Literał zapisany w języku sam z siebie jest jedynie wartością. Dopiero gdy
zostanie użyty, może się z niego zrobić obiekt - ale dopiero gdy zostanie
użyty jako obiekt i dopiero w miejscu, w którym będzie użyty jako obiekt tym
obiektem będzie. Wcześniej jest tylko zapisem w programie.

> >> Jeśli chodzi ci o tożsamość, to już trzeba by zapisać to
> >> np. tak:
> >>
> >>    if (&x == &y) ...
> >>
> >> i wtedy już wiadomo, czy "x jest y" ;)
> >
> > I w których operacjach wynik tego porównania ma znaczenie,
> > a w których nie ma?

> Nie rozumiem pytania :|

Pytanie proste: co możesz umieścić za tym 'if', żeby twój program miał sens?

> > 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.

No ale po co?

Właśnie na tym polega istota typów wartościowych: informacja, jaką one niosą,
to jest wyłącznie wartość. Obiekty, które są typów wartościowych, mogą zatem
pojawiać się i znikać co chwilę, kompilator w zależności od opcji
optymalizacji może tych obiektów tworzyć więcej, lub mniej i tak dalej. Po
prostu te obiekty są jedynie użyte instrumentalnie - ich tożsamość nie powinna
cię interesować; te obiekty kompilator niech sobie tworzy, jak mu się podoba,
a dla ciebie istotna powinna być tylko wartość.

> > 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...

Tak. Javowy String ;)

> 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.

Tak, ale to nie jest jeszcze takie proste.

Tak, jak mówiłem o Smalltalkowych symbolach: możesz stworzyć grupę obiektów,
która będzie symbolicznie oznaczać określone wartości.

W twoim przypadku najlepiej by było np. stworzyć listę tych wartości i mieć je
jako "stałe". Podobnie jak stałe enum. Zaznaczasz przy tym, że:

 - tylko twoja klasa ma możliwość tworzenia takich obiektów. Użytkownikowi
   wolno jedynie korzystać z już gotowych
 - każdy obiekt typu TrybGraficzny jest unikalny

I w takim przypadku, oczywiście, najsensowniej jest, jeśli porównujesz te
obiekty po tożsamości. Tyle że skoro obiekty są unikalne, to i tak da ono ten
sam wynik, co porównanie zawartości. Ale fakt, że zoptymalizowałeś to na
porównanie tożsamości, to tylko kwestia implementacji.

Jeśli ilość trybów jest dynamiczna, to wtedy musisz zorganizować jakieś
mapowanie na unikalne wartości (w sensie, na coś, co jest łatwiej porównać).

> 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, jak najbardziej. W takim przypadku po prostu przygotowujesz zestaw
wszystkich możliwych wartości na początku, a potem posługujesz się do nich
wskaźnikiem jako symbolem określonego trybu.

Zauważ zresztą, co dla ciebie w praktyce oznacza stwierdzenie, że "tryb
graficzny x to ten sam tryb co y".

To nie znaczy, że "x i y" mają tą samą rozdzielczość pionową, tę samą
rozdzielczość poziomą i tę samą głębokość kolorów".

To znaczy, że x np. oznacza tryb graficzny numer 4, a y też tryb graficzny
numer 4. A tryb graficzny numer 4 to dopiero ma... itd.

Zauważ też, że nie wykonujesz żadnych operacji na obiektach typu
TrybGraficzny, które mogłyby wyprodukować nowe obiekty typu TrybGraficzny.
Gddyby takie były, to oczywiście też musiałyby być wykonane tak, żeby w wyniku
dostać inny obiekt typu TrybGraficzny.

> > 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 ;)

C++, na przykład. Nie mówię, że w ogóle tylko C++, bo istnieje jeszcze parę
innych, których to dotyczy.

W D jest to może nawet odrobinę lepiej zrobione (chodzi mi o "auto class").

> > Oczywiście teorię typów wartościowych i niewartościowych [...]
> > można olać, jeśli ktoś uważa, że mu nie pasuje. Tylko że
> > alternatywą jest stwierdzenie, że mamy kilka różnych definicji
> > porównania, kopiowanie płytkie i głębokie itd.

> Mógłbyś uściślić na czym polega związek typów wartościowych
> z płytkim/głębokim kopiowaniem?

Widzisz, problem polega na tym, że rozróżnienie między kopiowaniem płytkim, a
głębokim jest konieczne, bo czasem potrzebne jest nam współdzielenie
wewnętrznych danych (w tym modyfikowalnych), a czasem chcemy mieć własną
kopię. Kopiowanie obiektów wartościowych odpowiada kopiowaniu głębokiemu. Z tą
tylko różnicą, że w zależności od możliwości języka możemy to zorganizować
przez copy-on-write (czyli kopiowanie jest efektywnie płytkie, ale tylko do
pierwszej modyfikacji).

Pojęcia kopiowania płytkiego i głębokiego są pojęciami niskiego poziomu i ich
używanie jest konieczne, jeśli język nie dostarcza żadnych bardziej ogólnych
narzędzi pozwalających na zrobienie takiego typu, czy też najprościej mówiąc,
programista uważa, że tak mu lepiej.

> > Nawiasem mówiąc, w Rubym spierdzielili sprawę ze stringami
> > totalnie. String w ogólności jest typem wartościowym - niestety
> > w Rubym jest on ehm... takim dziwnie-hybrydowym. To znaczy,
> > modyfikacje przenoszą się na inne obiekty oznaczane
> > identyfikatorami:
> >
> > a = "dupa"
> > b = a
> > b[0] = "p"
> > print a

> A czy w Javie przypadkiem nie jest tak samo?
> No chyba że tam się wtedy robi kopia przy modyfikacji przez b.
> Już nie pamiętam...

W javie przede wszystkim tej trzeciej instrukcji nie skompilujesz.

Na tym właśnie polega myk ze zorganizowaniem typu wartościowego przez
niemodyfikowalny typ obiektowy.


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15763
Author: Mariusz Lotko
Date: Tue, 20 Mar 2007 18:49
16 lines
1738 bytes
Sektor van Skijlen wrote:

> A ja, jak widzę, trafiłem na kogoś zakompleksionego, kto musi się
> dowartościować przez pomiatanie innymi.

Ciekawa uwaga. Niejeden psycholog określiłby to stwierdzenie
mianem "projekcji"
(http://pl.wikipedia.org/wiki/Projekcja_%28psychologia%29).

Gwoli informacji: ja nic nie muszę. Jeśli coś robię to dlatego, że chcę.

Pozdrawiam _Ciebie_ i do niezobaczenia. Życzę powodzenia w krzewieniu
nowej teorii nt. obiektowości.

-- 
Mariusz Lotko
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15770
Author: Piotr Dembiński
Date: Wed, 21 Mar 2007 10:46
10 lines
1730 bytes
Mariusz Lotko <imie.nazwisko@wp.pl> writes:

[...]

> Obiekt kolor ma jeszcze atrybuty: data naniesienia, technika
> wykonania i stopień nasłonecznienia, które pozwalają obliczyć
> rzeczywisty kolor w czasie :> Wtedy nie da się porównać dwóch
> "czerwonych". Odsyłam do ekspertów - lakierników samochodowych.

No to jest mutable color.
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15765
Author: Piotr Dembiński
Date: Wed, 21 Mar 2007 10:55
13 lines
2015 bytes
Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid> writes:

[...]

> (Na marginesie: to bardzo dobrze, że literatura do OO twierdzi, że
> programowanie obiektowe jest modelowaniem rzeczywistości. Tak bowiem
> należy tą sprawę tłumaczyć początkującym. Im więcej jednak człowiek
> programuje obiektowo, tym bardziej się przekonuje, że to nie ma nic
> wspólnego z prawdą.  To jest jeden ze znaków rozpoznawczych, czy
> ktoś potrafi myśleć samodzielnie rzeczywiście dysponuje
> doświadczeniem zawodowym, czy recytuje z pamięci wiedzę książkową.)

Twierdzisz, że domknięcia i iteratory nie występują w rzeczywistości?
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15764
Author: Piotr Dembiński
Date: Wed, 21 Mar 2007 10:58
10 lines
1635 bytes
Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
writes:

[...]

> Typ wartościowy jest typem, którego obiekt jest identyfikowany
> zawsze przez wartość.

Ja to rozumiem tak, że w typach wartościowych wartość jest
tożsamością, a tożsamość wartością.
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15766
Author: Sektor van Skijlen
Date: Wed, 21 Mar 2007 12:43
22 lines
2518 bytes
Dnia Wed, 21 Mar 2007 11:55:50 +0100, Piotr Dembiński skrobie:
> Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid> writes:

> [...]

> > (Na marginesie: to bardzo dobrze, że literatura do OO twierdzi, że
> > programowanie obiektowe jest modelowaniem rzeczywistości. Tak bowiem
> > należy tą sprawę tłumaczyć początkującym. Im więcej jednak człowiek
> > programuje obiektowo, tym bardziej się przekonuje, że to nie ma nic
> > wspólnego z prawdą.  To jest jeden ze znaków rozpoznawczych, czy
> > ktoś potrafi myśleć samodzielnie rzeczywiście dysponuje
> > doświadczeniem zawodowym, czy recytuje z pamięci wiedzę książkową.)

> Twierdzisz, że domknięcia i iteratory nie występują w rzeczywistości?

No, na przykład. Co do iteratorów, to jeszcze można by się spierać.

-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15767
Author: Piotr Dembiński
Date: Wed, 21 Mar 2007 15:07
12 lines
1736 bytes
Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
writes:

[...]

>> Twierdzisz, że domknięcia i iteratory nie występują
>> w rzeczywistości?
>
> No, na przykład. Co do iteratorów, to jeszcze można by się spierać.

Domknięcia są jeszcze łatwiejsze.  IMO każdy nie komunikujący się
z otoczeniem, spełniający dowolną funkcję komputer tworzy domknięcie.
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15768
Author: Sektor van Skijlen
Date: Wed, 21 Mar 2007 20:53
26 lines
2485 bytes
Dnia Wed, 21 Mar 2007 16:07:41 +0100, Piotr Dembiński skrobie:
> Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
> writes:

> [...]

> >> Twierdzisz, że domknięcia i iteratory nie występują
> >> w rzeczywistości?
> >
> > No, na przykład. Co do iteratorów, to jeszcze można by się spierać.

> Domknięcia są jeszcze łatwiejsze.  IMO każdy nie komunikujący się
> z otoczeniem, spełniający dowolną funkcję komputer tworzy domknięcie.

Moment, rozwiążmy najpierw problem niejednoznaczności określenia "domknięcie".

Jeśli pod pojęciem "domknięcie" masz na myśli lokalną funkcję mającą dostęp do
środowiska funkcji zewnętrznej, to porównanie tego z komputerem odciętym od
sieci przebija o wiele długości metody porównawcze "rogatego szefa Dilberta".


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15756
Author: SasQ
Date: Thu, 22 Mar 2007 00:35
670 lines
31903 bytes
Dnia Tue, 20 Mar 2007 18:03:10 +0000, Sektor van Skijlen napisał(a):

> Oczywiście i tak w efekcie wszystko można po części sprowadzić do
> absurdu, ale jedna rzecz i tak zawsze będzie zachowana: obiekty
> typów wartościowych zawsze mają swoją własną kopię zawartości.

Tzn?

>>> (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 :|
>
> Jaki jest sens sprawdzania, czy dwa portfele zawierają
> tyle samo pieniędzy?

Jeśli jeden z nich jest mój, to takie porównanie daje mi
informację, czy ktoś ma tyle samo kasy co ja ;J

> Można, tylko po co? Jeśli już, to chcemy sprawdzić, czy
> np. w portfelu jest "wystarczająca ilość" pieniędzy.

Niepotrzebnie ograniczasz możliwości ;)
I właśnie tego nie możemy zrozumieć: twoja teoria, że istnieje
podział na obiekty wartościowe i resztę, ma jak dla mnie sens,
ale nie mogę zrozumieć, po co wyciągać z tego jakieś ograniczenia.

> W większości przypadków zaś, sprawdzenie stanu polega na
> porównaniu go z jakąś istniejącą wartością, może stałą, może
> też z innym stanem, który wyznacza, powiedzmy, wymagany "poziom"
> stanów - chociaż też tam zwykle się używa operatora <, a nie ==.

Mów trochę jaśniej, jak chcesz żebyśmy zrozumieli ;)
Ja np. preferuję obrazowe wyjaśnienia na przykładach ;)

> Ja wiem, że teoretycznie może taka sytuacja istnieć, ale skoro
> jest ona taka unikalna, to nie ma co mówić o typowości takiego
> porównania - jest ono właśnie czymś bardzo nietypowym.

Ale jest. Więc czemu się ograniczać i go zabraniać? Może akurat
w tym 1 na 1000 przypadków komuś to będzie potrzebne?

>> 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.
>
> Ciepło, ale to stwierdzenie jest nieprecyzyjne. Bo co uważamy
> za typ podstawowy?

:) Typy wbudowane miałem na myśli. Czyli te podstawowe, z których
buduje się inne typy, bardziej złożone.

>> Hmm... a jak to jest z referencjami i wskaźnikami?
>
> Referencje - jeśli chodzi o C++ - to jest akurat taki dość
> wyjątkowy typ. W zasadzie to nawet nie powinien być uważany za
> oddzielny typ.

No tak, to raczej sposób dostępu do obiektu, niż osobny typ.

> Jest to podstawowa forma, w jakiej istnieje każdy obiekt
> określany symbolem i oznacza coś, co ma swoje odwzorowanie
> w pamięci.

Hehe ja sobie to wyobrażam jako etykietę ;)
Referencja to taka etykieta nadana miejscu w pamięci. Tylko że
w C++ jest to taka dodatkowa etykieta do już istniejącego
miejsca w pamięci, a "zwyczajne" nazwy to są "te główne" nazwy
danego miejsca w pamięci:

  int nazwa;             Nazwa +-----------------+
                               | obiekt typu int |
                               +-----------------+

  int& ref = nazwa;      Nazwa +-----------------+
                           ref | obiekt typu int |
                               +-----------------+

I takie rozumienie się nawet zgadza, bo używanie referencji
niczym się w C++ nie różni składniowo od używania "zwykłej"
nazwy obiektu. Jedynie przy przekazaniu do funkcji jako parametr
wychodzi rozróżnienie [sztuczne? :P] polegające na tworzeniu kopii
obiektów gdy się je przekazuje jako "zwykłą" nazwę, i przekazywaniu
samych adresów lub inline'owanu bezpośredniego dostępu gdy się
przekazuje jako referencję.

> Wskaźnik na to coś wskazuje.

Ano :J

  int* wsk = &nazwa;       wsk +------------------------+
                               | adres obiektu typu int |
                               +-----------+------------+
                                           |
                                           v
                         Nazwa +-----------------+
                           ref | obiekt typu int |
                               +-----------------+

Osobny obiekt, osobny obszar pamięci, osobna nazwa ;J
Dlatego można też mieć referencję wskaźnika:

  int*& refwsk = &wsk;     wsk  +------------------------+
                         refwsk | adres obiektu typu int |
                                +-----------+------------+
                                            |
                                            v
                          Nazwa +-----------------+
                            ref | obiekt typu int |
                                +-----------------+

> I wskaźnik już jest typem wartościowym.

Nom, jak by nie patrzeć to jest. Gdy przypiszę go do drugiego,
to ten drugi "przejmuje tożsamość" tego pierwszego, staje się nim
[hehe "The return of the body switchers" :D]  Gdy je porównuję, to
nie obchodzi mnie że ten drugi to osobny obiekt, tylko interesuje
mnie, czy mają tą samą wartość [pokazują na to samo miejsce].
I tu rzeczywiście nie wyobrażam sobie sytuacji, w której bym
oczekiwał od porównania wskaźników porównania czy są to te same
obiekty w tym samym miejscu pamięci, czy może leżą w różnych.
ALE.. może po prostu mam słabą wyobraźnię ;)  W końcu czasami
przekazuje się wskaźnik przez referencję lub jako wskaźnik do
wskaźnika, a wtedy rozchodzi się o ich położenie w pamięci,
a nie wartość. Nie wiem tylko jak z tym porównaniem wtedy.

>> 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.
>
> No właśnie... widzisz, chodzi tutaj o to, że string w sposób
> naturalny jest typem wartościowym i jak się porównuje stringi,
> to nigdy nikomu nie chodzi o porównanie ich tożsamości.

Chyba że jest menedżerem pamięci zarządzającym stringami ;)
Wtedy fakt, gdzie w pamięci leży obiekt, ma większe znaczenie
niż to, co on zawiera. Z punktu widzenia takiego menedżera
może być istotne, czy dwa obiekty to ten sam obiekt w tym
samym miejscu pamięci, czy może leżą w różnych miejscach i
są to różne obiekty [mimo że mogą przechowywać tą samą wartość].
Bo np. ktoś kazał mu "zwolnij TEGO stringa", i on sobie chce
porównać, czy "TEN string" to przypadkiem nie jest któryś z
obsługiwanych przez niego, albo żeby nie zwolnić dwa razy
"tego samego" stringa - i tutaj "ten sam" oznacza "leżący w
tym samym miejscu pamięci", a nie "mający tą samą wartość".

Wygląda więc na to, że obiekt może być wartościowy z jednego
punktu widzenia, a niewartościowy z innego punktu widzenia,
zależnie od tego kto i jak go rozumie i używa [zależnie od
interfejsu, którego używa użytkownik?.. :/].

> Tu problem polega na tym, że w C nie myślano o specjalizowanym
> zastosowaniu operatora ==

No i tego czasami brakuje. Szczególnie chciałoby się móc
przeciążyć operator+ żeby możliwy był taki zapis:

  string s;
  s = "abcd" + x + "defg" + y + "hijk";

Na szczęście są jeszcze strumienie do stringów ;J
Pewnie jako "łatka" na powyższe braki ;)

> a tekst w cudzysłowiu jest tylko uproszczonym zapisem tablicy
> z zerem na końcu (a po nim przejął to tak C++).

To akurat jeszcze ujdzie, bo gwarantuje, że będzie to tak samo jak
w Assemblerze i nic więcej nie będzie tam wpychane do pamięci ;J

>> Czyli to jest wybór arbitralny, czy jednak podyktowany jakimiś
>> właściwościami?
>
> No, gdyby portfel z tą samą ilością pieniędzy był zawsze tym
> samym portfelem...

Aha, czyli zależy od tego, jak rozumiemy ten portfel w świecie
rzeczywistym.

> Podawałem przykład "salda" i "koloru" jako typów wartościowych.
> Chodzi o podobieństwo do tych typów, i co np. jest dla ciebie
> tym samym. Co to znaczy, że "kolor jest ten sam", co znaczy
> "saldo jest to samo", a co znaczy z kolei "portfel jest ten sam"?

Hmm... W takim razie o co ta cała dyskusja? :J  Gdy w C++ ktoś
przeładowuje operator porównania, to implementuje sobie jedną z
tych dwóch semantyk, zależnie jak mu pasuje ;J  Chce żeby porównanie
porównywało wartość [przeważnie tak jest], to tak robi [porównuje
składniki, które stanowią widoczną wartość obu obiektów]. Chce
żeby porównanie sprawdzało czy obiekty są te same - da się zrobić
[hmm... porównując wskaźniki this? :P nie wiem, nie znam sie aż tak
dobrze na tym ;J].

> A jeśli i tak nie wiesz, to najprościej stwierdzić to w ten sposób:
>
> Utwórz a
> b = a
> Zmodyfikuj b
>
> Jeśli spodziewasz się, że po takim czymś 'a' powinno zostać
> zmodyfikowane, to jest to typ obiektowy.

Heh... w C++ to właściwie nigdy bym się nie spodziewał takiego
przebiegu zdarzeń ;D  Gdyby tak się działo, uznałbym to za błąd,
bo jestem przyzwyczajony traktować nazwy obiektów jako aliasy
dla ich wartości, czyli tak samo jak dla typów wbudowanych ;J
Jedyny wyjątek, gdzie ta intuicja się zmienia, to referencje.
Jeśli b jest referencją do a, to wszystko gra i buczy ;J

> Typy obiektowe poza tym często posiadają powiązania. Powiązania
> te często powodują nawet, że nie da się ich klonować.

A to nie spotkałem się jeszcze. Jakiś przykład możesz podać?

> Typy wartościowe nigdy nie posiadają powiązań.

Jesoo, czemu to wszystko takimi ogólnikami gadasz? :P
Spox, może ty wiesz o czym mówisz i masz wyraźną wizję o co
biega z tymi powiązaniami, masz w głowie jakieś konkretne
przykłady, ale nie wychodzi to poza obszar twojej głowy, gdy
mówisz tak ogólnie :P a ja się tego sam nie domyślę, co tak
naprawdę chodziło ci po głowie gdy to pisałeś ;J
Prosiłbym o jakieś bardziej konkretne przykłady.

>>>> 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."
>
> Względem języka tak. Ale fizycznie one nie muszą istnieć.

Hmm... Dla mnie obiekt to coś, co istnieje namacalnie, czyli
zajmuje jakiś obszar pamięci. Nie musi mieć nazwy, bo są przecież
obiekty anonimowe [np. te alokowane na stercie, czy obiekty
tymczasowe], ale jakoś nie wyobrażam sobie obiektu-ducha, którego
nie ma :|  [nie leży nigdzie w pamięci]

>> A teraz mi tu siejesz trwogę, że są "gołymi" wartościami nie
>> trzymanymi nigdzie? :P
>
> W praktyce tak :)

Znów nic nie mówiący ogólnik ;J

> Nie no, formalnie to one oczywiście są obiektami stałymi, a
> także jest prawdą, że do przechowywania wartości jakiś obiekt
> musi być.

Ano właśnie.

> Ale ten obiekt jest traktowany wyłącznie instrumeentalnie.

Masz na myśli coś w rodzaju "naczynia na wartość"?

>> 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
>
> No są. W programie ;)
>
> Tzn. dokładnie to jest tak: formalnie, to są obiekty stałe.
> Tzn. jeszcze inaczej: to MOGĄ BYĆ obiekty stałe.

Heh... zakręcone to wszystko jak tampon w p**dzie :P
Chciałbym to jednak dobrze zrozumieć, dlatego spróbuję to
trochę jakoś zrekapitulować, a ty mnie popraw gdybym gdzieś
coś źle mówił:

Obiekt reprezentuje w programie jakiś element ze świata
rzeczywistego i pozwala nam się do niego odwoływać, jako
do pewnego "czegoś" ["bytu"? :P], które "gdzieś tam istnieje".
Możemy się do tego "czegoś" odwoływać w programie, a to "coś"
może nam odpowiedzieć, zrobić coś, przechować jakąś wartość itp.

Obiekty mogą posiadać wartość, czyli aktualny stan. Jeśli ten
stan może się zmieniać w czasie działania programu [możemy
przypisać do obiektu nowy stan], to taki obiekt nazywamy
obiektem zmiennym [lub zmienną, jak w matematyce lub w
tradycyjnym programowaniu]. Jeśli początkowego stanu obiektu
nie można zmieniać [nie można mu przypisać nowej wartości], to
nazywamy go obiektem stałym [lub inaczej stałą].

Zazwyczaj obiekty są alokowane w jakimś ciągłym i jednolitym
obszarze pamięci i tam właśnie przechowują swój stan. Są jednak
sytuacje, w których obiekty mogą nie być nigdzie alokowane
[np. jeśli są to stałe dosłowne, lub obiekty tymczasowe].

Stałe dosłowne to takie obiekty stałe, które są podane dosłownie
w kodzie programu, "z marszu" [ang. "on-the-fly"]. Takie obiekty
nie posiadają nazwy, więc nie można się do nich odwoływać nigdzie
indziej w programie poza miejscem, gdzie zostały dosłownie podane.
Kompilator może nawet wogóle nie alokować ich nigdzie w pamięci,
tylko wplatać w kod wynikowy wszędzie tam, gdzie będzie to potrzebne,
jako część instrukcji maszynowej, lub generować bezpośrednio w
rejestrze jeśli tak jest szybciej. I tu jedynym wyjątkiem są stałe
tekstowe, które są alokowane w pamięci statycznej. Jednak nawet
wtedy kompilator może zaalokować kilka stałych tekstowych podanych
w różnych miejscach programu jako jeden i ten sam obszar pamięci,
jeśli wszystkie te stałe tekstowe mają tą samą treść.

Obiekty tymczasowe to też są obiekty, które nie posiadają nazwy,
a kompilator może nie alokować ich w pamięci jeśli tak mu jest
wygodniej. Obiekty tymczasowe są szczególnie zaprojektowane by
ułatwić kompilatorowi optymalizacje, by nie musiały robić
zbytniego narzutu w sytuacji, gdy programista nie może dokładnie
nad tym panować. Jeśli zakładamy, że takie optymalizacje mogą
być robione dla niektórych typów obiektów [np. wbudowanych], a
dla niektórych nie [bo np. nie mieszczą się w rejestrze], a nie
mamy wpływu na to jak i kiedy kompilator będzie optymalizował,
to musimy zakładać że robi to zawsze i dla wszystkich obiektów
[tak na wszelki wypadek :P]. Dlatego nie da się pobrać adresu
obiektu tymczasowego. Tylko w ten sposób można zagwarantować,
że kompilator będzie mógł zrobić te optymalizacje dla każdego
obiektu, dla którego uzna to za stosowne.

Zwykłe obiekty też mogą być w ten sposób optymalizowane, ale
tutaj już nie ma na to takiego nacisku, więc kompilator może
to zrobić tylko wtedy, gdy nie pobieramy adresu obiektu.
Jeśli się pobiera adres obiektu, to kompilator musi zadbać o to,
żeby ten obiekt był gdzieś zaalokowany. Tym razem jednak to my
możemy zdecydować, że nie chcemy optymalizacji, pobierając adres
obiektu. W przypadku obiektów tymczasowych i stałych dosłownych
nie mieliśmy nad tym władzy - decydował kompilator, a my musieliśmy
się na to godzić i obiecać, że nie pobierzemy nigdy adresu takiego
obiektu nawet wtedy, gdyby jednak kompilator nie zrobił tej
optymalizacji i obiekt leżałby jednak gdzieś w pamięci.

> Problem po prostu polega na tym, że co prawda C++ pozwala ci
> zrobić tak:
>
>  const int& a = 5, & b = 5;

No spoko, od niedawna już o tym wiem ;)
Wolno przykleić referencję-do-stałej do obiektu tymczasowego
lub stałej dosłownej. Zastanawiam się tylko, czemu w tym przypadku
nikt się już nie martwi o optymalizacje i nieistnienie obiektów
tymczasowych/stałych dosłownych w pamięci? ;P  W czym taka referencja
jest lepsza od wskaźnika? [choćby i nawet stałego wskaźnika do stałej]
Czy wtedy obiekt jest jednak alokowany w pamięci?
Czy może nie jest to jedynie inny zapis [bardziej dosłowny] dla
definicji obiektu stałego?
Bo jakoś nie widzę różnicy między tym:

   const int a = 5;           a +-----+
                                |  5  |
                                +-----+
a tym:

   const int& a = 5;          a +-----+
                                |  5  |
                                +-----+

oprócz tego, że:
1. W pierwszym przypadku kompilator widzi deklarację nazwy "a" jako
   nazwy dla obiektu stałego o początkowej wartości 5, więc alokuje
   pamięć pod niego, wpisuje tam 5 i zapamiętuje sobie, że do tego
   obszaru pamięci można się odwołać poprzez nazwę "a".
2. W drugim przypadku kompilator widzi deklarację nazwy "a" jako
   referencji-do-stałej, która ma referować do wartości stałej
   dosłownej 5, więc chcąc nie chcąc musi zameldować tą wartość
   gdzieś w pamięci i przypisać do tego miejsca referencję [nazwę]
   "a" zapamiętując, że od tej chwili do tego obszaru pamięci można
   się odwołać poprzez nazwę "a".

Czyli różnica by była tylko w tym, że w pierwszym przypadku kompilator
automatycznie wiąże nazwę obiektu z przydzielonym dla niego wcześniej
obszarem pamięci, a w drugim przypadku przydziela obszar pamięci, z
którym my sami każemy mu związać pewną nazwę.

Blah, zamotałem się :PPP

> A nawet tak:
>
>  if ( &a == &b )

Hmm... o ile dobrze myślę, że pobranie adresu referencji oznacza
pobranie adresu obszaru pamięci, który ona referuje... to takie
porównanie będzie prawdziwe jeśli obie wartości stałe dosłowne
zostały zameldowane pod tym samym adresem?

> Ale to porównanie nie zwróci ci żadnej sensownej informacji.

No wtedy to rzeczywiście, mało nam takie coś daje :P

> Literał zapisany w języku sam z siebie jest jedynie wartością.

Czyli nie jest obiektem? :|
No qrka, na moje oko to jest. Dlaczego? Na rzecz obiektu powinno się
dać wywołać metody, jeśli on jakieś ma. No i idąc dalej tym tropem:
obiekt dowolnego typu ma zwykle pewien zestaw metod, nawet jeśli
programista żadnych nie zadeklarował. Przykładem jest np. destruktor.
Dla typów wbudowanych można wywołać destruktor [który wtedy nie robi
nic], np. tak:

  int x = 7;
  x.~int();    //OK

Co ciekawe, da się to zrobić także dla stałej dosłownej, tylko że
trzeba ją ująć w nawiasy, żeby uniknąć dziwacznej składni, której
kompilator mógłby nie zrozumieć.

  7.~int();     //błąd składni
  (7).~int();	//OK

Zastanawiam się tylko, czy ujęcie w nawiasy nie powoduje powstania
jakiegoś tymczasowego obiektu jako wyniku wyrażenia w nawiasie.
Bo jeśli tak, to wniosek byłby że jednak stałe dosłowne nie są
obiektami :P

> Dopiero gdy zostanie użyty, może się z niego zrobić obiekt - ale
> dopiero gdy zostanie użyty jako obiekt i dopiero w miejscu, w
> którym będzie użyty jako obiekt tym obiektem będzie. Wcześniej
> jest tylko zapisem w programie.

No coś tam mi już świta, ale pewności nie mam jeszcze w tym temacie :/

>> Nie rozumiem pytania :|
>
> Pytanie proste: co możesz umieścić za tym 'if', żeby twój program
> miał sens?

A to już zależy od konkretnego przypadku. Jeśli porównywane obiekty
traktuję jako wartości, wtedy nie obchodzi mnie gdzie one leżą w
pamięci, ale czy mają tą samą wartość, bo to oznacza dla mnie "równość".
Jeśli zarządzam obiektami w pamięci [tworzę dynamicznie, niszczę,
realokuję itp.], to wtedy nie obchodzi mnie co w nich jest, tylko że
są obiektami i gdzie w pamięci leżą. Wtedy równość oznacza dla mnie,
czy leżą w tym samym miejscu pamięci [jest to ten sam obiekt].

Np. funkcja dostaje dwa adresy obiektów i chce sprawdzić, czy
dostała adresy dwóch różnych obiektów, czy tego samego. Wtedy
obchodzą mnie bardziej ich tożsamości [adresy w pamięci], niż
(za)wartości.

Chociaż tu jest jeszcze jedna kwestia: wskaźnik jest traktowany
jako wartość - adres. Więc w tym przypadku też tak naprawdę
porównywane są wartości - adresy obiektów, a nie same obiekty.
Więc może w porównaniu zawsze chodzi o porównanie wartości? :P

>> 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.
> 
> No ale po co?

Żeby np. nie zwolnić dwa razy tego samego obiektu
[patrz: operator przypisania i przypisanie do samego siebie].

> Właśnie na tym polega istota typów wartościowych: informacja,
> jaką one niosą, to jest wyłącznie wartość.

Oficjalnie tak, a nieoficjalnie są one mimo wszystko obiektami
i mają pewną niezależną tożsamość [adres w pamięci]. Nie zawsze
trzeba to brać pod uwagę, ale "nie zawsze" != "nigdy" ;P

> Obiekty, które są typów wartościowych, mogą zatem pojawiać
> się i znikać co chwilę, kompilator w zależności od opcji
> optymalizacji może tych obiektów tworzyć więcej, lub mniej
> i tak dalej.

Hmm... jakieś konkretne przykłady? Bo znów wyobraźnia mnie zawodzi ;J

>> Czy obiekt klasy TrybGraficzny mógłby być typem wartościowym?
>> Chodzi mi o taki obiek 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.
> 
> Tak, ale to nie jest jeszcze takie proste.

O żesz w morde jeża :/  A już sie cieszyłem :P

> W twoim przypadku najlepiej by było np. stworzyć listę tych
> wartości i mieć je jako "stałe".

Taki był właśnie plan. Obiekt pewnej klasy, który reprezentuje
kartę graficzną, miał sobie pobierać informacje o dostępnych
na niej trybach graficznych i tworzyć taką stałą dla danej karty
listę oferowanych trybów graficznych [również stałych]. Inne
obiekty mogłyby sobie pobrać takie obiekty TrybGraficzny z
informacją o danym trybie, skopiować sobie takie obiekty na
własny użytek [zapamiętać gdzieś na boku by po chwili użyć
w jakimś innym wywołaniu do obiektu karty graficznej], ale
zabronione miało być tworzenie sobie przez "byle kogo" [czyt.
obiekty inne niż ten co obsługuje kartę graficzną] nowych
obiektów klasy TrybGraficzny i modyfikowanie tych już istniejących
kopii skopiowanych od obiektu karty graficznej, żeby nie mógł
powstać obiekt z nieprawidłowymi danymi na temat trybu graficznego.

> Podobnie jak stałe enum. Zaznaczasz przy tym, że:
>
> - tylko twoja klasa ma możliwość tworzenia takich obiektów.
>  Użytkownikowi wolno jedynie korzystać z już gotowych

No to myślimy o tym samym, jak widać ;)
Szkoda, bo już myślałem że wpadłem na coś oryginalnego :P ;)

> - każdy obiekt typu TrybGraficzny jest unikalny

W jakim sensie "unikalny"? Niepowtarzalny? [może istnieć tylko
jeden obiekt z tak ustawionymi parametrami trybu graficznego]?
Ja bym jednak wolał, żeby dało się je kopiować, bo czasem
użytkownik może woleć sobie przechować jakieś dane na własną
rękę, a mnie to nie robi żadnej szkody, dopóki te parametry
trybu pozostają poprawne ;J

> I w takim przypadku, oczywiście, najsensowniej jest, jeśli
> porównujesz te obiekty po tożsamości.

??
Masz na myśli żebym to tak zoptymalizował, że zamiast porównywać
wartość [poszczególne parametry trybów], to porównywać adresy
całych obiektów?  No, coś w tym jest, ale wyklucza możliwość
tworzenia kopii, de facto poprawnych a więc nieszkodliwych ;J

> Tyle że skoro obiekty są unikalne, to i tak da ono ten sam
> wynik, co porównanie zawartości.

No otóż to.

> Ale fakt, że zoptymalizowałeś to na porównanie tożsamości,
> to tylko kwestia implementacji.

No raczej tak. Użytkownik nadal widziałby to jako tryb1==tryb2.

> Jeśli ilość trybów jest dynamiczna, to wtedy musisz zorganizować
> jakieś mapowanie na unikalne wartości (w sensie, na coś, co jest
> łatwiej porównać).

Ilość trybów dla danej karty graficznej jest raczej stała przez
cały czas działania programu ;J  więc wystarczy jak sobie zbuduję
listę trybów przy inicjalizacji [w konstruktorze] i może ona być
nawet stała [może wystarczy nawet zwykła tablica ;J].

>> 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, jak najbardziej. W takim przypadku po prostu przygotowujesz
> zestaw wszystkich możliwych wartości na początku, a potem
> posługujesz się do nich wskaźnikiem jako symbolem określonego
> trybu.

Myślałem też nad rozwiązaniem takim, żeby zamiast przechowywać w
każdym obiekcie klasy TrybGraficzny pełne informacje o typie, to
zrobić z niego coś na kształt "uchwytu" tudzież "proxy". Dla
użytkownika nic by to nie zmieniało, bo nadal mógłby używać tego
samego interfejsu i otrzymać te same informacje o trybie, ale
wewnętrznie te dane nie musiałyby wtedy być przechowywane w
obiekcie, tylko pobierane na żądanie z jednego źródła [np. z
jakiejś wewnętrznej struktury danych w klasie karty graficznej].
Wtedy porównanie dwóch trybów także można by było przyspieszyć,
bo zamiast porównywać poszczególne parametry, wystarczyłoby
porównać ten "numer trybu" czy też wskaźnik przechowywany
wewnątrz obiektu klasy TrybGraficzny ;J

> Zauważ zresztą, co dla ciebie w praktyce oznacza stwierdzenie,
> że "tryb graficzny x to ten sam tryb co y".
> 
> To nie znaczy, że "x i y" mają tą samą rozdzielczość pionową,
> tę samą rozdzielczość poziomą i tę samą głębokość kolorów".

Jak to nie? :P  Przecież o to się właśnie dokładnie rozchodzi :P

> To znaczy, że x np. oznacza tryb graficzny numer 4, a y też
> tryb graficzny numer 4.

No nie wiem... dla usera to jest raczej nieistotne, który ten
tryb jest tam w kolejności na karcie graficznej [jaki ma numer],
tylko właśnie parametry tego trybu, i czy dwa podane tryby mają
takie same parametry, bo wtedy są przez użytkownika traktowane
jako ten sam tryb, tylko pamiętany w różnych miejscach.

> A tryb graficzny numer 4 to dopiero ma... itd.

Hmm... po części masz rację, bo w większości przypadków albo
pobierany będzie tryb z listy i przechowywany gdzieś, albo
będzie podawany spowrotem klasie karty graficznej, żeby np.
ustawić ten tryb dla ekranu monitora. Ale już gdy zechcemy
wylistować dostępne tryby, by użytkownik programu mógł sobie
wybrać odpowiedni tryb według jego parametrów, to jednak
trzeba te informacje o trybie wydostać.
[i tu mam jeszcze pewne niejasności, jakie informacje będą
przechowywane w obiekcie TrybGraficzny: czy będzie to tylko
szerokość, wysokość i głębia kolorów, czy może jakieś
dokładniejsze informacje o formacie pixela itp.].

> Zauważ też, że nie wykonujesz żadnych operacji na obiektach
> typu TrybGraficzny, które mogłyby wyprodukować nowe obiekty
> typu TrybGraficzny.

Nowe obiekty może tworzyć jedynie obiekt, który obsługuje
kartę graficzną, bo tylko on zna poprawne wartości i może
je wpisać do obiektów klasy TrybGraficzny.
Nikt inny nie powinien tworzyć nowych obiektów, aby nie
wyprodukował sobie trybu graficznego z błędnymi parametrami :P
Zauważ jednak, że tworzenie nowych może być dozwolone, ALE
tylko na podstawie tych już istniejących, poprawnych [czyli
konstrukcja kopiująca jest OK, nic nie psuje]. Zabroniona
powinno być też modyfikacja już istniejących obiektów.

> Gddyby takie były, to oczywiście też musiałyby być wykonane
> tak, żeby w wyniku dostać inny obiekt typu TrybGraficzny.

Jak inny? Nie czaję... Chyba raczej taki sam? :/

>> Mógłbyś uściślić na czym polega związek typów wartościowych z
>> płytkim/głębokim kopiowaniem?
>
> Widzisz, problem polega na tym, że rozróżnienie między
> kopiowaniem płytkim, a głębokim jest konieczne, bo czasem
> potrzebne jest nam współdzielenie wewnętrznych danych (w tym
> modyfikowalnych), a czasem chcemy mieć własną kopię.

To wiem.

> Kopiowanie obiektów wartościowych odpowiada kopiowaniu
> głębokiemu.

To już też wiem, bo wspominałeś o tym. Nie wiem tylko,
dlaczego tak ;J  Wskaźnik też przechowuje wartość, która
jest adresem innego obiektu, a ten inny obiekt nie jest
kopiowany, gdy kopiujesz wskaźnik ;J

> Pojęcia kopiowania płytkiego i głębokiego są pojęciami niskiego
> poziomu i ich używanie jest konieczne, jeśli język nie dostarcza
> żadnych bardziej ogólnych narzędzi

No ale skąd język miałby wiedzieć, jak postąpić w konkretnym
przypadku? Skąd ma wiedzieć, które składniki może skopiować
płytko [przepisać wartość], a które musi głęboko [sklonować]?

-- 
SasQ
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15769
Author: Piotr Dembiński
Date: Thu, 22 Mar 2007 14:54
27 lines
2353 bytes
Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid> writes:

> Dnia Wed, 21 Mar 2007 16:07:41 +0100, Piotr Dembiński skrobie:
>> Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
>> writes:
>
>> [...]
>
>> >> Twierdzisz, że domknięcia i iteratory nie występują
>> >> w rzeczywistości?
>> >
>> > No, na przykład. Co do iteratorów, to jeszcze można by się
>> > spierać.
>
>> Domknięcia są jeszcze łatwiejsze.  IMO każdy nie komunikujący się
>> z otoczeniem, spełniający dowolną funkcję komputer tworzy
>> domknięcie.
>
> Moment, rozwiążmy najpierw problem niejednoznaczności określenia
> "domknięcie".
>
> Jeśli pod pojęciem "domknięcie" masz na myśli lokalną funkcję mającą
> dostęp do środowiska funkcji zewnętrznej, to porównanie tego
> z komputerem odciętym od sieci przebija o wiele długości metody
> porównawcze "rogatego szefa Dilberta".

A mi się zawsze wydawało, że domknięcie to funkcja zachowująca stan.
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15773
Author: SasQ
Date: Sun, 01 Apr 2007 10:24
17 lines
1797 bytes
Dnia Thu, 01 Mar 2007 10:51:10 +0000, Sektor van Skijlen napisał(a):

> Kopiowanie nie zachodzi dla obiektów typów niewartościowych, a
> jedynie dla obiektów typów wartościowych. Kopiowaniu podlega
> wtedy owa "wartość", która może być dowolnie przenoszona
> pomiędzy poszczególnymi obiektami.
>
> Natomiast obiekty niewartościowe, jak sama nazwa wskazuje,
> wartości nie mają, więc one podlegają klonowaniu - tworzy się
> nowy obiekt o nowej tożsamości. W obiektach wartościowych
> tożsamością jest wartość.

Coś w temacie typów wartościowych ;)
http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedIdioms.pdf

-- 
SasQ
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15757
Author: Sektor van Skijlen
Date: Wed, 16 Jan 2008 23:57
386 lines
18997 bytes
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 ) )

co w każdym normalnym języku (Qrczak by dodał "oraz C++" :) pisze się:

if ( s != "" )

A dodatkowo Java i C# dołączyły radośnie do języka C w gronie języków, które
rozróżniają "null string" i "pusty string". Ja swojego współpracownika w
projekcie (lepiej się znającego na Javie) za nic tak nie goniłem, jak za
dopuszczanie do powstawania "null string".

> > Oczywiście teorię typów wartościowych i niewartościowych [...]
> > można olać, jeśli ktoś uważa, że mu nie pasuje. Tylko że
> > alternatywą jest stwierdzenie, że mamy kilka różnych definicji
> > porównania, kopiowanie płytkie i głębokie itd.

> Mógłbyś uściślić na czym polega związek typów wartościowych
> z płytkim/głębokim kopiowaniem?

Związek jest dokładnie żaden.

Albo stosujemy teorię typów wartościowych i niewartościowych (i wtedy mówimy o
kopiowaniu wartości, w tym wartości tych typów lub wartości
referencji/wskaźnika, a w przypadku typów niewartościowych co najwyżej o
klonowaniu, które dodatkowo nie musi być operacją dostępną dla każdego typu
lub niekoniecznie tworzyć faktycznie wierną kopię swojego wzorca), albo
twierdzimy, że to nam jest niepotrzebne i wtedy męczymy się z pojęciami
płytkiego i głębokiego kopiowania i uważamy, żeby kopiować tam, a nie kopiować
tu itd.

> > Nawiasem mówiąc, w Rubym spierdzielili sprawę ze stringami
> > totalnie. String w ogólności jest typem wartościowym - niestety
> > w Rubym jest on ehm... takim dziwnie-hybrydowym. To znaczy,
> > modyfikacje przenoszą się na inne obiekty oznaczane
> > identyfikatorami:
> >
> > a = "dupa"
> > b = a
> > b[0] = "p"
> > print a

> A czy w Javie przypadkiem nie jest tak samo?
> No chyba że tam się wtedy robi kopia przy modyfikacji przez b.
> Już nie pamiętam...

To zależy.

W Javie przytomnie zdecydowano, że String jest typem stałym (nie można
modyfikować tego obiektu w miejscu - obiekt typu string posiada swoją tablicę
znaków nadaną w momencie tworzenia once forever). Natomiast StringBuffer i
StringBuilder jak najbardziej (nazwy tych typów zasługują na osobny wątek: oba
robią dokładnie to samo i mają nawet chyba taki sam interfejs, a różnią się
tylko tym, że w jednym z nich operacje są synchronizowane: który to z nich,
kto potrafi odpowiedzieć z pamięci?).


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15771
Author: Sektor van Skijlen
Date: Thu, 24 Jan 2008 20:05
36 lines
3053 bytes
We hate the truth, and they hide it from
us. We desire flattery, and they flatter us. We like to be deceived, and
they deceive us.

So each degree of good fortune which raises us in the world removes us
farther from truth, because we are most afraid of wounding those whose
affection is most useful and whose dislike is most dangerous. A prince may
be the byword of all Europe, and he alone will know nothing of it. I am not
astonished. To tell the truth is useful to those to whom it is spoken, but
disadvantageous to those who tell it, because it makes them disliked. Now
those who live with princes love their own interests more than that of the
prince whom they serve; and so they take care not to confer on him a benefit
so as to injure themselves.

This evil is no doubt greater and more common among the higher classes; but
the lower are not exempt from it, since there is always some advantage in
making men love us. Human life is thus only a perpetual illusion; men
deceive and flatter each other. No one speaks of us in our presence as he
does of us in our absence. Human society is founded on mutual deceit; few
friendships would endure if each knew what his friend said of him in his
absence, although he then spoke in sincerity and without passion.

Man is, then, only disguise, falsehood, and hypocrisy, both in himself and
in regard to others. He does not wish any one to tell him the truth; he
avoids telling it to others, and all these dispositions, so removed from
justice and reason, have a natural root in his heart.

101. I set it down as a fact that if all men knew what each said of the
other, there would not be four friends in the world. This is apparent from
the quarrels which arise from the indiscreet tales told from time to time. I
say, further, all men would be...

102. Some vices only lay hold of us by means of others, and these, like
branches, fall on removal of the trunk.

103. The example of Alexander's chastity has not ma
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15772
Author: SasQ
Date: Thu, 24 Jan 2008 20:16
32 lines
2640 bytes
because they do not pray.

Et tu conversus confirma fratres tuos. But before, conversus Jesus respexit
Petrum.147

Saint Peter asks permission to strike Malchus and strikes before hearing the
answer. Jesus Christ replies afterwards.

The word, Galilee, which the mob pronounced as if by chance, in accusing
Jesus Christ before Pilate, afforded Pilate a reason for sending Jesus
Christ to Herod. And thereby the mystery was accomplished, that He should be
judged by Jews and Gentiles. Chance was apparently the cause of the
accomplishment of the mystery.

745. Those who have a difficulty in believing seek a reason in the fact that
the Jews do not believe. "Were this so clear," say they, "why did the Jews
not believe"? And they almost wish that they had believed, so as not to be
kept back by the example of their refusal. But it is their very refusal that
is the foundation of our faith. We should be much less disposed to the
faith, if they were on our side. We should then have a more ample pretext.
The wonderful thing is to have made the Jews great lovers of the things
foretold, and great enemies of their fulfilment.

746. The Jews were accustomed to great and striking miracles, and so, having
had the great miracles of the Red Sea and of the land of Canaan as an
epitome of the great deeds of their Messiah, they therefore looked for more
striking miracles, of which those of Moses were only the patterns.

747. The carnal Jews and the heathen have their calamities, and Christians
also. There is no Redeemer for the heathen, for they do not so much as hope
for one. There is no Redeemer for the Jews; they hope for Him in vain. There
is a Redeemer only for Christians
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15758
Author: Radoslaw Jocz
Date: Tue, 01 Apr 2008 18:39
326 lines
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()
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15760
Author: Sektor van Skijlen
Date: Tue, 01 Apr 2008 22:34
19 lines
2342 bytes
Dnia Tue, 01 Apr 2008 19:39:25 +0100, Radoslaw Jocz skrobie:
> > 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()

Ładniej wygląda, oczywiście, tylko ma paskudną wadę - jeśli s jest null to
rzuca NullPointerException.


-- 
//  _    ___         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"
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15761
Author: Piotr Kobzda
Date: Wed, 02 Apr 2008 07:54
19 lines
2158 bytes
Sektor van Skijlen wrote:
> Dnia Tue, 01 Apr 2008 19:39:25 +0100, Radoslaw Jocz skrobie:
>>> 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()
> 
> Ładniej wygląda, oczywiście, tylko ma paskudną wadę - jeśli s jest null to
> rzuca NullPointerException.

Dlaczego paskudną?  Ja zwykle właśnie NPE rzucam gdy mam nieoczekiwanego 
nulla, a dzięki s.equals("") mam oczekiwany efekt za darmo.


piotr
Re: pl.comp.objects FAQ (Frequently Asked Questions and more)
#15762
Author: Sektor van Skijlen
Date: Wed, 02 Apr 2008 08:04
39 lines
3656 bytes
Dnia Wed, 02 Apr 2008 09:54:47 +0200, Piotr Kobzda skrobie:
> Sektor van Skijlen wrote:
> > Dnia Tue, 01 Apr 2008 19:39:25 +0100, Radoslaw Jocz skrobie:
> >>> 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()
> > 
> > Ładniej wygląda, oczywiście, tylko ma paskudną wadę - jeśli s jest null to
> > rzuca NullPointerException.

> Dlaczego paskudną?  Ja zwykle właśnie NPE rzucam gdy mam nieoczekiwanego 
> nulla, a dzięki s.equals("") mam oczekiwany efekt za darmo.

Problem polega właśnie na tym, że wyjątki, jako forma Runtime Error, objawiają
się dopiero w działaniu. Rozumiem, że możesz chcieć, aby taki wyjątek właśnie
wystąpił, ale musisz mieć pełną świadomość tego, że tak właśnie jest.

Natomiast w Javie - podobnie jak w języku C - w większości przypadków null
traktuje się jak pusty string (właśnie dlatego, że możliwość bycia przez
string null-em jest nadmiarową i nieużywaną właściwością, w wyniku czego
jedynie sprawia problemy). Znalazłem co prawda w bibliotece standardowej kilka
przypadków, kiedy podanie null zamiast stringa traktowano jako określony
szczególny przypadek - ale wszędzie tam ową szczególność można było zaznaczyć
inaczej, natomiast w większości przypadków jak przyjmujemy w metodzie stringa,
to chcemy dostać stringa, a nie null.

W Javie, podobnie jak w języku C, zapewnienie tego jest niemożliwe. Już nawet
w bazach danych się da.

-- 
//  _    ___         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"
Page 2 of 2 • 79 total messages
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads