Obiektowe języki zapytań
Wykładowca: Kazimierz Subieta
Polsko-Japońska Wyższa Szkoła
Technik Komputerowych, Warszawa
subieta@pjwstk.edu.pl
Wykład 14:
Procedury,
procedury funkcyjne,
metody
Instytut Podstaw Informatyki PAN,
Warszawa
subieta@ipipan.waw.pl
© K.Subieta. Obiektowe języki zapytań 14, Folia 1
czerwiec 2004
Krótka charakterystyka procedur
Imperatywne języki programowania, w tym języki obiektowe, są
wyposażone w mechanizmy procedur.
Ich istotą jest to, że:
•
•
•
•
Hermetyzują dowolnie skomplikowane obliczenia,
Ich wnętrze jest niedostępne z zewnątrz,
Mogą być wywoływane z wielu miejsc,
Ich przystosowanie do konkretnego celu następuje poprzez określenie
parametrów lub poprzez efekty uboczne (czyli korzystanie ze stanu spoza
danej procedury lub zmiany tego stanu).
Procedury mogą być dalej podzielone na:
• Procedury właściwe i procedury funkcyjne (zwane też funkcjami);
• Procedury i metody;
• Procedury znajdujące się po stronie programu aplikacyjnego i
przechowywane w bazie danych.
Procedury właściwe nie zwracają wyniku, nie mogą więc być użyte jako
składniki wyrażeń, zaś procedury funkcyjne zwracają wynik i przez to ich
wywołania są szczególnymi przypadkami wyrażeń.
© K.Subieta. Obiektowe języki zapytań 14, Folia 2
czerwiec 2004
Procedury a metody
Jeżeli chodzi o podział na procedury i metody, różnica dotyczy miejsca
logicznego ulokowania kodu procedur oraz sposobu ich wywołania.
Procedury są zwykle ulokowane w określonych jednostkach programu,
np. w modułach,
Metody są ulokowane logicznie w klasach.
• Dodatkowo, niejawnym (pośrednim) parametrem metody jest obiekt, na
którym ta metoda działa.
• Metodę funkcyjną (zwracającą wynik) nazywa się niekiedy atrybutem
wirtualnym.
• Poza tym, różnice pomiędzy procedurami i metodami są drugorzędne
• wbrew twierdzeniom niektórych zwolenników obiektowych języków
programowania.
Popularne w obiektowości „wysyłanie komunikatu do obiektu” jest
dokładnie tym samym co wywołanie procedury/metody działającej na
tym obiekcie.
• Inne interpretacje są nad-interpretacjami lub niekompetencją.
© K.Subieta. Obiektowe języki zapytań 14, Folia 3
czerwiec 2004
Procedury pierwszej i drugiej kategorii program.
Tradycyjnie, procedury po kompilacji są nierozerwalną częścią danego
programu aplikacyjnego (są drugiej kategorii programistycznej),
W związku z czym nie można ich podczas czasu wykonania usunąć,
wstawić, zmienić, itd.
W systemach BD pojawił się inny typ procedury, zwany zapamiętaną
procedurą (stored procedure) lub procedurą bazy danych (database
procedure).
•
•
•
•
Są pierwszej kategorii programistycznej, wiązane dynamicznie.
Można je dynamicznie tworzyć, usuwać lub zmieniać.
Są pisane w specjalnym interpretowanym języku, np. w PL/SQL.
Nie mogą być pisane w klasycznych lub obiektowych językach
programowania takich jak C++ lub Java.
Możliwa jest dowolna kombinacja tych opcji.
• Np. w systemie Oracle występują zapamiętane metody, czyli kombinacja
procedur bazy danych i metod.
• Znane z SQL perspektywy (views) można uważać za zapamiętane procedury
funkcyjne.
© K.Subieta. Obiektowe języki zapytań 14, Folia 4
czerwiec 2004
Efekty uboczne procedur/metod
Efekt uboczny jest to działanie procedury na innym środowisku niż
własne lokalne środowisko.
• Pasywny efekt uboczny – procedura korzysta z innego środowiska.
• Aktywny efekt uboczny – procedura dokonuje zmian w zewnętrznym
środowisku.
Efekty uboczne są podstawą technik programistycznych.
• Projektanci języków nie ograniczają możliwości dostępu do zasobów
zewnętrznych, w tym danych globalnych i danych z bazy danych, oraz
aktualizacji tych zasobów.
• Niestety styl specyfikacji procedur często ignoruje fakt, że mogą one mieć
efekty uboczne.
W oryginalnej propozycji Parnasa dotyczącej modułów efekty uboczne
były uwzględnione w postaci tzw. list importowych.
• Rozwiązanie to zostało zastosowane w języku Modula-2 (następca Pascala).
• Brak specyfikacji i kontroli efektów ubocznych w popularnych językach
programowania, takich jak C++ i Java jest zwiększaniem skłonności
oprogramowania do błędów (katastrofą rakiety Ariane-5 była spowodowany
brakiem wyspecyfikowanych efektów ubocznych)
© K.Subieta. Obiektowe języki zapytań 14, Folia 5
czerwiec 2004
Procedury/metody rekurencyjne
Procedury/metody mogą być rekurencyjne, co implikuje konieczność
stosowania dyscypliny w zakresie komunikowania parametrów oraz
mechanizmu kontrolującego zakresy obowiązywania nazw użytych w
ciałach procedur oraz wiązania tych nazw.
Mechanizmy te są oparte o ten sam stos środowiskowy znany nam z
poprzednich wykładów.
Dalej pokażemy w jaki sposób ten stos będzie przystosowany do
wspomagania wszelkiego rodzaju procedur (w tym metod).
Będziemy przy tym przyjmować, że zarówno parametry procedur jak i
wynik procedur funkcyjnych będą określone poprzez zapytania.
© K.Subieta. Obiektowe języki zapytań 14, Folia 6
czerwiec 2004
Parametry procedur
Procedury mogą mieć parametry.
W odróżnieniu od funkcji matematycznych, gdzie w zasadzie nie mówi
się o sposobach komunikowania parametrów, w językach programowania
wykształciło się kilka dobrze rozpoznanych metod komunikowania
parametrów o istotnych różnicach semantycznych.
Dalej podamy krótki ich przegląd.
Niektóre z tych metod będą omówione dla przypadku parametrów
będących zapytaniami.
Możliwe są nowe metody nie spotykane lub rzadko spotykane w
literaturze.
• Przykładem jest wołanie, w którym każdy parametr aktualny jest skojarzony z
nazwą parametru formalnego.
• Umożliwia to przy wywołaniu dowolną kolejność parametrów oraz pomijanie
parametrów (zastępowanie ich wartościami domyślnymi).
© K.Subieta. Obiektowe języki zapytań 14, Folia 7
czerwiec 2004
Wołanie poprzez wartość (call-by-value)
Jest to technika przekazywania argumentu procedury (lub metody) do jej
wnętrza, w której przekazywana jest wartość argumentu obliczona przed
przekazaniem sterowania do wnętrza procedury.
Jeżeli argumentem jest referencja, to dokonuje się automatycznie
dereferencji.
W niektórych językach (C/C++) tworzy się lokalną zmienną zawierającą
kopię wartości przekazanej jako argument.
Zmienna ta ma nazwę parametru formalnego i można ją aktualizować tak
jak zwykłą lokalną zmienną.
W innych językach (Pascal, Modula-2) taka aktualizacja takiej zmiennej
jest zabroniona, gdyż parametr w ciele procedury jest inaczej traktowany
niż zmienna.
© K.Subieta. Obiektowe języki zapytań 14, Folia 8
czerwiec 2004
Wołanie poprzez referencję (call-by-reference)
Technika przekazywania argumentu procedury (lub metody) do jej
wnętrza, w której przekazywana jest referencja do obiektu.
Dzięki temu wewnątrz procedury można dokonać zmiany stanu
(aktualizacji) obiektu zewnętrznego w stosunku do tej procedury.
Wołanie przez referencję jest kojarzone z własnością zmienności
(mutability).
Obiekt przekazywany poprzez referencję jest dostępny w ciele procedury
nie pod swoją nazwą, lecz pod nazwą jej odpowiedniego parametru
formalnego.
Wołanie przez referencję musi być odróżnione od innych sposobów
wołania poprzez składnię.
• W językach Pascalo-podobnych jest to słowo kluczowe var.
• W innych językach (np. IDL CORBA) są to słowa kluczowe inout oraz out;
drugie z nich oznacza, że komunikowany obiekt (zmienna) może nie być
zainicjowany, wobec czego nie wolno go czytać.
• Dla symetrii, w takich systemach wołanie przez wartość oznacza się słowem
kluczowym in.
© K.Subieta. Obiektowe języki zapytań 14, Folia 9
czerwiec 2004
Ścisłe wołanie przez wartość (strict-call-by-value)
W technice tej nie występuje zróżnicowanie na wołanie przez wartość i
wołanie przez referencję.
Jeżeli komunikowana jest wartość, to jest ona przekazywana do ciała
procedury tak jak w wołaniu przez wartość.
Jeżeli komunikowana jest referencja (pointer), to bez żadnych zmian
przekazywany jest on do wnętrza procedury, tak jak w wołaniu przez
referencję.
Przykładem zastosowania tej techniki jest język C.
© K.Subieta. Obiektowe języki zapytań 14, Folia 10
czerwiec 2004
Wołanie poprzez wartość ze zwrotem (call-by-value-return)
Wołanie poprzez referencję, w którym wewnątrz ciała procedury tworzy
się lokalną kopię obiektu (zmiennej), którego referencja jest przekazana
jako parametr.
Wszelkie operacje na parametrze wewnątrz ciała procedury następują na
tej lokalnej kopii, a nie na oryginalnej zmiennej (różnica z wołaniem
przez referencję).
W momencie zakończenia procedury wartość tego lokalnego obiektu
podstawia się z powrotem na obiekt, którego referencja jest przekazana
jako parametr.
Technika ma duże znaczenie w systemach rozproszonych, gdzie
komunikowana referencja może dotyczyć obiektu znajdującego się poza
przestrzenią adresową pamięci operacyjnej danego komputera.
Technika nie jest w pełni semantycznie „czysta”, gdyż umożliwia
nałożenie się dwóch lub więcej aktualizacji w ramach tego samego
programu.
© K.Subieta. Obiektowe języki zapytań 14, Folia 11
czerwiec 2004
Wołanie poprzez nazwę (call-by-name)
Technika przekazywania parametrów (po raz pierwszy zastosowana w
języku Algol-60) polegająca na tym, że parametru nie oblicza się w
momencie wołania metody/procedury, ale przekazuje się go w postaci
kodu (tekstu) wyrażenia będącego parametrem aktualnym.
Tekst ten zastępuje wszystkie wystąpienia parametru formalnego w ciele
metody/procedury (parametr jest traktowany jak makro).
Specyfiką tej techniki jest to, że środowisko, w którym taki parametr jest
ewaluowany, jest środowiskiem wywołania tej metody/procedury, a nie jej
środowiskiem lokalnym (co jest konieczne z semantycznego punktu
widzenia);
Technika nie jest semantycznie „czysta” - może powodować efekt, w
którym obliczane wartości parametru w poszczególnych miejscach ciała
metody/procedury nie są identyczne ze względu na zmianę stanu.
Technika ta jest powszechnie stosowana w przypadku parametrów makr.
• Może mieć również znaczenie dla technik optymalizacyjnych (optymalizacji
zapytań) opartych na przepisywaniu (rewriting).
© K.Subieta. Obiektowe języki zapytań 14, Folia 12
czerwiec 2004
Wołanie poprzez potrzebę (call-by-need)
Technika przekazywania parametrów określana także jako leniwa
ewaluacja (lazy evaluation).
Oznacza opóźnienie wyliczania wartości parametru aktualnego do
momentu, kiedy będzie on rzeczywiście potrzebny wewnątrz ciała
metody/procedury.
Parametr jest ewaluowany tylko raz (różnica z wołaniem przez nazwę), w
środowisku wywołania metody/procedury.
Technika ma na celu optymalizację czasu wykonywania i może być
kombinowana z innymi metodami (call-by-value, call-by-reference, itd.).
Podobnie do wołania przez nazwę, technika ta nie jest semantycznie
„czysta”, gdyż może prowadzić do efektu, w którym wartość wyliczonego
parametru jest inna niż wartość, która byłaby wyliczona w momencie
wołania metody/procedury.
© K.Subieta. Obiektowe języki zapytań 14, Folia 13
czerwiec 2004
Procedury w SBQL
Przyjmiemy następującą składnię deklaracji procedury (nie
uwzględniającą kontroli typologicznej):
procedura ::= procedure nazwaProc {instrukcje}
procedura ::= procedure nazwaProc( ) {instrukcje}
procedura ::= procedure nazwaProc ( parFormalne) {instrukcje}
nazwaProc ::= nazwa
parFormalne ::= parFormalny | parFormalny; parFormalne
parFormalny ::= nazwa | in nazwa | out nazwa
instrukcja ::= return [zapytanie]
Wywołanie procedury:
instrukcja ::= nazwaProc | nazwaProc( ) | nazwaProc ( parAktualne )
zapytanie ::= nazwaProc | nazwaProc( ) | nazwaProc ( parAktualne )
parAktualne ::= parAktualny | parAktualny ; parAktualne
parAktualny ::= zapytanie
© K.Subieta. Obiektowe języki zapytań 14, Folia 14
czerwiec 2004
Semantyka procedur (1)
Nie rozróżniamy procedur właściwych i procedur funkcyjnych.
Procedura funkcyjna musi zawierać wewnątrz instrukcję return, z
parametrem będącym zapytaniem.
• Instrukcja ta kończy działanie procedury.
• Taka procedura może być wywołana jako zapytanie.
• Jeżeli procedura funkcyjna jest wywołana jako instrukcja (poza zapytaniem),
wówczas zwracany przez nią wynik jest ignorowany.
• Jeżeli napotkana instrukcja return nie ma parametru w postaci zapytania, to
jej wykonanie kończy działanie procedury, ale nic ona nie zwraca (wobec
czego nie jest procedurą funkcyjną).
Przyjęliśmy, że formalne parametry procedury mogą być pozbawione
kwalifikatora; wówczas oznacza to ścisłe wołanie przez wartość (strictcall-by-value).
Kwalifikator in oznacza zwykłe wołanie przez wartość, zaś kwalifikator
out oznacza wołanie przez referencję.
• Semantyka tych metod transmisji parametrów zostanie objaśniona dalej.
© K.Subieta. Obiektowe języki zapytań 14, Folia 15
czerwiec 2004
Semantyka procedur (2)
Istotne jest jak i gdzie procedura będzie zapamiętana.
Najczęstszym rozwiązaniem jest uwzględnienie deklaracji procedury w
środowisku rozwoju oprogramowania.
• Miejsce ulokowania procedury wynika wtedy z innych czynników, np.
miejscem jest moduł lub klasa, jeżeli dana procedura jest składową kodu
źródłowego tego modułu lub klasy.
W przypadku baz danych procedury są bytami pierwszej kategorii
programistycznej, wobec tego mogą być potrzebne specjalne
udogodnienia administracyjne dla ich tworzenia, wstawiania w
odpowiednie miejsce składu obiektów, kompilowania, usuwania,
zabezpieczania, optymalizacji, itd.
W systemie Loqis przyjęliśmy, że procedury są składowymi modułów
źródłowych lub klas, które po kompilacji stają się modułami lub klasami
bazy danych.
Procedury takie mogą być przenoszone pomiędzy modułami lub klasami
poprzez instrukcję insert.
© K.Subieta. Obiektowe języki zapytań 14, Folia 16
czerwiec 2004
Gzie procedurę można zapamiętać?
Procedurę można zapamiętać w dowolnym środowisku składu obiektów,
w szczególności:
• W bazie danych po stronie serwera na najwyższym poziomie hierarchii
obiektów.
• W środowisku lokalnym sesji użytkownika, po stronie klienta, czyli programu
aplikacyjnego i środowiska jego wykonania.
• Wewnątrz dowolnego obiektu, w szczególności, modułu bazy danych, o ile
takie pojęcie będzie wprowadzone.
• Wewnątrz klasy, zarówno umieszczonej po stronie serwera bazy danych, jak i
po stronie aplikacji klienta. Umieszczenie procedury wewnątrz klasy
powoduje, że staje się ona tym, co powszechnie jest określane w
obiektowości jako „metoda”.
• Wewnątrz specjalnej biblioteki procedur po stronie serwera, lub pewnej
struktury takich bibliotek.
Zależnie od miejsca umieszczenia procedur w składzie, bindery
zawierające referencje do procedur i ich nazwy muszą być umieszczone w
odpowiednich sekcjach stosu ENVS.
• W ten sposób nazwy procedur będą dostępne do wiązania.
© K.Subieta. Obiektowe języki zapytań 14, Folia 17
czerwiec 2004
Semantyka wywołania procedur (1)
Najpierw wiąże się jej nazwę występującą w zapytaniu/programie na stosie
ENVS. Wynikiem jest referencja do procedury.
Następuje uruchomienie procedury, czego skutkiem jest pojawienie się na stosie
ENVS sekcji z binderami (zwanej zapisem aktywacyjnym).
Zapis aktywacyjny zawiera trzy rodzaje bytów:
• bindery aktualnych parametrów procedury;
• bindery do lokalnych obiektów procedury;
• ślad powrotu, umożliwiający przekazanie sterowania do kodu wywołującego
procedurę po zakończeniu jej działania. Ślad ten w tym kroku jest wstawiany do
zapisu aktywacyjnego.
Jeżeli procedura była umieszczona wewnątrz klasy (tj. była metodą), to poniżej
zapisu aktywacyjnego umieszcza się sekcję z binderami do wszystkich
prywatnych własności tej klasy.
Następuje ewaluacja zapytań będących parametrami procedury; wynik tej
ewaluacji znajduje się na QRES.
Po ewaluacji parametrów tworzy się z nich bindery i wstawia do sekcji ENVS
zawierającej zapis aktywacyjny procedury. Parametry te usuwa się z QRES.
© K.Subieta. Obiektowe języki zapytań 14, Folia 18
czerwiec 2004
Semantyka wywołania procedur (2)
Jeżeli procedura miała zadeklarowane obiekty, to są one tworzone w
składzie, zaś ich bindery są umieszczone wewnątrz zapisu aktywacyjnego.
Sterowanie jest przekazywane do ciała procedury.
Przy wiązaniu nazw wewnątrz ciała procedury wszystkie sekcje procedur,
które wywołały bezpośrednio lub pośrednio daną procedurę (wraz z
towarzyszącymi im sekcjami obiektów, zapytań, klas, itd.) są niedostępne
do wiązania.
Jeżeli sterowanie osiągnie końcowy nawias ciała procedury, lub napotka
instrukcję return, to procedura kończy swoje działanie.
• Jeżeli instrukcja return miała parametr w postaci zapytania, to ewaluuje się je
w środowisku tej procedury, jak zwykle.
• Wynik, jak zwykle, znajdzie się na wierzchołku QRES jako wynik działania
procedury funkcyjnej.
Zakończenie działania procedury oznacza zdjęcie ze stosu wszystkich
sekcji, które były tam włożone w momencie jej startu, usunięcie
zadeklarowanych lub utworzonych lokalnych obiektów, oraz powrót
sterowania do programu wywołującego, zgodnie ze śladem powrotu.
© K.Subieta. Obiektowe języki zapytań 14, Folia 19
czerwiec 2004
Przykład procedury (1)
Procedura ZmieńDział zmienia dział dla pracowników komunikowanych
jako parametr P na dział komunikowany jako parametr D.
procedure ZmieńDział( P; out D ) {
delete Dział.Zatrudnia where Prac P;
for each P as p do {
p.PracujeW := ref D
insert D, create ref p as Zatrudnia }}
Wywołanie procedury: przenieś wszystkich analityków do działu
kierowanego przez Nowaka:
ZmieńDział(
Prac where Stan = ”analityk”;
Dział where (Szef.Prac.Nazwisko) = ”Nowak” )
Jeżeli system respektowałby automatyczną aktualizację bliźniaczych
pointerów (PracujeW i Zatrudnia), to procedura zostałaby uproszczona:
procedure ZmieńDział( P; out D ) {
for each P do PracujeW := ref D }}
© K.Subieta. Obiektowe języki zapytań 14, Folia 20
czerwiec 2004
Przykład procedury (2)
Procedura funkcyjna MałoZarabiający zwraca nazwisko, zarobek i nazwę
działu dla pracowników określonych stanowisk zarabiających mniej niż
średnia. Wynik jest strukturą z nazwami N, Z, D.
procedure MałoZarabiający ( in Stanowiska ) {
create avg( Prac.Zar ) as Średnia;
create ref (Prac where Stan Stanowiska
and Zar < Średnia) as Mało;
return Mało.Prac.(
Nazwisko as N, Zar as Z,
(PracujeW.Dział.Nazwa) as D) };
• Podaj nazwiska i zarobek dla mało zarabiających piekarzy i stolarzy z działu
produkcji.
(MałoZarabiający( bag(”piekarz”,”stolarz”))
where D = ”produkcja”). (N, Z)
• Podwyższ o 100 zarobek wszystkim mało zarabiającym programistom z
działu konserwacji.
for each MałoZarabiający( ”programista”) )
where D = ”Konserwacja” do Z := Z+100;
© K.Subieta. Obiektowe języki zapytań 14, Folia 21
czerwiec 2004
Procedury funkcyjne a perspektywy (1)
Procedura BogatyPrac zwraca informacje o pracownikach, który zarabiają
brutto co najmniej 3000. Informacja zawiera nazwisko pracownika jako
Nazwisko, nazwisko jego szefa jako Szef oraz zarobek netto jako Zarobek.
procedure BogatyPrac {
return (Prac where Zar 3000). ( Nazwisko as Nazwisko,
(PracujeW.Dział.Szef.Prac.Nazwisko) as Szef, ZarNetto() as Zarobek) };
Nazwiska i zarobki netto bogatych pracowników pracujących dla
Wilickiego:
(BogatyPrac where Szef = „Wilicki”) . (Nazwisko, Zarobek)
• Procedura BogatyPrac została użyta w taki sposób, że użytkownik może
rozumieć nazwę BogatyPrac jako nazwę obiektów posiadających trzy
atrybuty: Nazwisko, Szef i Zarobek.
• Są to obiekty „wirtualne”, istniejące w postaci definicji (i w wyobraźni
programisty), ale nieobecne w składzie danych.
Procedura BogatyPrac przypomina więc pojęcie z baz danych znane jako
perspektywa (view).
© K.Subieta. Obiektowe języki zapytań 14, Folia 22
czerwiec 2004
Procedury funkcyjne a perspektywy (2)
Jeżeli pominąć drugorzędne opcje, to klasyczne perspektywy np. w SQL
są procedurami funkcyjnymi zapamiętanymi w bazie danych.
• Ten fakt do dzisiaj nie dotarł do powszechnej świadomości społeczności baz
danych.
Pozytywne konsekwencje tego założenia:
• Moc obliczeniowa i moc pragmatyczna takich perspektyw jest
nieograniczona.
• Semantyka oparta na stosie środowiskowym jest przygotowana do rekurencji.
• Perspektywy mogą posiadać parametry w postaci dowolnych zapytań.
• Wirtualne obiekty są automatycznie podłączone do klas, o ile funkcja zwróci
referencje do obiektów tych klas.
• Automatycznie dostarczone są środki do aktualizacji perspektyw, gdyż
procedury mogą zwrócić referencje do obiektów, atrybutów, itd.
Ostatni punkt wymaga dłuższej dyskusji: ze względu na aktualizację
wyraźnie musimy rozróżnić procedury funkcyjne i perspektywy.
© K.Subieta. Obiektowe języki zapytań 14, Folia 23
czerwiec 2004
Aktualizacja wirtualnych obiektów
Dotychczasowy wysiłek badawczy związany z aktualizacją witalnych
obiektów dotyczył dodatkowych ograniczeń na definicje perspektyw i ich
aktualizacje, aby zapobiec anomaliom aktualizacyjnym.
Dla perspektyw obiektowych te ograniczenia są tak silne, że praktycznie
nie zezwalają na tworzenie czegokolwiek sensownego.
Przyjmiemy następującą filozofię.
• Jeżeli programista lub projektant definiuje funkcję, to powinien być w pełni
świadomy, że jest to funkcja, a nie perspektywa.
• Jeżeli mimo tej świadomości decyduje się na aktualizację poprzez referencje
zwracane przez tę funkcję, to wolno mu to zrobić, ale ponosi za to
odpowiedzialność.
• Nie dopuszczamy w tym względzie żadnych protez, w rodzaju ograniczeń
znanych z systemu Oracle
Jeżeli programista chce, aby funkcja była perspektywa o pełnych walorach
przezroczystości, wówczas musi stworzyć taką perspektywę explicite,
według koncepcji, która będzie przedstawiona w następnym semestrze.
Koncepcja ta rozwiązuje problem aktualizacji perspektyw.
© K.Subieta. Obiektowe języki zapytań 14, Folia 24
czerwiec 2004
Metody w SBQL
Metoda jest procedurą umieszczoną wewnątrz klasy i traktowaną jako inwariant
obiektów będących członkami tej klasy.
• Metoda w SBQL jest zawsze wywoływana w kontekście obiektu, na którym działa;
ten kontekst jest określony poprzez umieszczenie binderów do własności obiektu na
stosie ENVS i następnie wywołanie metody.
Metoda ZarobekNetto umieszczona wewnątrz klasy Pracownik zwraca zarobek
netto dla pracownika, obliczając go według pewnej formuły:
procedure ZarNetto {
if exists(self.Zar) then {
return (if self.Zar < 500 then self.Zar
else if self.Zar < 1000 then 0.8 * (self.Zar - 500) + 500
else 0.7 * (self.Zar - 1000) + 900);}
else return 0; };
• Wywołania metody:
Podaj pracowników z zarobkiem netto mniejszym od 1000:
Prac where ZarNetto < 1000
Podaj średnią zarobków netto, z wyłączeniem pracowników, dla których funkcja
ZarNetto zwróci 0.
avg((Prac where ZarNetto > 0).ZarNetto)
© K.Subieta. Obiektowe języki zapytań 14, Folia 25
czerwiec 2004
Wyróżniona nazwa self (this)
W przykładzie wykorzystaliśmy nazwę self zwracającą referencję do
aktualnie przetwarzanego obiektu.
Tego rodzaju predefinowana nazwa (self, this, itp.) występuje w
większości obiektowych języków programowania.
W naszym przypadku nie jest ona niezbędna.
Z technicznego punktu widzenia, wszystkie bindery do wewnętrznych
własności przetwarzanego obiektu znajdują się w odpowiedniej sekcji
ENVS.
Istnieją powody, dla których taką nazwę warto wprowadzić:
• Modelowanie pojęciowe: nazwa self pozwala programiście widzieć wyraźnie
w kodzie metody wszystkie odwołania do przetwarzanego obiektu.
• W niektórych sytuacjach (np. porównanie referencji) referencja do
przetwarzanego obiektu ułatwia napisanie metody.
Z drugiej strony, jak zwykle w przypadku predefiniowanych nazw, w
niektórych sytuacjach predefinowana nazwa self może prowadzić do
niejednoznaczności i wymagać większej uwagi od programisty,
szczególnie w przypadku zmian już napisanego kodu.
© K.Subieta. Obiektowe języki zapytań 14, Folia 26
czerwiec 2004
Jak wprowadzić nazwę self:
• Taka nazwa mogłaby się przydać również w innych kontekstach.
Nazwę self wprowadzimy poprzez poprawienie funkcji nested.
Jeżeli argumentem tej
funkcji jest pojedyncza
referencja r do obiektu, który
jest podłączony do klasy, to
wynik tej funkcji, oprócz
binderów do pod-obiektów
tego obiektu, zawierać
będzie binder self(r).
Sytuacja na ENVS w
momencie przetwarzania
metody ZarNetto dla obiektu
posiadającego identyfikator
i4 .
Klasa Osoba
Klasa Prac
i4 Prac
i5 Nazwisko ”Nowak”
i6 RokUr
i7 NrP
1944
8897865
i8 Stan "referent"
i9 Zar
2500
i10 PracujeW
Skład
© K.Subieta. Obiektowe języki zapytań 14, Folia 27
Lokalna sekcja wywołania metody
ZarNetto
Bindery do prywatnych własności klasy
Prac
Sekcja przetwarzanego obiektu:
self(i4), Nazwisko(i5), RokUr(i6), NrP(i7),
Stan(i8), Zar(i9), PracujeW(i10)
Bindery do publicznych własności klasy
Prac: ZmieńZar(..), ZarNetto(..),...
Bindery do publicznych własności klasy
Osoba: Wiek(..),...
.......
Sekcja sesji użytkownika
Sekcja bazy danych:
Osoba(..), Osoba(..), ..., Prac(..), Prac(..),
..., Dział(..), Dział(..)
Sekcja globalnych funkcji bibliotecznych
Sekcja zmiennych i funkcji środowiska
komputerowego
Stos ENVS
czerwiec 2004
Rozszerzenie SBQL w modelu M3
Model M3 wprowadza listy eksportowe dzielące własności obiektów i klas na
publiczne i prywatne.
Własności prywatne zarówno klasy K, jak i obiektów klasy K, są dostępne
wyłącznie z wnętrza ciała metod (publicznych i prywatnych) klasy tej samej K.
• Można to prosto zrealizować poprzez odpowiednie ustawienie sekcji stosu oraz
poprawkę do funkcji nested.
• Niech iK będzie identyfikatorem obiektu klasy K posiadającej listę eksportową
exportK.
• Lista ta zawiera nazwy własności klasy i obiektów tej klasy dostępnych publicznie.
• Funkcje nested_private oraz nested_public zmieniają definicję funkcji nested
uwzględniając listę eksportową:
nested_private(iK ) = {n(x) : n(x) nested(iK ) and n exportK}
nested_public(iK ) = {n(x) : n(x) nested(iK ) and n exportK}
Dla argumentów nie będących identyfikatorami obiektów funkcje te są identyczne
z funkcją nested.
• Funkcje te podobnie jak poprzednio rozszerzamy na dowolne struktury.
© K.Subieta. Obiektowe języki zapytań 14, Folia 28
czerwiec 2004
Operator niealgebraiczny w modelu M3
Rozpatrzmy zapytanie q1 q2, gdzie jest operatorem nie-algebraicznym.
• Niech eval(q1) zwróci bag{ r1, r2,...}, gdzie r1, r2,... są referencjami do
obiektów będących członkami klasy K1, która jest pod-klasą K2, która jest
pod-klasą K3.
• Wiązana jest nazwa m występująca w q2, m nie jest nazwą metody.
• W takim przypadku sytuacja przypomina model M1, ale:
• Wykorzystana jest w tej sytuacji funkcja nested_public, zaś kolejne stany
stosu ENVS przy przetwarzaniu ri są następujące:
nested_public(ri)
Sekcje wkładane przy
przetwarzaniu ri przez
operator θ
Koniec przetwarzania
ri przez q2
nested_public(iK1)
nested_public(iK2)
nested_public(iK3)
Poprzedni stan ENVS
© K.Subieta. Obiektowe języki zapytań 14, Folia 29
Poprzedni stan ENVS
Poprzedni stan ENVS
czerwiec 2004
Przetwarzanie metod w M3
Sytuacja jest nieco bardziej złożona, gdy wiązana jest nazwa m
występująca w q2 i m jest nazwą metody.
Na stos ENVS muszą być również włożone prywatne własności klasy, do
której należy metoda m oraz prywatne własności obiektu przetwarzanego
przez tę metodę (którego referencja jest zwrócona przez q1).
Wywołanie
metody m
Sekcje wkładane
przy wywołaniu
metody m
Lokalne
środowisko metody
m
nested_private(ri)
nested_private(iK2)
Operator θ
Poprzedni
stan ENVS
Koniec
działania
metody m
nested_public(ri)
nested_public(ri)
nested_public(ri)
nested_public(iK1)
nested_public(iK1)
nested_public(iK1)
nested_public(iK2)
nested_public(iK2)
nested_public(iK2)
nested_public(iK3)
nested_public(iK3)
nested_public(iK3)
Poprzedni stan
ENVS
Poprzedni stan
ENVS
Poprzedni stan
ENVS
© K.Subieta. Obiektowe języki zapytań 14, Folia 30
Koniec
przetwarzania
ri przez q2
Poprzedni
stan ENVS
czerwiec 2004
Schemat bazy danych w modelu M3
Plus oznacza własność publiczną, minus oznacza własność prywatną.
Osoba[0..*]
+ Nazwisko
- RokUr
+ Wiek
Prac[0..*] + PracujeW
- Zar
+ ZmieńZar
+ ZarNetto
© K.Subieta. Obiektowe języki zapytań 14, Folia 31
+ Zatrudnia[0..*] Dział[0..*]
+ Nazwa
+ Budżet
czerwiec 2004
Poprawne i niepoprawne konstrukcje w M3
Prac where Nazwisko = „Nowak”
Osoba where RokUr < 1975
(Prac where Nazwisko = „Nowak”).Zar
(Prac where Nazwisko = „Nowak”).Wiek
procedure Wiek { return BieżącyRok – RokUr }
procedure ZmieńZar( nowy ) { self.Zar := nowy }
Poprawna
Błędna
Błędna
Poprawna
Poprawna
Poprawna
procedure ZarNetto( )
{ return if RokUr > 1955 then 0.9 * Zar else 0.8 * Zar }
Błędna
procedure ZarNetto( )
return if Nazwa = “Marketing” then 0.9 * self.Zar
...
Prac where Dział (Budżet > 100 * ZarNetto)
Błędna
© K.Subieta. Obiektowe języki zapytań 14, Folia 32
else 0.8 * self.Zar }
czerwiec 2004