Języki wysokiego poziomu: – funkcje i programowanie bezklasowe λ Sebastian Poręba
1. Wprowadzenie
Poziom abstrakcji języka PHP4 – łatwa nauka Klasyfikacja języków programowania 1. Wprowadzenie Ze względu na: Przykłady: Łatwość nauki Popularność Poziom abstrakcji języka PHP4 – łatwa nauka Assembler, Cobol – niski poziom abstrakcji C++, Java – wysoki (?) poziom abstrakcji, akceptowalny poziom trudności Poziom abstrakcji – zakres narzędzi umożliwiających wydajniejsze programowanie Proof: każdy z nas zaczynał od Pascala, C – po dotarciu do języka w którym możemy zrealizować potencjalnie każde zadanie w akceptowalnym czasie, przestajemy uczyć się nowych języków. Tzw Blub Paradox, każdy widzi, czego brakuje w innych językach względem języka który sam wybrał, ale nie widzi zastosowań dla dodatkowych możliwości języków wyższego poziomu. Tendencja ta wzmacnia się z wiekiem – starsi programiści rzadziej decydują się na naukę nowego języka jeśli nie zmuszają ich do tego okoliczności. http://www.paulgraham.com/avg.html Poziom abstrakcji niski wysoki
? 1. Wprowadzenie Klasyfikacja języków programowania popularność C++ Java Ruby Edsger Dijkstra powiedział o COBOL-u, "używanie COBOL-a kaleczy mózg, nauczanie COBOL-a powinno być uznane za przestępstwo„ 90% światowych transakcji finansowych jest przetwarzanych przez programy napisane w COBOL-u – dlaczego? Kiedy Cobol był u szczytu popularności, programiści Cobola woleli tworzyć w nim kaleczący mózg kod, zamiast przejść w kierunku innych języków. Im bardziej abstrakcyjny język, tym więcej dodatkowej pracy jest wykonywanej pod maską, przez kompilator i sam program (np. typy zmiennych zależne od wejścia). Python C Pascal Assembler ? Cobol Poziom abstrakcji
Języki skryptowe w silnikach gier Po co programiście gier języki wyższego poziomu? 1. Wprowadzenie OpenGL gamedev == C++ DirectX performance (Java, C, Assembler) QuakeC, UnrealScript – dość słabe implementacje, QuakeC < UnrealScript akurat US jest niezły, ale generalnie język pisany specjalnie pod grę przechodzi zawsze długą drogę zanim zacznie być ok Języki skryptowe w silnikach gier Lua, Python QuakeC, UnrealScript
2. – funkcje λ
2. Funkcje lambda Co się dzieje kiedy definiujemy funkcję w C++ class Elephant { void step() { // do some stuff } }; vtable (w klasie) i vptr (w obiekcie) C++0x (see plus plus oh ex) – będzie mieć funkcje lambda *step Elephant // do some stuff function step *step Elephant *step Elephant
Funkcje lambda 2. Funkcje lambda Funkcje lambda pozwalają na samodzielne zarządzanie wskaźnikiem do funkcji Funkcje lamdba rzadko występują w językach z mocną typizacją – ciężko zarządzać typem zwracanej wartości (można to zrobić np. w c#) step = function () { // do some stuff } step();
zwracać jako wynik innej funkcji podawać jako argument do funkcji Do czego to się przydaje? 2. Funkcje lambda Funkcję można: zmieniać zwracać jako wynik innej funkcji podawać jako argument do funkcji
C++: 2. Funkcje lambda Zmiana wskaźnika na funkcję Niewygodne zarządzanie kodem #define RK4 #ifdef, #ifndef Zarządzanie kodem tylko przy kompilacji Rungyego Kutty 4 stopnia vs Eulera – różniczkowanie numeryczne ify przy każdej iteracji pętli programu If/switch wybierający funkcję Przechowywanie niepotrzebnych funkcji w pamięci
Podmiana funkcji w locie Brak ifów Zmiana wskaźnika na funkcję 2. Funkcje lambda Funkcja lambda Podmiana funkcji w locie Brak ifów Zwolnienie pamięci po funkcji do której nie ma żadnego wskaźnika Podmiana funkcji w locie – możliwość wyboru algorytmu w zależności od performance Zwolnienie pamięci – linuksowy system plików
Możliwość zwracania funkcji jako wynik funkcji Generatory funkcji 2. Funkcje lambda Możliwość zwracania funkcji jako wynik funkcji Czasami najskuteczniejszą metodą kompresji jest brak kompresji. Nagłówki kompresji (np. słownik) zajmują więcej niż plik. Przykład: funkcja zwracająca algorytm kompresujący na podstawie parametrów pliku do skompresowania
2. Funkcje lambda Memoizacja fib(100) -> 708 * 1018 wywołań fib( ) int fib(int n) { return n<=2 ? 1 : fib(n-1) + fib(n-2); } fib(100) -> 708 * 1018 wywołań fib( ) long long memo[101]; // zainicjalizowane na 0 int memofib(int n) { if(memo[n]) return memo[n]; memo[n] = memofib(n-1) + memofib(n-2); return memo[n]; }
2. Funkcje lambda Funkcja jako argument – modyfikatory funkcji function memoize (func) { var memo = {}; return function (key) { if(!memo[key]) {memo[key] = func(key); } return memo[key]; }; (równie dobrze możemy przypisać do fib wersję po memoizacji) var fib = function (n) {return n<=2 ? 1 : fib(n-1) + fib(n-2);} var memofib = memoize(fib); memofib(100);
Funkcje lambda 2. Funkcje lambda Wprowadzenie tak nieznacznej modyfikacji jak funkcje lambda udostępnia cały wachlarz nowych technik programowania
3. Programowanie bezklasowe
3. Programowanie bezklasowe Powtórka z filozofii 3. Programowanie bezklasowe Platon Według Platona każdy przedmiot odwołuje się do pewnej idei, do pewnego uogólnienia. Jest to założenie podobne do programowania z wykorzystaniem klas, gdzie zakładamy, że konkretne obiekty można uogólnić przez abstrakcyjną klasę.
3. Programowanie bezklasowe Dlaczego w takim razie programujemy z wykorzystaniem klas? 3. Programowanie bezklasowe Programowanie klasowe zakłada, że możemy poprawnie określić klasy występujące w projekcie, że możemy poprawnie zaprojektować system. Wystąpienie obiektu nieznacznie niepasującego do określającej go klasy wymaga rozszerzania klasy lub definiowania nowej (problem one object – one instance). MIT – Structure and Interpretation of Computer Programs, Wykład 2b, ~36:00 prof. Harold Abelson (rok 1986)
3. Programowanie bezklasowe Dziedziczenie klasowe 3. Programowanie bezklasowe Obj1 foo() bar() baz
3. Programowanie bezklasowe Dziedziczenie klasowe 3. Programowanie bezklasowe Obj1 Klasa, która wykonuje pewne zadania w inny sposób foo() bar() baz Obj2 foo()
3. Programowanie bezklasowe Dziedziczenie klasowe 3. Programowanie bezklasowe ObjBase foo() Klasa, która nie zawiera pewnych pól Obj1 Obj2 bar() baz
3. Programowanie bezklasowe Dziedziczenie klasowe 3. Programowanie bezklasowe ObjBase foo() Obj12 abc adf Obj1 Obj2 bar() baz Obj72 mattDamon jimmyKimmel time Obj21 foo Różne pola w różnych klasach
3. Programowanie bezklasowe Dziedziczenie klasowe 3. Programowanie bezklasowe
3. Programowanie bezklasowe Powtórka z filozofii 3. Programowanie bezklasowe Arystoteles Arystoteles – czy pies z trzema nogami wciąż jest psem? Co z obiektami, które różnią się od swojej idei w drobny, ale znaczący sposób? Arystoteles twierdził, że prawdziwa istota rzeczy znajduje się tylko w nich samych. Wzorcem każdego przedmiotu jest ten przedmiot. Platon był filozofem z nastawieniem bardziej społecznym, Arystoteles stworzył pierwsze zasady logiki, wnioskowania i dowodzenia twierdzeń (m.in. Brzytwę Ockhama).
3. Programowanie bezklasowe Programowanie klasowe vs bezklasowe 3. Programowanie bezklasowe Klasowe Bezklasowe Definiujemy klasę pewnych obiektów i zależności między nimi Tworzymy instancje klasy Obiekty zawierają pola swoje i swoich klas nadrzędnych oraz tablicę wskaźników na metody Tworzymy obiekty Obiekty zawierają pola, wskaźniki na swoje metody oraz wskaźnik na prototyp Programowanie bezklasowe zakłada, że do każdego obiektu możemy w dowolnej chwili dodać dowolną metodę lub pole
3. Programowanie bezklasowe Dziedziczenie klasowe 3. Programowanie bezklasowe class A { int pampararam; method abc (param : int) { … } } class B inheriting A { method abc (param: int) { … } b = new B( ); Enkapsulacja Obiekt B Obiekt A
3. Programowanie bezklasowe Dziedziczenie prototypowe 3. Programowanie bezklasowe Wskaźnik na prototyp a = { int pampararam; method abc (param : int) { … } } b = { method abc (param: int) { … } b.prototype = a; Obiekt B Obiekt A *prototype
3. Programowanie bezklasowe Jaka jest praktyczna różnica? 3. Programowanie bezklasowe Klasowe Bezklasowe Każdy obiekt klasy potomnej zawiera w sobie obiekt klasy nadrzędnej Obiekty klas dziedziczących po innych klasach mogą zawierać pola, które nie są używane Obiekty przechowują jedynie wskaźnik na obiekt nadrzędny Jeżeli odczytujemy wartość pola pampararam (z przykładu, w klasie nadrzędnej), jest on szukany w prototype chain Jeżeli chcemy zapisać wartość pampararam, zostanie utworzone nowe pole w obiekcie B, prototype chain nie będzie potrzebny
3. Programowanie bezklasowe Dziedziczenie klasowe 3. Programowanie bezklasowe ObjBase foo() Obj12 abc adf Obj1 Obj2 bar() baz Obj72 mattDamon jimmyKimmel time Obj21 foo() Różne pola w różnych klasach
3. Programowanie bezklasowe Dziedziczenie prototypowe 3. Programowanie bezklasowe Obj2 = {}; Obj2.prototype = { foo: ObjBase.foo, adf: Obj12.adf, time: Obj72.time, foo2: Obj21.foo, bar: Obj1.bar }; Możemy stworzyć nowy, złożony obiekt nie modyfikując w ogóle innych obiektów.
3. Programowanie bezklasowe Klonowanie obiektów 3. Programowanie bezklasowe A co jeśli chcemy mieć wiele obiektów z tymi samymi metodami? prototype foo adf time cookies bar Obj2 = {}; Obj2.prototype = { foo: ObjBase.foo, adf: Obj12.adf, time: Obj72.time, cookies: Obj21.cookies, bar: Obj1.bar }; Obj3 = Obj2.clone(); Obj2 Obj3
3. Programowanie bezklasowe Klonowanie obiektu 3. Programowanie bezklasowe Prototyp obiektu nie ma nazwy, nie zaśmieca namespace – jedynym odwołaniem do niego jest wskaźnik w obiektach Obj2 i Obj3.
3. Programowanie bezklasowe Zmiana delegacji obiektu 3. Programowanie bezklasowe Prototyp obiektu może zawierać zmienne dzielone dla wielu obiektów. W C++ zmienne klasy nadrzędnej mają rezerwowaną osobną pamięć dla każdej instancji.
3. Programowanie bezklasowe Zmiana delegacji obiektu 3. Programowanie bezklasowe Prototyp obiektu jest określony za pomocą wskaźnika – nic nie stoi więc na przeszkodzie, żeby zmienić go w czasie wykonywania programu.
3. Programowanie bezklasowe Zmiana delegacji obiektu 3. Programowanie bezklasowe NPC DeadNPC talkTo(); attack(); giveSandwich(); talkTo() { return „I see dead people”; }; attack(); giveSandwich(); Tutaj wstawka o Prototypes with Multiple Dispatch Pirate // something If(Pirate.isA(DeadNPC)) { // do stuff }
3. Programowanie bezklasowe Testy wydajnościowe 3. Programowanie bezklasowe Benchmark kodeka MPEG 1/2 – C vs Lisaac C version Lisaac version Rate (%) Code line count 9852 6176 37,31 % less binary size 99 kB 109 kB 10,10% more Memory used at runtime 1352 kB 1332 kB Run time (s) 3,60 3,67 1,94 % more Ciekawostka – Lisaac ma wbudowane tylko 4 słowa kluczowe (niestety ma dokumentację po francusku)
Poznawanie nowych języków programowania może być pożyteczne! Wnioski Wnioski Poznawanie nowych języków programowania może być pożyteczne!
MIT SICP 101 - http://www.academicearth.org/ Bibliografia Bibliografia MIT SICP 101 - http://www.academicearth.org/ Douglas Crockford, YIU Theather - http://crockford.com/javascript/ Funkcje Lambda w C# http://blogs.msdn.com/b/sriram/archive/2005/08/07/448722.aspx Antero Taivalsaari, Classes vs. Prototypes: Some Philosophical and Historical Observations http://citeseerx.ist.psu.edu/viewdoc/download? doi=10.1.1.56.4713&rep=rep1&type=pdf Prototypes with multiple dispatch - http://tunes.org/~eihrul/ecoop.pdf Lisaac - http://isaacos.loria.fr/li.html Lua - http://www.lua.org/
THE END Q&A?