Obiektowe języki zapytań 1..5

advertisement
Języki i środowiska programowania
systemów rozproszonych
Wykład 11
Procedury,
procedury funkcyjne
Wykładowca: Tomasz Kowalski
Wykłady przygotowane na
podstawie materiałów
prof. Kazimierza Subiety
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 1
2011
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ń.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 2
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 3
2011
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)
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 4
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 5
2011
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).
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 6
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 7
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 8
2011
Ś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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 9
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 10
2011
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).
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 11
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 12
2011
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
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 13
2011
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ę.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 14
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 15
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 16
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 17
2011
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.
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 18
2011
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 }}
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 19
2011
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;
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 20
2011
Procedury funkcyjne a perspektywy
 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).
Języki i środowiska programowania systemów rozproszonych, Wykład 11, Slajd 21
2011
Download