• Nie Znaleziono Wyników

Wstęp do Programowania Obiektowego

N/A
N/A
Protected

Academic year: 2021

Share "Wstęp do Programowania Obiektowego"

Copied!
38
0
0

Pełen tekst

(1)

Wstęp do Programowania Obiektowego

Wykład 13

Paradygmaty. Składnia i semantyka.

1

(2)

PRZEGLĄD

PODSTAWOWYCH PARADYGMATÓW

2

(3)

Cztery podstawowe paradygmaty

1.

Programowanie imperatywne.

2.

Programowanie funkcyjne.

3.

Programowanie logiczne.

4.

Programowanie obiektowe.

3

(4)

Ad. 1. Programowanie imperatywne

Obliczenia rozumiemy tu jako

sekwencję poleceń zmieniających krok po kroku stan maszyny, aż do uzyskania oczekiwanego wyniku.

Stan maszyny należy z kolei rozumieć jako zawartość całej pamięci oraz

rejestrów i znaczników procesora.

Jest to ściśle związane z budową

sprzętu komputerowego o architekturze von Neumanna.

4

(5)

Architektura von Neumanna

5

Podział komputera na trzy podstawowe części:

 procesor (ALU oraz CU)

pamięć komputera (Memory)

urządzenia wejścia/wyjścia (IN/OUT)

(6)

Języki wysokiego poziomu — takie jak Fortran, Algol, Pascal, Ada lub C —

posługują się pewnymi abstrakcjami, ale wciąż odpowiadają paradygmatowi

programowania imperatywnego.

Np. instrukcja podstawienia działa na danych pobranych z pamięci i umieszcza wynik w tejże pamięci, zaś abstrakcją

komórek pamięci są zmienne.

6

(7)

Przykładowy program

imperatywny (w języku Pascal)

program pierwszy;

var i, n, s: integer;

begin read(n);

s := 1;

for i := 2 to n do s := s * i;

write(s);

end.

7

(8)

Ad. 2. Programowanie obiektowe

Program obiektowy to zbiór

porozumiewających się ze sobą

obiektów, czyli jednostek zawierających pewne dane i umiejących wykonywać na nich pewne operacje.

Ważną cechą jest powiązanie danych (czyli stanu) z operacjami na nich (czyli poleceniami) w całość,

stanowiącą odrębną jednostkę — obiekt.

8

(9)

W programowaniu obiektowym

wprowadzono szereg mechanizmów ułatwiających programowanie, m.in.

dziedziczenie (możliwość definiowania nowych, bardziej złożonych obiektów, na bazie obiektów już istniejących).

9

(10)

paradygmat obiektowy dobrze

odzwierciedla ludzkie (przedmiotowe) postrzeganie rzeczywistości.

programowanie obiektowe zdobyło

ogromną popularność i wypada je uznać za paradygmat obecnie dominujący.

10

(11)

Przykładowy program obiektowy (w języku Java)

public class Hello {

public static void main(String[] args) { System.out.println("Hello world!");

} }

11

(12)

Ad. 3. Programowanie funkcyjne

Program funkcyjny to po prostu złożona funkcja (w sensie

matematycznym), która otrzymawszy dane wejściowe wylicza pewien wynik.

12

(13)

Cechy programowania funkcyjnego

Brak stanu maszyny;

Nie ma (tradycyjnie rozumianych) pętli;

Konstruowanie programów to składanie funkcji, zazwyczaj z wykorzystaniem rekurencji.

Charakterystyczne jest definiowanie funkcji wyższego rzędu, czyli takich, dla których

argumentami i których wynikami mogą być funkcje (a nie tylko „proste” dane jak liczby lub napisy).

13

(14)

Przykładowy program funkcyjny (w języku LISP)

(DEFINE (suma m n) (IF (> m n)

0

(+ m (suma (+ m 1) n)) )

)

14

(15)

Ad. 4. Programowanie w logice (programowanie logiczne)

Na program składa się zbiór zależności (przesłanki) i pewne stwierdzenie (cel)

Wykonanie programu to próba

udowodnienia celu w oparciu o podane przesłanki.

Obliczenia wykonywane są niejako „przy okazji” dowodzenia celu.

Opisujemy jedynie, co wiemy i co chcemy uzyskać.

15

(16)

Przykładowy program logiczny (w języku Prolog)

ojciec(jan, jerzy).

ojciec(jerzy, janusz).

ojciec(jerzy, józef).

dziadek(X, Z) :- ojciec(X, Y), ojciec(Y, Z).

?- dziadek(X, janusz).

16

(17)

OGÓLNE WŁASNOŚCI PARADYGMATÓW

17

(18)

Istnieje wiele innych

paradygmatów, niektóre się przenikają

Często paradygmaty obejmują tylko

niektóre aspekty programowania,

Programowanie skalarne i macierzowe - rozróżnienie między nimi odnosi się do

tego, czy działamy na pojedynczych wartościach, czy na całych tablicach (macierzach).

Programowanie proceduralne i

programowanie strukturalne można traktować jako odmianę programowania imperatywnego.

18

(19)

Istnieją paradygmaty przeciwstawne

19

programowanie sterowane

zdarzeniami to przeciwieństwo klasycznego programowania z własnym wątkiem sterowania

…co nie oznacza, że nie można łączyć

tych dwóch paradygmatów w jednym

programie; tak jest np. w typowych

aplikacjach bazodanowych.

(20)

Konkretne język programowania mogą ucieleśniać jeden lub więcej

paradygmatów.

Fortran, Pascal i C to języki imperatywne.

Java i C# to języki typowo obiektowe, w których programowanie imperatywne zostało mocno

ograniczone.

Natomiast C++ jest językiem zarówno obiektowym, jak i imperatywnym.

Można też uznać, że programowanie imperatywne to szczególny przypadek

programowania obiektowego, gdzie wszystko rozgrywa się wewnątrz jednego „superobiektu”.

20

(21)

Architektura współczesnych komputerów

Przytłaczająca większość komputerów działa w oparciu o imperatywną architekturę von Neumanna.

Każdy program, który chcemy uruchomić, musi być zatem najpierw przetłumaczony do postaci imperatywnej, czyli do ciągu rozkazów w języku wewnętrznym

konkretnej maszyny.

Mechanizmy z różnych paradygmatów

wymagają niekiedy skomplikowanych metod, by odwzorować je w formie rozkazów

zwykłego komputera; bardzo różna jest też ich efektywność.

21

(22)

SKŁADNIA I

SEMANTYKA

22

(23)

Składnia

Składnia to zbiór reguł, mówiących jak wygląda poprawny program w

danym języku, czyli np.:

Jak tworzy się polecenia i wyrażenia.

Jaką postać mają struktury sterowania (if, while, for itp.).

Jak zapisuje się deklaracje zmiennych.

23

(24)

Semantyka

Semantyka to znaczenie

wspomnianych wyżej form, czyli w jaki sposób działają konkretne zapisy.

24

(25)

Przykład składni i semantyki

Typowa instrukcja warunkowa if w języku C\C++.

Składnia:

if "(" <wyrażenie> ")" <instrukcja>

Semantyka jest następująca: „sprawdź wartość logiczną podanego wyrażenia i jeśli jest prawdziwe, to wykonaj

podaną instrukcję, jeżeli nie to przejdź do kolejnej instrukcji.”

25

(26)

Intuicyjność semantyki

Najlepiej byłoby, gdyby semantykę dało się łatwo odgadnąć, patrząc na składnię języka.

Dla prostych konstrukcji tak zazwyczaj bywa; bardziej skomplikowane twory są niestety mniej oczywiste.

Stąd potrzebne są ścisłe metody opisu i składni, i semantyki.

26

(27)

Jak opisać składnię i semantykę?

Składnię języków będziemy opisywali za pomocą notacji BNF,

odpowiadającej gramatykom bezkontekstowym.

Semantykę rozmaitych konstrukcji

będziemy na ogół opisywali w języku naturalnym.

27

(28)

Notacja BNF (Backus Naur Form)

Definicja języka w notacji BNF to zbiór reguł.

Poszczególne reguły mają postać:

<symbol> ::= <definicja symbolu>

Sens takiej reguły jest następujący: symbol

występujący po lewej stronie znaku ::= można zastąpić tym, co pojawia się po prawej stronie.

Symbole pojawiające się po lewej stronie reguł zwane są symbolami nieterminalnymi.

Symbole pojawiające się wyłącznie po prawej stronie to symbole terminalne.

Generalnie symbole terminalne to symbole z alfabetu definiowanego języka, a zatem

„docelowe”; symbole nieterminalne spełniają natomiast rolę pomocniczą przy jego

definiowaniu.

28

(29)

Dodatkowe symbole i konwencje (1/2)

Pionowa kreska | oznacza alternatywne warianty reguły, np.

<typ> ::= char | int | float | double

Nawiasy kwadratowe [...] oznaczają opcjonalną część reguły, np.

instr_warunk ::= if wyr_logiczne then instr [ else instr ]

Nawiasy klamrowe {...} oznaczają fragment, który może być powtórzony dowolnie wiele razy (również zero razy, czyli całkowicie pominięty), np.

<lista_arg> ::= <arg> { "," <arg> }

29

(30)

Dodatkowe symbole i konwencje (2/2)

Zwykłych nawiasów okrągłych (...) używa się do

grupowania alternatywnych fragmentów definicji, np.

<liczba_ze_znakiem> ::= ("+" | "–") <liczba_bez_znaku>

Jednoznakowe symbole terminalne umieszcza się w cudzysłowie, dla odróżnienia ich od symboli samej notacji BNF.

Symbole terminalne niekiedy pisze się czcionką wytłuszczoną; nie jest wówczas konieczne pisanie nawiasów kątowych wokół symboli nieterminalnych.

30

(31)

Powtarzające się elementy

Chcąc opisać powtarzające się elementy, możemy stworzyć definicję rekurencyjną lub wykorzystać nawiasy klamrowe.

Przykład: definicja niepustej listy identyfikatorów, rozdzielonych przecinkami.

Definicja rekurencyjna:

<lista_identyfikatorów> ::= <identyfikator>

| <lista_identyfikatorów> "," <identyfikator>

Definicja z nawiasami klamrowymi:

<lista_identyfikatorów> ::= <identyfikator> { "," <identyfikator> }

31

(32)

Klasyczny przykład użycia notacji BNF to sam opis składni notacji BNF:

<składnia> ::= { <reguła> }

<reguła> ::= <identyfikator> "::=" <wyrażenie>

<wyrażenie> ::= <składnik> { "|" <składnik> }

<składnik> ::= <czynnik> { <czynnik> }

<czynnik> ::= <identyfikator>

| <symbol_zacytowany>

| "(" <wyrażenie> ")"

| "[" <wyrażenie> "]"

| "{" <wyrażenie> "}"

<identyfikator> ::= <litera> { <litera> | <cyfra> }

<symbol_zacytowany> ::= """ { <dowolny_znak> } """

32

(33)

Niedodefiniowanie – symbole domyślne

Niektóre symbole, formalnie terminalne, są właściwie niedodefiniowanymi symbolami nieterminalnymi.

Gwoli ścisłości powinniśmy zatem dopisać:

<litera> ::= "A" | "B" | "C" | ...

<cyfra> ::= "0" | "1" | ... | "9"

<dowolny_znak> ::= ...

33

(34)

PRZETWARZANIE

PROGRAMU NA KOD MASZYNY

34

(35)

Program w dowolnym

języku/paradygmacie musi zostać

przetłumaczony na język wewnętrzny

maszyny, na której program zamierzamy uruchomić.

Są trzy zasadnicze sposoby takiego tłumaczenia:

1.

Kompilacja

2.

Interpretacja

3.

Kompilacja do kodu pośredniego

35

(36)

Kompilacja a interpretacja

Kompilacja to przetłumaczenie całego programu „za jednym zamachem”. Otrzymujemy kod wynikowy, który (po konsolidacji

zwanej też linkowaniem) wykonuje się bezpośrednio na maszynie docelowej.

Interpretacja to tłumaczenie i

wykonywanie programu instrukcja po instrukcji, za pomocą programu zwanego interpreterem.

36

(37)

Rozwiązanie pośrednie

Kompilacja do kodu pośredniego – wstępnie skompilowany kod pośredni jest następnie interpretowany lub

kompilowany ponownie „w ostatniej chwili”.

Przykład: język Java. Daje to dobry kompromis między efektywnością a przenośnością kodu na różne

komputery.

37

(38)

Wpływ nieznajomość semantyki na efektywność programu

Rozważmy pozornie identyczne pętle for w Pascalu i w C:

for i := 1 to length(s) do ...

for (i = 1; i <= strlen(s); ++i) ...

Na pierwszy rzut oka pętle te powinny zachowywać się tak samo.

Jest jednak istotna różnica: w Pascalu długość napisu s zostanie policzona tylko raz, a w języku C będzie ona liczona przy każdym obiegu pętli.

To może prowadzić do fatalnego pogorszenia efektywności programu.

Wniosek: trzeba dobrze znać semantykę języka programowania, by tworzyć efektywne programy.

38

Cytaty

Powiązane dokumenty

Szafarz nadzwyczajny – osoba świecka, która może udzielić chrztu (każdy chrześcijanin). Rodzice chrzestni –

Oznacza pranie zwykłe z ustawieniem standardowej temperatury, wskazanej na materiale.. Dodatkowo piorąc w tym programie

Jednak, choć możliwe, że miejska kultura rzemieślników łączyła z kotem znaczenia, które pojawiają się w narracji oraz w makabrycznej ceremo- nii (jeśli się ona

Podziel każdą z tych figur na dwie równe części. Zamaluj kredką połowę

między tymi literami znajduje się dowolny ciąg liter a i b, taki że każde dwie litery b są oddzielone co najmniej jedną literą

techniki pracy, zmniejszenie/zwiększenie liczby zadań/kart pracy, dostosowanie środków dydaktycznych do dysfunkcji dziecka, zróżnicowanie kart pracy, stały nadzór,

:URFäDZLD&#34; &amp;]\P MHVW eZURFäDZ- VNRĈès&#34; %DJLþVNL WZLHUG]L ĔH eQLH. PD FDäNRZLFLH RELHNW\ZQ\FK NU\- WHULÑZ

Nocny Patrol, Dzienny Patrol, Patrol Zmroku, Ostatni Patrol. 177