Typy w językach i systemach obiektowych (i nie tylko) Cześć 2.

24
K.Subieta. Typy w systemach obiektowych, część 2, Folia 1 Maj 1998 Typy w językach i systemach obiektowych (i nie tylko) Cześć 2. Kazimierz Subieta Instytut Podstaw Informatyki PAN, Warszawa [email protected] http://www.ipipan.waw.pl/~subieta Polsko-Japońska Wyższa Szkoła Technik Komputerowych, Warszawa

description

Typy w językach i systemach obiektowych (i nie tylko) Cześć 2. Kazimierz Subieta Instytut Podstaw Informatyki PAN, Warszawa [email protected] http://www.ipipan.waw.pl/~subieta Polsko-Japońska Wyższa Szkoła Technik Komputerowych, Warszawa. Zmienność. mutability. - PowerPoint PPT Presentation

Transcript of Typy w językach i systemach obiektowych (i nie tylko) Cześć 2.

Page 1: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 1 Maj 1998

Typy w językach i systemach obiektowych

(i nie tylko)

Cześć 2.

Kazimierz Subieta

Instytut Podstaw Informatyki PAN, Warszawa

[email protected]://www.ipipan.waw.pl/~subieta

Polsko-Japońska Wyższa SzkołaTechnik Komputerowych, Warszawa

Page 2: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 2 Maj 1998

Zmienność

Zmienność jest dodatkową własnością, która może być przypisana do bytu programistycznego (zmiennej, obiektu, parametru) lub, poprzez reguły wnioskowania o poprawności typologicznej, do wyrażenia.

Byt posiadający tę własność może podlegać istotnej operacji, mianowicie aktualizacji. Tej operacji nie można wykonywać na bycie nie posiadającej tej własności.

Np. wartość 5 nie posiada własności zmienności; operacja (2+3) := 6 powinna zostać odrzucona ze względów typologicznych.

Dla zmiennej int X operacja X := 6 jest legalna.

Wartość 5 nie ma przypisanej własności zmienności, zaś zmiennej X przypisuje się taką własność. Potrzeba przypisywania własności zmienności do bytów programistycznych jest konsekwencją używania w tym samym kontekście syntaktycznym tego samego typu zarówno dla wartości jak i zmiennej przechowującej taką wartość.

mutability

Page 3: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 3 Maj 1998

Semantyka cechy zmiennościWiększość języków programowania dokonuje przypisania atrybutu zmienności poprzez reguły syntaktyczne rozróżnienie deklaracji stałych i deklaracji zmiennych. Ten sposób zastosowano również w standardzie ODMG gdzie projektant ma możliwość rozróżnienia pomiędzy obiektami, tj. bytami z przypisanym atrybutem zmienności, oraz literałami (literals), tj. bytami których nie można zmieniać; poza własnością zmienności cechy obiektów i literałów koncepcyjnie niewiele się różnią.

Własność zmienności przypisuje się do parametrów procedur. W językach z rodziny Pascala każdy parametr formalny z atrybutem zmienności jest poprzedzany słowem kluczowym var. W standardzie ODMG i wielu innych językach takim słowem jest out. Ta deklaracja oznacza, że odpowiednie wyrażenie będące parametrem aktualnym tej procedury ma wartościować się do bytu programistycznego, który posiada własność zmienności. Oznacza ona również, że wewnątrz ciała procedury aktualizacje tego parametru nie dotyczą parametru jako takiego, lecz tego bytu programu (zwykle zmiennej, obiektu, atrybutu) na który taki parametr wskazuje. Technikę tę określa się jako call-by-reference.

Z reguły przypisanie atrybutu zmienności do pewnego bytu w tekście programu oznacza, że wynikiem jego wiązania będzie referencja.

Page 4: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 4 Maj 1998

Przykład zastosowania zmiennościvoid zmień(out int MojaZmienna) begin

int X; czytaj( X ); //Wczytanie wartości X z klawiatury MojaZmienna = X;

end;

Taka procedura może być wywołana w następującym kontekście;

typedef TypPrac = struct { string Nazwisko, int Rok_urodz, int Zarobek }....TypPrac Pracownik;Pracownik = (Nazwisko: „Nowak”, Rok_urodz: 1955, Zarobek: 3000);zmień( Pracownik . Zarobek );

Istotne w tym programie jest to, że chcemy w niej zmienić zarobek Nowaka, wczytując go z klawiatury. Deklaracja out int MojaZmienna oznacza, że jako parametru oczekujemy refererencji do zewnętrznego bytu programistycznego, który posiada własność zmienności. Ta referencja uzyskuje wewnątrz procedury lokalną nazwę MojaZmienna.

zmień( Pracownik.Zarobek + 1000 ); ! Błąd typu

Page 5: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 5 Maj 1998

Inne techniki określania zmiennościNiektóre instrukcje języka programowania dokonują przypisania zmienności implicite. Np. instrukcja

wyrażenie1 := wyrażenie2;

ustala, że wyrażenie1 ma zostać zwartościowane do wartości zmienialnej. Taką wartość określa się jako L-value, od słowa Left oznaczającego, że dotyczy to lewej strony podstawienia.

wyrażenie2 po ewaluacji zwraca wartość, która nie musi mieć własności zmienialności. Taką wartość określa się jako R-value, od słowa Right oznaczającego, że dotyczy to prawej strony podstawienia.

Podobnie instrukcja usuwania obiektu o przykładowej postaci

delete wyrażenie;

oczekuje, że wyrażenie zostanie zwartościowane do L-value; w przeciwnym przypadku sygnalizowany będzie błąd typu.

Page 6: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 6 Maj 1998

Programowanie ogólne

Programowaniem ogólnym nazywa się technikę tworzenie programów operujących nie na konkretnej strukturze danych, ale na szerokiej rodzinie takich struktur.

Przykładami programów ogólnych są: program sortujący dowolną listę, program wyświetlający zawartość dowolnej relacyjnej bazy danych, program tłumaczący dowolny program w Pascalu na program w C, kompilator, SZBD, itp.

Programowanie ogólne jest jedną z własności sprzyjających ponownemu użyciu (reuse). Jest ono nieodzownym składnikiem programowania systemowego.

Polimorfizm typów jest niezbędną cechą takiego języka programowania, który ma mieć jednocześnie możliwość programowania ogólnego oraz pełną statyczną kontrolę typów.

Niestety, jak wspomnieliśmy, polimorfizm typów wprowadza złożoność, która jest trudno akceptowalna dla programistów.

generic

Page 7: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 7 Maj 1998

Inne techniki programowania ogólnego

Z reguły, uniemożliwiają lub ograniczają mocną kontrolę typów.

Operatory zmiany typu (koercje) zmieniające struktury złożone na struktury prymitywne; np. cast w językach C i C++ umożliwia potraktowanie zapisu jak sekwencji bajtów. Niekiedy wiąże się to z przejściem na niższy poziom językowy,np. programowanie w assemblerze.

Funkcje wyższego rzędu, tj. funkcje, których parametrami są funkcje; przykładem udostępniania takiej techniki jest język LISP, ML, SCHEME oraz Smalltalk.

Parametryzowane klasy, klasy szablonowe (templates);

Refleksja (reflection), czyli dynamiczna generacja kodu programu. Programowanie z refleksją oznacza, że programista pisze program, który wygeneruje kawałek kodu; ten kod jest automatycznie uruchamiany z programu, który go utworzył. Technika ta wymaga późnego wiązania, jest również trudna dla programistów. Jej elementy można odnaleźć w dynamicznym SQL. Istnieją techniki, które pozwalają wprowadzić do mechanizmu refleksji statyczną kontrolę typu, ale zgodnie z naszą najlepszą wiedzą, nie wyszły one dotąd poza stadium teoretycznych rozważań.

Page 8: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 8 Maj 1998

Co to jest zgodność typów?Niech wyr będzie pewnym wyrażeniem języka programowania, które jest użyte jako aktualny parametr wywołania procedury proc(wyr). Procedura proc została zadeklarowana przez programistę jako

void proc( T par ) { ... };

gdzie T jest typem parametru formalnego par.

Podczas analizy składniowej poprzez zastosowanie reguł wnioskowania o typie, wyrażenie wyr jest odrzucone jako typologicznie niepoprawne, lub ma przypisany pewien typ, powiedzmy T1. Zarówno T jak i T1 są pewnymi wyrażeniami językowymi, które wiążą nazwy typów atomowych (int, real, char, boolean, ...), konstruktory typu (array, record, set, sequence,...), nazwy typów skonstruowanych przez programistę, nazwy pól w strukturach oraz inne elementy, w tym składniowe.

Powstaje pytanie, jaka powinna być zależność pomiędzy typem T i typem T1, aby wywołanie procedury proc(wyr) można było zakwalifikować jako typologicznie poprawne. Odpowiedź na to pytanie wyznacza zasadę zgodności typów.

Page 9: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 9 Maj 1998

Nazwowa zgodność typów (1)Klasyczne języki programowania, np. Pascal, przyjmują w takiej sytuacji tzw. zgodność nazwową. Oznacza ona, że typ T1 jest określony nazwą typu atomowego lub typu skonstruowanego przez programistę, zaś typ T musi być dokładnie tą samą nazwą. Jeżeli np. programista zdefiniował nowy typ, np. numer, który jest identyczny z typem integer, następnie zaś użył typu numer w deklaracji parametru procedury, to nie może następnie wywołać tej procedury z wyrażeniem typy integer, a wyłącznie z parametrem typu numer:

type numer = integer; TypZapisu = record X: numer, Y integer end;

... procedure proc( numer par ) ... ;

...var R: TypZapisu;

... proc( R.X ); (* Wywołanie typologicznie poprawne *) proc( R.Y ); (* Wywołanie typologicznie niepoprawne *)

Page 10: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 10 Maj 1998

Nazwowa zgodność typów (2)

Nazwowa zgodność typów jest dość łatwa w implementacji i posiada zalety dla modelowania pojęciowego. Umożliwia ona konstruowanie typów o różnej intencji pojęciowej.

Jak widać z powyższego przykładu, numer jest reprezentowany jako integer, ale jest pojęciowo innym typem. W szczególności (przyjmując ortodoksyjny punkt widzenia) nie wolno do niego stosować np. operacji +, gdyż nie została ona dla tego typu zdefiniowana.

Niestety, zgodność nazwowa okazała się też nieco niewygodna w wielu sytuacjach (głównie ograniczenie możliwości programowania generycznego). W związku z tym niektóre języki (np. Modula-2) stosuje się zgodność nazwową o dość liberalnych regułach; w szczególności, typy nazwane przejmują zestaw operacji z typu będącego podstawą ich definicji.

Nazwowa zgodność typów znalazła zastosowanie w nowym standardzie SQL3 w postaci tzw. typów rozróżnionych (distinct types).

Page 11: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 11 Maj 1998

Strukturalna zgodność typów

Strukturalna zgodność typów przyjmuje, że nazwa typu jest tylko zastępczym środkiem reprezentującym pewną strukturę i może być przez tę strukturę zastąpiona. Takie zastępowanie nazw wprowadzonych przez projektanta lub programistę przez odpowiadające im struktury prowadzi się aż do pełnego wyeliminowania tych nazw z wyrażenia językowego ustalającego typ.

Po takim zabiegu pozostają więc tylko nazwy typów atomowych, nazwy konstruktorów typów, nazwy pól w strukturach i pewien lukier syntaktyczny.

Metoda ta oznacza bardziej liberalną kontrolę typu. Przykładowo, przy zastosowaniu tej metody oba podane wyżej wywołania procedury proc są poprawne. Uważa się, że strukturalna zgodność typu bardziej pasuje do obiektowości (patrz omówioną wyżej własność zastępowania), jest koncepcyjnie prostsza i bardziej uniwersalna.

Mimo niekonsekwencji w zakresie modelowania pojęciowego, jest wystarczająco skuteczna.

Page 12: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 12 Maj 1998

Wady strukturalnej zgodności typówW niektórych sytuacjach strukturalna zgodność typów oraz splątanie pojęcia typu z pojęciem klasy prowadzą do paradoksów, które mają pewne odbicie w obiektowej literaturze. Przykładowo załóżmy, że klasa Prostokąt jest zdefiniowana jako typ

typedef Prostokąt = struct{int X, int Y}

gdzie X i Y oznaczają jego szerokość i wysokość, zaś klasa Kwadrat jest zdefiniowana jako typ

typedef Kwadrat = struct{int X}

gdzie X oznacza zarówno szerokość jak i wysokość. Nasze doświadczenie podpowiada, że kwadrat jest podklasą prostokąta. W tym przypadku okazuje się, że Prostokąt jest podklasą klasy Kwadrat, ponieważ ma więcej atrybutów!

Tego rodzaju paradoksy są skutkiem pewnej aproksymacji koncepcji typów, podtypów, klas i dziedziczenia w stosunku do modelowania pojęciowego. Podany przykład (jeden z wielu) świadczy o tym, że pojęcia obiektowości są jednak pewnym uproszczeniem w stosunku do sytuacji zdarzających się w modelowaniu pojęciowym. Prawdopodobnie każda formalna dyscyplina musi prowadzić do pewnych paradoksów pomiędzy potocznym odczuciem a własnościami formalnymi. Wyeliminowanie podanego wyżej paradoksu jest dość łatwe po rozpoznaniu jego istotnej przyczyny, ale powoduje skomplikowanie modelu obiektowego.

Page 13: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 13 Maj 1998

Rozszerzalność systemu typów

Cecha rozszerzalności systemu typów jest standardowa dla bardzo wielu języków, w szczególności, dla całej rodziny języków Pascalo-podobnych (Pascal, Modula, Ada, itp.).

Polega ona na tym, że istnieje pewien zestaw typów atomowych (integer, real, char, boolean, itd.) oraz pewien zestaw konstruktorów typów (array, record, set_of, sequence_of, itd). Programista ma możliwość definiowania typu poprzez zastosowanie typów atomowych oraz konstruktorów typów, zgodnie z pewnymi zasadami syntaktycznymi, ale w gruncie rzeczy bez większych ograniczeń w zakresie kombinowania i zagnieżdżania konstruktorów typów.

Co więcej, tak skonstruowany typ może nazwać i następnie posługiwać się tą nazwą w dalszych definicjach tak samo jak nazwą typu atomowego.

Page 14: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 14 Maj 1998

DBPL: przykład rozszerzania typów

Powyżej znajdują się nazwane definicje dwóch typów, TypDostawcy i TypRelacjiDostawcy. RECORD, ARRAY i RELATION są konstruktorami typów; CHAR i INTEGER są typami atomowymi. Mając tak zdefiniowane typy można zdefiniować dowolną liczbę zmiennych posiadających takie typy, np.

TYPETypDostawcy = RECORD nrdostawcy: ARRAY[0..2] OF CHAR;

nazwisko: ARRAY[0..19] OF CHAR;status: INTEGER;miasto: ARRAY[0..19] OF CHAR; END;

TypRelacjiDostawcy = RELATION nrdostawcy OF TypDostawcy;

VARMojDostawca: TypDostawcy; (* Zmienna dla przechowywania jednej krotki *)Dostawcy: TypRelacjiDostawcy; (* Deklaracja relacji Dostawcy *)ZwolnieniDostawcy: TypRelacjiDostawcy; (* Inna relacja tego samego typu *)

Page 15: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 15 Maj 1998

Rozszerzalność typów a model relacyjny

W popularnych relacyjnych systemach zarządzania bazami danych nie ma możliwości konstruowania i nazywania typów oraz ich wykorzystania do deklaracji struktur danych. Cecha rozszerzalności systemu typów jest obca dla ideologii relacyjnej, co spowodowało powstanie takiego tematu (mimo, że wydawało się, że przestał on istnieć od czasu Algolu).

Systemy relacyjne ograniczają system typów do jednego, z góry zdefiniowanego konstruktora typu (relacji) i nie dopuszczają ortogonalnej kombinacji tego i innych konstruktorów. Co więcej, systemy te wiążą w jednym zdaniu deklarację typu z deklaracją zmiennej (relacji) tego typu.

Te ograniczenia są konsekwencją rozwoju historycznego, ale także doktrynalnie przyjętych, ideologicznych ograniczeń modelu danych (podyktowanych dążeniem do prostoty lub rzekomej „zgodności” z przyjętym aparatem matematycznym).

Obiektowość słusznie zrywa z tego rodzaju ideologiczno-paranoicznymi ograniczeniami, postulując pełną ortogonalność i rozszerzalność systemu typów.

Page 16: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 16 Maj 1998

Cechy rozszerzalnego systemu typówSystem typów zawiera pewną liczbę typów atomowych, takich jak integer, real, char, itd.

System typów zawiera pewną liczbę konstruktorów typów (których elementami są wartości lub obiekty - w zależności od systemu), takich jak record, struct, array, oraz konstruktorów typów masowych, takich jak zbiór (set), wielozbiór (bag), sekwencja (sequence).

System typów daje możliwość deklarowania wariantów (lub unii, w terminologii C i C++);

System typów daje możliwość konstruowania nowych typów poprzez dowolne, ortogonalne zastosowanie konstruktorów typów do typów atomowych lub typów już skonstruowanych;Nie występują różnice w użyciu przez programistę typu atomowego i typu skonstruowanego;

System typów daje możliwość konstruowania sygnatur (specyfikacji parametrów wejściowych i wyniku) dla funkcji, procedur, operacji i metod.

System typów daje możliwość nazwania dowolnego typu atomowego, skonstruowanego, itd.

Zdefiniowaną nazwę typu można używać do konstruowania nowych typów lub sygnatur.

Deklaracja typu jest niezależna od deklaracji struktury danych (np. obiektu) tego typu. Dla jednego typu można zdefiniować dowolną liczbę struktur danych posiadających ten typ.

Page 17: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 17 Maj 1998

Co to znaczy “mocna kontrola typu”?Mocna kontrola typu oznacza, że wszystkie byty programistyczne (obiekty, zmienne, procedury, funkcje, metody, operacje, moduły, klasy, ADT) podlegają obowiązkowej specyfikacji typu, zaś każda operacja w programie (w szczególności, wyrażenia arytmetyczne i boolowskie, porównania, operatory podstawienia, wywołania procedur) jest sprawdzana na zgodność z tą specyfikacją. Ta kontrola odbywa się podczas czasu kompilacji programu (jest to określane jako kontrola statyczna); wyjątkowo, w nielicznych sytuacjach ta kontrola jest oddelegowana do czasu wykonania programu (jest to określane jako kontrola dynamiczna). Przykładami kontroli dynamicznej jest kontrola zakresu indeksów tablic lub kontrola poprawności użycia wariantów zapisów. Istotna kontrola typu powinna być kontrolą statyczną. Kontrola dynamiczna jest bardziej kosztowna, gdyż stanowi obciążenie czasu wykonania. Ponadto, jest znacznie mniej skuteczna, gdyż błąd typu może pozostać nie wykryty aż do momentu kiedy dany kawałek kodu zostanie wykonany, i to przy odpowiednim stanie. Z punktu widzenia własności niezawodnościowych systemów ten błąd typologiczny niczym nie różni się od innych błędów wykonania.

Page 18: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 18 Maj 1998

Wady mocnej kontroli typów

Mocna kontrola typu ma aspekty negatywne. Przede wszystkim, powoduje znaczne zmniejszenie mocy języka i jego elastyczności.

Klasycznym przykładem z języka Pascal jest uniemożliwienie napisania w tym języku procedur operujących na tablicach o dowolnych rozmiarach; np. procedury mnożącej dwie dowolne macierze. Tego rodzaju problemy muszą być rozwiązywane przy pomocy doraźnych programistycznych trików, np. poprzez programowanie wykorzystujące wskaźniki, które nie podlegają kontroli typów, nie są uniwersalne, oraz zaciemniają konstrukcję programu.

Własności takie jak: późne wiązanie, wartości zerowe (null values), warianty, perspektywy, procedury bazy danych, dynamiczne klasy, ewolucja schematu, etc. wymagają dynamicznej kontroli typu (zwykle, mało skutecznej) lub żmudnego ponownego kompilowania (konsolidowania) wszystkich napisanych programów po każdej dynamicznej zmianie środowiska w związku z wymienionymi wyżej cechami (np. po wprowadzeniu lub usunięciu perspektywy), co w wielu przypadkach jest nie do przyjęcia.

Page 19: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 19 Maj 1998

Elementy mocnej kontroli typów (1)Specyfikacja typów wszystkich zmiennych i obiektów, które występują w programie, włącznie z określeniem ich powiązań z innymi obiektami oraz metod, np.

typedef TypPrac = struct{ string nazwisko, int zarobek, Dział pracuje_w, int zarobek_netto( ) };TypPrac Pracownik;

Specyfikacja sygnatur wszystkich operatorów, procedur, funkcji, metod, np.

boolean sprawdź( in TypPrac prac, in TypDział dzial, out int ile_lat_pracuje )

Specyfikacja interfejsów modułów, klas i innych hermetyzowanych abstrakcji programistycznych.

Dla parametrów procedur, funkcji, metod: określenie które z nich są wejściowe (call-by-value), a które wyjściowe (call-by-reference). W zależności od tego, operacje na tych parametrach (np. podstawienie) mogą być dozwolone lub niedozwolone.

Page 20: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 20 Maj 1998

Elementy mocnej kontroli typów (2)

Określenie reguł wnioskowania o typie dla wszystkich konstrukcji składniowych języka programowania, szczególnie dla wyrażeń. Reguła wnioskowania o typie jest przypisana do danej produkcji gramatyki bezkontekstowej języka. Przyjmuje ona pewne założenia co do typów związanych z symbolami nieterminalnymi występującymi po prawej stronie takiej produkcji, następnie ustala regułę jaki będzie typ związany z symbolem nieterminalnym występującym po lewej stronie tej produkcji. Dzięki temu, w procesie analizy gramatycznej programu można wywnioskować jaki będzie wynikowy typ każdej konstrukcji, która w tym programie występuje. Przykładowo, jeżeli typ X jest integer (zmienialny), zaś typ Y jest real (zmienialny), to dla wyrażenia X + Y reguła wnioskowania o typie wyprowadzi typ real (niezmienialny).

W procesie analizy i wnioskowania o poprawności typologicznej ustalone są między innymi typy rzeczywistych parametrów aktualnych poszczególnych wywołań procedur, metod, etc. Te typy są porównywane z typami parametrów formalnych wyspecyfikowanymi przez programistę podczas deklaracji danej procedury lub metody. Niezgodności są sygnalizowane jako błędy typu.

Page 21: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 21 Maj 1998

Przykład reguły wnioskowania o typie

Niech produkcja gramatyczna ma postać:

predykat ::= wyrażenie1 = wyrażenie2

zaś T(symbol_nieterminalny) oznacza typ przypisany do danego symbolu nieterminalnego. Reguła wnioskowania o typie może mieć następującą postać:

T(wyrażenie1) {integer, real, char, boolean} and (T(wyrażenie1) = T(wyrażenie2) or (T(wyrażenie1) {integer, real} and T(wyrażenie2) {integer, real} ))

T(predykat) = boolean

poprzednik

następnik

Jeżeli w danym kontekście warunek poprzednika nie jest spełniony, to sygnalizowany jest błąd typu. Całości wyrażenia przypisywany jest typ podany w następniku.

Podana reguła jest bardzo uproszczona. Dochodzą do tego meta-reguły takie jak zasada zastępowania, kowariancja, itd. Typowa technika implementacyjna nosi nazwę gramatyk atrybutowych. Reguły takie są rozbudowywane o fragmenty wstawiające kawałki kodu do generowanego programu przeprowadzające kontrolę dynamiczną.

Page 22: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 22 Maj 1998

Warianty (unie) i wartości zeroweWarianty lub unie (variants, unions) i wartości zerowe (null values) są nieregularnościami w strukturach danych. Warianty służą do odwzorowania sytuacji w modelowaniu pojęciowym kiedy wystąpienia danej określonego typu mogą się różnić zestawem lub typem atrybutów. Np. :

Pracownik:( Nazwisko:"Nowak", Rodzaj:"etatowy", Zarobek:3000 )Pracownik:( Nazwisko:"Wrona", Rodzaj:"uczeń", Status:3, Stypendium:700 )

Obiekt pracownika Nowaka nie musi posiadać atrybutów Status i Stypendium, dzięki czemu zajmuje mniej pamięci. Tego rodzaju sytuacja jest modelowana jako „zapis z wariantami” (w rodzinie języków linii Pascala) lub unia (w rodzinie C i C++), np. (w składni C):

struct{ string Nazwisko; string Rodzaj; union{ int Zarobek; struct{ int Status; int Stypendium;} str; } un;

} Pracownik;

Warianty mogą posiadać atrybut (taki jak Rodzaj), który służy do rozróżnienia przypadku podczas czasu wykonania. Taki atrybut nazywa się dyskryminatorem.

Page 23: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 23 Maj 1998

Wartości zerowePojęcie wartości zerowej służy do podobnego celu jak pojęcie wariantu, chociaż jest koncepcyjnie nieco różne. Istnieje wiele powodów dla wartości zerowych, np.:

•Informacja jest nierelewantna, np. atrybut NazwiskoPanieńskie dla mężczyzn.•Informacja jest relewantna, lecz nie została jeszcze zapełniona („niezainicjowana zmienna”).•Informacja jest ważna tylko przez pewien czas.•Informacja jest znana i może być zapełniona, ale dla pewnych przypadków jest nieistotna.•Przy adaptacji heterogenicznych baz danych dane składają się ze starszych i młodszych zapisów, przy czym młodsze zawierają informacje wynikające z nowych wymagań na system; starsze zapisy tej informacji nie posiadają.

Warianty są z należytym respektem traktowane w językach programowania, natomiast wartości zerowe raczej nie; zwykle sprowadza się je do „wartości niezainicjowanej zmiennej” lub „zerowego wskaźnika”. W bazach danych ten stosunek jest dokładnie odwrotny: wartości zerowe uzyskały tam pierwszą kategorię obywatelstwa, podczas gdy o wariantach praktycznie się nie wspomina.

Z punktu widzenia poprawności typologicznej wartości zerowe implikują podobne problemy jak warianty. Trudności związane z wariantami i wartościami zerowymi spowodowały tendencję do ich eliminowania z języków programowania, np. z języków Java i Modula-3.

Page 24: Typy  w językach i systemach obiektowych (i nie tylko) Cześć 2.

K.Subieta. Typy w systemach obiektowych, część 2, Folia 24 Maj 1998

Warianty potraktowane jako odrębne klasy

OsobaNazwiskoRodzaj

PracownikZarobek

UczeńStatusStypendium

Przy takim potraktowaniu wariantów moze sie również okazać, że dyskryminator (w przykładzie atrybut Rodzaj) jest zbędny, gdyż ta sama informacja jest już odwzorowana.

W związku z możliwością zastąpienia wariantów przez hierarchię klas spotykane są poglądy, że pojęcie wariantu jest zbędne, a nawet sprzeczne z obiektowością. Zwrócimy uwagę, że warianty i wartości zerowe są cechą techniczną, która może mieć znaczenie dla modelowania pojęciowego. Brak wariantów i wartości zerowych powoduje wiele niekorzystnych konsekwencji dla modelu pojęciowego i modelu implementacyjnego, w szczególności, niepotrzebne zwiększenie (eksplozję) liczby klas, konieczność wielokrotnego dziedziczenia, trudności związane z aktualizacją obiektów (zmiana wariantu obiektu oznacza zmianę klasy do której obiekt należy), itd.