320 likes | 434 Views
Podejście stosowe do obiektowych języków programowania baz danych. http://www.sbql.pl. Wykładowca : Kazimierz Subieta Polsko-Japońska Wyższa Szkoła Technik Komputerowych, Warszawa subieta@pjwstk.edu.pl http://www.ipipan.waw.pl/~subieta. Wykład 11 Procedury, procedury funkcyjne,
E N D
Podejście stosowe do obiektowych języków programowania baz danych http://www.sbql.pl Wykładowca: Kazimierz Subieta Polsko-Japońska Wyższa Szkoła Technik Komputerowych, Warszawa subieta@pjwstk.edu.pl http://www.ipipan.waw.pl/~subieta Wykład 11 Procedury, procedury funkcyjne, metody
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ń.
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ą.
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.
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)
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.
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).
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.
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.
Ś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.
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.
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).
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.
Procedury w SBQL • Przyjmiemy następującą składnię deklaracji procedury (nie uwzględniającą kontroli typologicznej): • Wywołanie procedury: 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] instrukcja ::= nazwaProc | nazwaProc( ) | nazwaProc ( parAktualne ) zapytanie ::= nazwaProc | nazwaProc( ) | nazwaProc ( parAktualne ) parAktualne ::= parAktualny | parAktualny ; parAktualne parAktualny ::= zapytanie
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ść (strict-call-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.
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.
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.
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.
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.
Przykład procedury (1) • Procedura ZmieńDział zmienia dział dla pracowników komunikowanych jako parametr P na dział komunikowany jako parametr D. • Wywołanie procedury: przenieś wszystkich analityków do działu kierowanego przez Nowaka: • 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 ) { delete Dział.Zatrudnia where Prac P; for each P as p do { p.PracujeW := ref D insert D, createref p as Zatrudnia }} ZmieńDział( Prac where Stan = ”analityk”; Dział where (Szef.Prac.Nazwisko) = ”Nowak” ) procedure ZmieńDział( P; out D ) { for each P doPracujeW := ref D }}
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. • Podaj nazwiska i zarobek dla mało zarabiających piekarzy i stolarzy z działu produkcji. • Podwyższ o 100 zarobek wszystkim mało zarabiającym programistom z działu konserwacji. 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) }; (MałoZarabiający( bag(”piekarz”,”stolarz”)) where D = ”produkcja”). (N, Z) for each MałoZarabiający( ”programista”) ) where D = ”Konserwacja” do Z := Z+100;
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. procedureBogatyPrac { return (PracwhereZar 3000). ( NazwiskoasNazwisko, (PracujeW.Dział.Szef.Prac.Nazwisko) asSzef, ZarNetto() asZarobek) }; • Nazwiska i zarobki netto bogatych pracowników pracujących dla Wilickiego: (BogatyPracwhereSzef = „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).
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.
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 później. • Koncepcja ta rozwiązuje problem aktualizacji perspektyw.
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: procedureZarNetto { if exists(self.Zar) then { return (if self.Zar <500then self.Zar else if self.Zar < 1000 then 0.8 * (self.Zar - 500) + 500 else 0.7 * (self.Zar - 1000) + 900);} elsereturn 0; }; • Wywołania metody: Podaj pracowników z zarobkiem netto mniejszym od 1000: PracwhereZarNetto < 1000 Podaj średnią zarobków netto, z wyłączeniem pracowników, dla których funkcja ZarNetto zwróci 0. avg((PracwhereZarNetto > 0).ZarNetto)
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.
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 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 Klasa Prac i4 Prac i5 Nazwisko ”Nowak” i6 RokUr 1944 i7 NrP 8897865 i8 Stan "referent" i9 Zar 2500 i10 PracujeW Skład Stos ENVS
Rozszerzenie SBQL w modelu AS3 • Model AS3 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 nexportK} nested_public(iK) = {n(x) : n(x) nested(iK) and nexportK} • 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.
Operator niealgebraiczny w modelu AS3 nested_public(ri) nested_public(iK1) nested_public(iK2) nested_public(iK3) Poprzedni stan ENVS • 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, mnie jest nazwą metody. • W takim przypadku sytuacja przypomina model AS1, ale: • Wykorzystana jest w tej sytuacji funkcja nested_public, zaś kolejne stany stosu ENVS przy przetwarzaniu risą następujące: Koniec przetwarzania ri przez q2 Sekcje wkładane przy przetwarzaniu ri przez operator θ Poprzedni stan ENVS Poprzedni stan ENVS
Przetwarzanie metod w AS3 Wywołanie metody m Lokalne środowisko metody m nested_private(ri) nested_private(iK2) nested_public(ri) nested_public(iK1) nested_public(iK2) nested_public(iK3) Poprzedni stan ENVS Sekcje wkładane przy wywołaniu metody m Koniec działania metody m nested_public(ri) nested_public(iK1) nested_public(iK2) nested_public(iK3) Poprzedni stan ENVS nested_public(ri) nested_public(iK1) nested_public(iK2) nested_public(iK3) Poprzedni stan ENVS Operator θ Koniec przetwarzania ri przez q2 Poprzedni stan ENVS Poprzedni stan ENVS • Sytuacja jest nieco bardziej złożona, gdy wiązana jest nazwa m występująca w q2i mjest 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).
Schemat bazy danych w modelu AS3 Osoba[0..*] + Nazwisko - RokUr + Wiek Prac[0..*] - Zar + ZmieńZar + ZarNetto Dział[0..*] + Nazwa + Budżet + PracujeW + Zatrudnia[0..*] • Plus oznacza własność publiczną, minus oznacza własność prywatną.
Poprawne i niepoprawne konstrukcje w AS3 PracwhereNazwisko = „Nowak” Poprawna Osoba where RokUr < 1975 Błędna (PracwhereNazwisko = „Nowak”).Zar Błędna (PracwhereNazwisko = „Nowak”).Wiek Poprawna procedureWiek { returnBieżącyRok – RokUr } Poprawna procedureZmieńZar( nowy ) { self.Zar := nowy } Poprawna procedureZarNetto( ) { return ifRokUr > 1955 then 0.9 * Zarelse 0.8 * Zar } Błędna procedureZarNetto( ) return ifNazwa = “Marketing” then 0.9 * self.Zarelse 0.8 * self.Zar } ... PracwhereDział (Budżet > 100 * ZarNetto) Błędna