220 likes | 327 Views
O wyższości Javy nad Loglanem. czyli o zasadach widoczności atrybutów i metod gdy w języku mamy i dziedziczenie i zawieranie modułów. Co oznacza identyfikator id ?. Znaczenie identyfikatora jest zasadniczą sprawą dla rozumienia programu.
E N D
O wyższości Javy nad Loglanem czylio zasadach widoczności atrybutów i metod gdy w języku mamy i dziedziczenie i zawieranie modułów
Co oznacza identyfikator id? Znaczenie identyfikatora jest zasadniczą sprawą dla rozumienia programu. W programie identyfikator idnt może występować wiele razy i w różnych znaczeniach. Zacznijmy od zróżnicowania wystąpień idenyfikatora na wystąpienia definiujące czyli deklaracje identyfikatora, oraz na wystąpienia aplikacyjne. Deklaracja określa rodzaj i typ identyfikatora np. zmienna typu integer, funkcja zwracająca wartośc boolowską o trzech argumentach typu real, etc. Inne wystąpienia identyfikatora muszą być związane z odpowiednią deklaracją by wiadomo było co znaczą. 2
Dynamiczne czy statyczne wiązanie Sprawa jest pozornie prosta, ale mechanizmy zawierania jednego modułu w drugim, dziedziczenia modułów i przekazywania parametrów mogą ją potężnie skomplikować. Jeżeli pewien identyfikator idnt występuje w module M razem z deklaracją tego identyfikatora, to oczywiście znaczenie identyfikatora idnt jest opisane w deklaracji zawartej w tym module. Gorzej jest gdy moduł M nie zawiera deklaracji identyfikatora idnt. Czytelnik programu (człowiek) i kompilator powinni zastosować taki sam algorytm odszukiwania deklaracji identyfikatora. W jednym z najwcześniejszych języków programowania, w LISPie poszukiwania odbywają się wzdłuż łańcucha dynamicznych ojców. Nie wchodząc na razie w szczegóły stwierdźmy, że znaczenie identyfikatora ustalane jest podczas wykonywania programu. Oznacza to niemożność przeprowadzenia analizy programu bez jego wykonania, gorzej różne wykonania tego samego programu mogą mieć różne znaczenia. 3
pouczająca historia Język LISP wyszedł dziś z użycia, przywiązani do niego programiści posługują się dziś językiem SCHEME. Składnia tych dwu języków jest identyczna, różnica polega tylko i aż na statycznym wiązaniu wystąpień aplikacyjnych z deklaracjami funkcji. (Lisp i Scheme są językami programowania funkcyjnego.) W języku Scheme znaczeniem nazwy funkcji nielokalnej jest ta którą znajduje się w module obejmującym moduł zawierający wystąpienie aplikacyjne identyfikatora funkcji. W Lispie nazwa funkcji nielokalnej szukana jest w rekordzie aktywacji funkcji, która wywołała funkcję aktualnie wykonywaną. Czyli znaczenie zależy od historii obliczenia. 4
Przykład Co zostanie wydrukowane? Program SDBinding;unit A: class; var x: integer; end A; unit B: A class; unit G: class; begin writeln(x) end G; unit C: A class; unit H: G class; begin writeln(x) end H; var gg: G, hh: H begin x := 2; gg := new G; hh := new H; end C; var cc: C begin x := 1; cc := new C End B; Var bb: B Begin bb := new B End 6
Drzewo zawierania modułów main B A C G x H 7
Las dziedziczenia modułów main B A C G H 8
Graf zawierania i dziedziczenia modułów main B A C G x H 9
Historia wykonania 1/6 Unit A: class; var x: integerend A Na początku mamy jednostkę Dynamiczną rekord aktywacjiprogramu Main Unit B: A class; ...end B Bb: b Bb := new b main 10
Historia wykonania 2/6 Unit A: class; var x: integerend A SLx : integer 1unit G: class; ...unit C: A class ...cc: C x := 1 Cc := new C Unit B: A class; ...end B Bb: B Bb := new b B Teraz procesor wykonuje konstruktor obiektu bb klasy B main 11
Historia wykonania 3/6 Unit A: class; var x: integerend A SLx : integer = 1 Aunit G: class; ...unit C: A class ...cc: C x := 1 Cc := new C SLx: integer = 2 Aunit H: G class ......Hh: Hgg: Gx := 2;gg := new G;hh := new H; Unit B: A class; ...end B Bb: B Bb := new b B C main Teraz procesor wykonuje konstruktor obiektu cc klasy C 12
Historia wykonania 4/6 Unit A: class; var x: integerend A SLx : integer = 1 Aunit G: class; ...unit C: A class ...cc: C x := 1 Cc := new C SLx: integer = 2 Aunit H: G class ......Hh: Hgg: Gx := 2;gg := new G;hh := new H; Unit B: A class; ...end B Bb: B Bb := new b B C SLwriteln(x) main G Skąd odczytać x? Jeśli wg SL, to wydrukuje się 1 13
Historia wykonania 4a/6 Unit A: class; var x: integerend A SLx : integer = 1 Aunit G: class; ...unit C: A class ...cc: C x := 1 Cc := new C SLx: integer = 2 Aunit H: G class ......Hh: Hgg: Gx := 2;gg := new G;hh := new H; Unit B: A class; ...end B Bb: B Bb := new b B C SL DLwriteln(x) main G Skąd odczytać x? Wg DL wydrukuje się 2 14
Historia wykonania 5/6 Unit A: class; var x: integerend A SLx : integer = 1 Aunit G: class; ...unit C: A class ...cc: C x := 1 Cc := new C SLx: integer = 2 Aunit H: G class ......Hh: Hgg: Gx := 2;gg := new G;hh := new H; Unit B: A class; ...end B Bb: B Bb := new b B SLwriteln(x) SLwriteln(x); Gwriteln(x) main G A co teraz? Ta instr. odziedziczona z G H 15
Historia wykonania 6/6 Unit A: class; var x: integerend A SLx : integer = 1 Aunit G: class; ...unit C: A class ...cc: C x := 1 Cc := new C SLx: integer = 2 Aunit H: G class ......Hh: Hgg: Gx := 2;gg := new G;hh := new H; Unit B: A class; ...end B Bb: B Bb := new b B SLwriteln(x) SLwriteln(x); Gwriteln(x) main G A co teraz? Powinno być 2 H 16
program semiStaticBinding;unit A: class; var x: integer begin writeln(" w warstwie A, x= ",x) end A;unit B: A class;unit G: class; begin writeln(" w warstwie G tego obiektu x= ",x:3) end G;unit C: A class;unit H: G class;begin writeln("w warstwie H tego obiektu x= ",x:3); end H; var gg: G, hh: H; begin x := 2; writeln(" w obiekcie klasy C wykonano x := 2"); writeln(" tworze obiekt klasy G, G zawarte w B "); gg := new G; writeln(" tworze obiekt klasy H, H zawarte w C, dziedziczy z G"); hh := new H; end C; var cc: C; begin x := 1; writeln(" w obiekcie klasy B wykonano x := 1"); writeln(" tworze obiekt klasy C, C dziedziczy z A, jest zawarte w B"); cc := new C; end B; var bb: b;begin writeln("This is semistatic semantic of inheritance: 1, 2, 2"); writeln(" tworze obiekt klasy B, B dziedziczy z A"); bb := new B; writeln(" end of example semiStatic semantic");end
Wykonanie tego programu daje This is semistatic semantic of inheritance: 1, 2, 2 tworze obiekt klasy B, B dziedziczy z A w warstwie A, x= 0 w obiekcie klasy B wykonano x := 1 tworze obiekt klasy C, C dziedziczy z A, jest zawarte w B w warstwie A, x= 0 w obiekcie klasy C wykonano x := 2 tworze obiekt klasy G, G zawarte w B w warstwie G tego obiektu x= 1 tworze obiekt klasy H, H zawarte w C, dziedziczy z G w warstwie G tego obiektu x= 2 w warstwie H tego obiektu x= 2 end of example semistatic semantic
Obejrzyjmy teraz odpowiedni program w Javie file:///c|/andrzej/progobi/staticbinding.java.sdw
Wyniki programu w Javie Wyniki:
Wnioski • Java ma lepszą semantykę dziedziczenia zagnieżdżonych klas – static binding, • Loglan prezentuje semantykę semi-static binding, • w zastosowaniach różnicy nie widać (przykład jest chyba bardziej skomplikowany niż potrzeby zastosowań) • w 1993 prof. A. Kreczmar zbudował maszynę wirtualną Loglanu z semantyką static binding, • są w Javie możliwości o jakich się programistom nie śniło!