W teorii języków programowania typ jest zbiorem wartości. Np. Typ „int” jest zbiorem wszystkich wartości całkowitych.
W językach OOP klasa jest typem, prawda?
Gdy klasa jest zdefiniowana z więcej niż jednym członkiem, np
class myclass{
int a;
double b;
}
Mówiąc o klasie, mamy na myśli
- „
(a,b)
gdziea
jest liczbą całkowitą ib
jest podwójną”, lub - „{
(x,y)
|x
is any int,y
is any double}”?
Co oznacza przykład myclass
?
- „
(a,b)
gdziea
jest liczbą całkowitą ib
jest podwójną”, lub - obiekt, który zajmuje przestrzeń pamięci i który może (niekoniecznie tj. może być pusty) przechowywać
(x,y)
, gdziex
jest dowolna liczba całkowita i czyy
jest ona podwójna?
a
ib
są członkami tego typu, jak wspomina Killian Forth. Myclass jest izomorficzny w stosunku do rekordów z polamia
ib
typuint
idouble
- możesz wziąć taki rekord i przekształcić go w instancjąmyclass
.Odpowiedzi:
Ani.
Rozumiem, że pytasz, czy posiadanie tego samego zestawu typów pól wystarczy, aby zaklasyfikować je jako tę samą klasę, czy też należy je nazwać identycznie. Odpowiedź brzmi: „Nie wystarczy mieć te same typy i te same nazwy!” Klasy równoważne strukturalnie niekoniecznie są zgodne z typem.
Na przykład, jeśli masz
CartesianCoordinates
i doPolarCordinates
klasy, to może zarówno mieć dwa numery w swoich dziedzinach, a może nawet mieć ten samNumber
typ i te same nazwy, ale nadal nie jest zgodny, a instancjaPolarCoordinates
nie byłoby wystąpienieCartesianCoordinates
. Możliwość oddzielania typów według zamierzonego celu, a nie ich bieżącej implementacji, jest bardzo przydatną częścią pisania bezpieczniejszego, łatwiejszego w utrzymaniu kodu.źródło
interface
w Javę i C #, jeśli kiedykolwiek chcesz przeprowadzić testy jednostkowe. W końcu piszesz masę płyt kotłowych, abyś mógł zmienić konkretną klasę, z której będzie korzystał twój program, nawet jeśli nie masz zamiaru go zmieniać w czasie wykonywania.Typy nie są zestawami.
Widzisz, teoria mnogości ma wiele cech, które po prostu nie dotyczą typów i odwrotnie . Na przykład obiekt ma jeden typ kanoniczny. Może to być wystąpienie kilku różnych typów, ale tylko jeden z tych typów został użyty do jego utworzenia. Teoria zbiorów nie ma pojęcia zbiorów „kanonicznych”.
Teoria zbiorów pozwala tworzyć podzestawy w locie , jeśli masz regułę opisującą, co należy do tego podzbioru. Teoria typów na ogół na to nie pozwala. Chociaż większość języków ma
Number
typ lub coś podobnego, nie ma takiegoEvenNumber
typu, a jego utworzenie nie byłoby proste. To znaczy, dość łatwo jest zdefiniować sam typ, ale wszelkie istniejące,Number
które się zdarzają, nie zostaną magicznie przekształcone wEvenNumber
s.W rzeczywistości powiedzenie, że można „tworzyć” podzbiory, jest nieco nieuczciwe, ponieważ zestawy są zupełnie innym rodzajem zwierząt. W teorii zbiorów te podzbiory już istnieją , na wszystkie nieskończone sposoby, jak je zdefiniować. W teorii typów zwykle oczekujemy, że będziemy mieć do czynienia ze skończoną (jeśli dużą) liczbą typów w danym momencie. Jedynymi typami, o których mówi się, że istnieją, są te, które faktycznie zdefiniowaliśmy, nie każdy typ, który moglibyśmy zdefiniować.
Zestawy nie mogą zawierać się bezpośrednio lub pośrednio . Niektóre języki, takie jak Python, zapewniają typy o mniej regularnych strukturach (w Pythonie
type
typem kanonicznym jesttype
iobject
jest uważany za przykładobject
). Z drugiej strony większość języków nie pozwala typom zdefiniowanym przez użytkownika angażować się w tego rodzaju oszustwa.Zestawy zwykle mogą się nakładać, ale nie są ze sobą powiązane. Jest to rzadkie w teorii typów, chociaż niektóre języki obsługują ją w postaci wielokrotnego dziedziczenia. Inne języki, takie jak Java, dopuszczają tylko ograniczoną formę tego lub całkowicie go zabraniają.
Pusty typ istnieje (nazywany jest typem dolnym ), ale większość języków go nie obsługuje lub nie uważa go za typ pierwszej klasy. „Typ zawierający wszystkie inne typy” również istnieje (nazywany jest typem górnym ) i jest szeroko obsługiwany, w przeciwieństwie do teorii mnogości.
Uwaga : Jak zauważyli wcześniej niektórzy komentatorzy (zanim wątek został przeniesiony na czat), możliwe jest modelowanie typów za pomocą teorii mnogości i innych standardowych konstrukcji matematycznych. Na przykład można modelować członkostwo typu jako relację, a nie modelować typy jako zestawy. Ale w praktyce jest to o wiele prostsze, jeśli użyjesz teorii kategorii zamiast teorii mnogości. Tak na przykład Haskell modeluje swoją teorię typów.
Pojęcie „podtypu” naprawdę różni się od pojęcia „podzbioru”. Jeśli
X
jest podtypemY
, oznacza to, że możemy zastąpić wystąpieniaY
wystąpieniami,X
a program nadal będzie w pewnym sensie „działał”. Jest to raczej behawioralne niż strukturalne, chociaż niektóre języki (np. Go, Rust, prawdopodobnie C) wybrały ten drugi ze względów wygody, albo dla programisty, albo dla implementacji języka.źródło
Algebraiczne typy danych są sposobem na omówienie tego.
Istnieją trzy podstawowe sposoby łączenia typów:
Produkt. Właśnie o tym myślisz:
jest rodzajem produktu; jego wartości to wszystkie możliwe kombinacje (tj. krotki) jednego
int
i jednegodouble
. Jeśli weźmiesz pod uwagę typy liczb jako zbiory, to liczność rodzaju produktu jest w rzeczywistości iloczynem liczności pól.Suma. W językach proceduralnych jest to trochę niewygodne do wyrażania bezpośrednio (klasycznie dzieje się to za pomocą oznaczonych związków ), więc dla lepszego zrozumienia, oto typ sumy w Haskell:
wartości tego typu mają albo postać
AnInt 345
, alboADouble 4.23
, ale zawsze dotyczy tylko jednej liczby (w przeciwieństwie do typu produktu, gdzie każda wartość ma dwie liczby). Więc liczność: najpierw wyliczyć wszystkieInt
wartości, każda musi być połączona zAnInt
konstruktorem. Plus wszystkieDouble
wartości, każda w połączeniu zADouble
. Stąd typ sumy .Potęgowanie 1 . Nie będę tutaj omawiać tego szczegółowo, ponieważ w ogóle nie ma wyraźnej korespondencji OO.
A co z zajęciami? Celowo użyłem słowa kluczowego
struct
zamiastclass
dlaIntXDouble
. Chodzi o to, że klasa jako typ nie jest tak naprawdę charakteryzowana przez pola, są to jedynie szczegóły implementacji. Decydującym czynnikiem jest raczej to, jakie wyróżniające się wartości może mieć klasa.Co jest istotne, choć jest wartość klasa może być Wartości każdy na jego podklasy ! Tak więc klasa jest w rzeczywistości rodzajem sumy, a nie typem produktu: jeśli
A
iB
oba byłyby wyprowadzone zmyClass
,myClass
to zasadniczo byłaby sumąA
iB
. Niezależnie od faktycznego wdrożenia.1 To są funkcje (w sensie matematycznym! ); typ funkcji
Int -> Double
jest reprezentowany przez wykładniczyDouble
Int
. Szkoda, że twój język nie ma odpowiednich funkcji ...źródło
static
metody, z tą różnicą, że wciąż nie są one pierwszorzędnymi wartościami. Rzecz w większości języków OO polega na tym, że przyjmują obiekty jako najmniejszy element konstrukcyjny, więc jeśli chcesz czegoś mniejszego , musisz sfałszować go z obiektami, a wciąż kończy się przeciąganie wielu funkcji semantyki. Np. Porównywanie funkcji dla równości nie ma sensu, ale nadal można porównywać dwa faux-obiekty.Przepraszam, ale nie wiem o teorii „surowej”. Mogę tylko zapewnić praktyczne podejście. Mam nadzieję, że jest to dopuszczalne na programmers.SE; Nie znam tu etykiety.
Głównym tematem OOP jest ukrywanie informacji . To, kim dokładnie są członkowie danych klasy, nie powinno być interesujące dla jej klientów. Klient wysyła komunikaty do (metod wywoływania / funkcji członkowskich) instancji, która może modyfikować stan wewnętrzny. Chodzi o to, że elementy wewnętrzne klasy mogą ulec zmianie bez wpływu na klienta.
Następstwem tego jest to, że klasa jest odpowiedzialna za zapewnienie, że jej wewnętrzna reprezentacja pozostaje „ważna”. Załóżmy klasę, która przechowuje (uproszczony) numer telefonu w dwóch liczbach całkowitych:
Są to członkowie danych klasy. Jednak klasa prawdopodobnie będzie czymś znacznie więcej niż tylko elementami danych, a na pewno nie można jej zdefiniować jako „zestawu wszystkich możliwych wartości int x int”. Nie powinieneś mieć bezpośredniego dostępu do członków danych.
Konstrukcja instancji może odmówić jakichkolwiek liczb ujemnych. Być może konstrukcja w jakiś sposób znormalizuje areakodę, a nawet zweryfikuje liczbę całkowitą. W ten sposób skończyłbyś znacznie bliżej swojego
"(a,b) where a is an int and b is a double"
, ponieważ z pewnością nie ma w nim żadnych dwóch int.Ale to tak naprawdę nie ma znaczenia, jeśli chodzi o klasę. To nie jest ani rodzaj członków danych, ani zakres ich możliwych wartości, które określa klasę, to te metody , które są zdefiniowane dla niego.
Tak długo, jak metody te pozostaną takie same, implementator może zmienić typy danych na zmiennoprzecinkowe, BIGNUM, ciągi znaków, cokolwiek, i dla wszystkich praktycznych celów, nadal będzie to ta sama klasa .
Istnieją wzorce projektowe zapewniające, że takie zmiany wewnętrznej reprezentacji mogą być dokonywane bez zdawania sobie z tego sprawy przez klienta (np. Idiom pimpl w C ++, który ukrywa elementy danych za nieprzezroczystym wskaźnikiem ).
źródło
It is neither the type of the data members, nor the range of their possible values that defines the class, it's the methods that are defined for it.
Członkowie danych nie definiują klasy tylko wtedy, gdy ją ukryjesz. To może być najczęstszy przypadek, ale z pewnością nie można powiedzieć, że dotyczy to wszystkich klas. Jeśli choćby jedno pole jest publiczne, jest tak samo ważne jak jego metody.class
es. (Oznaczenie ichfinal
pomaga uzyskać punkt, ale nadal). Nadal masz jednak problem zprotected
elementami członkowskimi, które można dziedziczyć, a zatem stanowią one część drugiego interfejsu API dla implementatorów podklas.protected
jak to możliwe w praktyce. ;-))class
jest konstrukcją zależną od języka. O ile wiem, nie ma czegoś takiego jakclass
teoria typów.Typ jest opis kategorii / zakres wartości, struktur złożonych, lub co ty. W przeciwnym razie jest to podobne do „interfejsu”. (W sensie agnostycznym języka. Nie tyle specyficzne dla języka. Na przykład w Javie
int
jest typem , ale nie ma związku zeinterface
specyfikacją pola publicznego / chronionego również nie jest częściąinterface
, ale są częścią „interfejsu” lub typu ).Najważniejsze jest to, że jest to bardziej definicja semantyczna niż konkretna. Struktura uwzględnia tylko czynniki, o ile odsłonięte pola / zachowania i ich określone cele są zgodne. Jeśli nie masz obu, nie masz kompatybilności typu.
Klasa jest realizacja określonego typu. Jest to szablon, który faktycznie określa wewnętrzną strukturę, dołączone zachowanie itp.
źródło