Proceduralni jezici - FESB
Proceduralni jezici - FESB
Proceduralni jezici - FESB
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Programski <strong>jezici</strong><br />
2009<br />
1. Povijest programskih jezika<br />
2. Što definira programski jezik:<br />
Leksička struktura<br />
Sintaksa<br />
Semantika<br />
3. Elementi s kojima manipuliramo programskim jezikom:<br />
tipovi i klase,<br />
konstante i varijable,<br />
funkcije i procedure,<br />
kontrolne strukture i iznimke<br />
4. Temeljne paradigme za podjelu programskih jezika:<br />
Strojni i asemblerski jezik<br />
<strong>Proceduralni</strong> (imperativni) <strong>jezici</strong> (C, Pascal, Fortran)<br />
Objektno orijentirani <strong>jezici</strong> (C++, Java, C#)<br />
Funkcionalni <strong>jezici</strong> (Lisp, Sheme, ML, Haskell)<br />
Logički orijentirani <strong>jezici</strong> (Prolog)<br />
Vizualno programiranje<br />
Učit ćemo barem jedan jezik iz svake grupe.<br />
1
Smjerovi razvoja programskih jezika<br />
U početku, ... programi su pisani u strojnom kodu, sekvence bitova, obično u heksadecimalnoj notaciji, predstavljali su i<br />
naredbe i podatke u računalu.<br />
Primjer:<br />
34020005<br />
0000000c<br />
3c011001<br />
Koji čudak moţe pisati programe na ovaj način (bilo ih je nekoliko)<br />
Prvi simbolički jezik - Asembler<br />
Umjesto binarnih nizova pišu se simbolička imena naredbi i memorijskih lokacija<br />
Primjer:<br />
mov eax,5<br />
push eax<br />
call absvalue<br />
sub esp, 4<br />
Ovo je lakše razumjeti od binarnih sekvenci, ali i dalje se mora programirati na vrlo niskoj razini - direktno se manipulira s<br />
memorijom i vanjskim ureĎajima.<br />
2
U asembleru:<br />
o Postoji samo jedan tip podataka - niz bajta.<br />
o Kontrolne strukture su: uvjetni i bezuvjetni skokovi.<br />
o Imena (varijabli i labela) su globalni objekti<br />
o Potprogrami se realiziraju kao prosti skokovi na mjesto izvršenja programa.<br />
o Nije poznat mehanizam prijenosa argumenata funkcije.<br />
Fortran (Formula Translator)<br />
Prvi pravi programski jezik, razvijen 50-tih godina.<br />
Primjer:<br />
sum = 0<br />
do 10 i=1,100<br />
10 sum = sum + a(i)<br />
Korak naprijed u programiranju:<br />
Programiranje postaje ―problemski orijentirano‖, a manje je ―strojno orijentirano.‖<br />
Uvode se kontrolne strukture: "if" - selekcija i "do"-petlja .<br />
Uvodi se mehanizam prijenosa argumenata potprograma<br />
Razlikuju se funkcije i procedure<br />
Novije varijante su: Fortran 77, Fortran 90 i HPF (High Performance Fortran).<br />
3
Cobol (Common Business Oriented Language)<br />
Jezik za poslovne aplikacije s bazama podataka. Razvijen početkom 60-tih godina.<br />
Primjer:<br />
multiply i by 3 giving j.<br />
move j to k.<br />
write line1 after advancing<br />
1 lines.<br />
Cobol je:<br />
o Prvi standardizirani programski jezik.<br />
o Još i danas se koristi u komercijalnim aplikacijama.<br />
o Jezik s dosta riječi, pogodan za proste programere.<br />
o Prvi puta otvara diskusiju o potrebi pisanja razumljivog kôda<br />
4
BASIC<br />
BASIC (Beginner’s All-purpose Symbolic Instruction Code) je kreiran na DARTMOUTH College od John Kemeny i<br />
Thomas Kurtz-a 1964. godine kao jezik za ne-profesionalce. To je bio prvi pravi interpreter.<br />
Varijable su zapisivane jednim slovom ili slovom iza kojeg slijede znamenke.<br />
Ne koristi se eksplicitne deklaracije varijabli.<br />
Varijable mogu biti numeričke vrijednosti ili stringovi.<br />
Svakoj naredbi prethodi numerička oznaka, koja se koristi kao oznaka za skokove u programu.<br />
Primjer:<br />
10 REM A SAMPLE BASIC PROGRAM FOR SORTING ARRAY A<br />
20 DIM A(100)<br />
30 FOR I = 1 TO 100<br />
40 INPUT A(I)<br />
50 NEXT I<br />
60 FOR I = 1 TO 100<br />
70 J = I<br />
80 FOR K = J+1 TO 100<br />
90 IF A(K) < A(J) THEN 130<br />
100 T = A(I)<br />
110 A(I) = A(J)<br />
120 A(J) = T<br />
130 NEXT K<br />
140 NEXT I<br />
150 STOP<br />
160 END<br />
Današnje verzije BASIC jezika, primjerice Visual Basic, nemaju značajnije sličnosti s ovim jezikom.<br />
5
Algol 60 (Algorithmic Language)<br />
Razvijen 1960. kao prvi jezik koji je potpuno pogodan za strukturalno programiranje. Direktni je prethodnik jezika Pascal,<br />
C, C++ i Java.<br />
Primjer:<br />
real procedure cheb(x,n);<br />
value x,n;<br />
real x; integer n;<br />
cheb := if n = 0 then 1<br />
else if n = 1 then x<br />
else 2 * x * cheb(x,n-1) - cheb(x,n-2);<br />
Algol uvodi u programske jezika danas standardne elemente:<br />
o Blokovi s lokalnim deklaracijama<br />
o UgnijeţĎene deklaracije i kontrolne strukture.<br />
o Prijenos parametara potprograma,<br />
o Potprogrami mogu biti rekurzivni.<br />
Iako dobro koncipiran, nije šire prihvaćen jer:<br />
o Nema standardizirani pristup I/O ureĎajima.<br />
o IBM je preferirao razvoj Fortrana i PL/I.<br />
6
Lisp (List Processing Language)<br />
Lisp je razvijen početkom 60-tih godina. U njemu se odstupa od proceduralne (imperativne) osnove programskih jezika, a<br />
uvode se elementi funkcionalnog programiranja<br />
Primjer Lisp interpretera:<br />
>(+ 1 2 5)<br />
8<br />
>((lambda (x) (* x x)) 10)<br />
100<br />
Karakterisike Lispa:<br />
o Program i podaci se predstavljaju kao liste u prefiksnoj notaciji<br />
o (+ 9 8 7) znači: izraz kojem se rezultat dobije zbrajanjem brojeva 8,8 i 7<br />
o Ne postoji deklaracija tipova varijabli<br />
o Tipovi su svojstva vrijednosti podataka, a ne svojstva varijable ili parametara funkcije.<br />
o Program u toku izvršenja moţe stvarati i izvršavati funkcije i izraze<br />
o Vrši se automatsko alociranje memorije - koristi se "garbage collection" mehanizam<br />
Pri razvoju jezika prvi put je razvijena i definirana formalna semantika - njome se precizno odreĎuje značenja<br />
programa.<br />
Slijednik Lispa je jezik Scheme koji uvodi neke elemente iz Algola (lokalni doseg).<br />
7
Simula 67 (Simulation Algol)<br />
Simula 67 je prvi objektni jezik - uvodi se definiciju klasa<br />
Primjer:<br />
Class Rectangle (Width, Height);<br />
Real Width, Height;<br />
Boolean Procedure IsSquare;<br />
IsSquare := Width=Height;<br />
End of Rectangle;<br />
Simula 67 proširuje Algol s:<br />
definicija klase i proširene klase.<br />
Definicija objekata i garbage collector.<br />
ADA<br />
ADA - jezik je sredinom 70-tih razvijen za U.S. Dept. of Defense<br />
Ističe vaţnost modularnog programiranja<br />
8
C i C++<br />
C je razvijen početkom 70-tih godina, a C++ sredinom 80-tih godina. Oba jezika su prihvaćeni kao temeljni <strong>jezici</strong> za<br />
"performance-critical applications": izradu operativnih sustava i sistemskog softvera.<br />
Omogućuju platform-independent programiranje. (#define leksičke - supstitiucije)<br />
Oba jezika mogu koristiti i početnici i profesionalni programeri, ali to ne znači da su podesni za početno poimanje<br />
programiranja.<br />
To bolje omogućuju Java i C#. Jednostavnost slijedi iz činjenice da ovi <strong>jezici</strong> ne koriste pokazivače.<br />
Java<br />
Jezik Java je razvijen krajem 90-tih, kao jezik za izradu distribuiranih mreţnih programa. Glavne karakteristike su :<br />
Jednostavniji je i čišći jezik od C++, što je ostvareno nauštrb brzine izvršenja programa.<br />
Čisti OO jezik - sve konstrukcije jezika se definiraju unutar klase.<br />
Naglasan na sigurnosti, a ne na brzini.<br />
Potpuna neovisnost o operativnom sustavu.<br />
C#<br />
Vrlo je sličan Javi, ali je nešto bliţi C++ jeziku nego Java.<br />
9
Zašto se istražuju novi programski <strong>jezici</strong>?<br />
1. Znatiželja<br />
Koji drugi oblici jezika mogu biti realizirani?<br />
2. Produktivnost<br />
Standardni proceduralni <strong>jezici</strong> su vrlo zahtjevni kad treba razvijati softver posebne namjene. U tom slučaju je moţda bolje<br />
razviti intepreter za tu posebnu namjenu. Primjerice, jezik Matlab omogućuje jednostavno rješavanje matematičkih<br />
problema.<br />
3. Sigurnost i pouzdanost<br />
I dalje je pitanje sigurnosti izvršenja programa vrlo vaţno pitanje, koje je moţda moţe bolje riješiti u samom programskom<br />
jeziku.<br />
4. Brzina izvršenja<br />
Jezici C i C++ omogućuju najbrţe izvršenje programa na standardnim računalima, meĎutim nisu pogodni za sustave<br />
računala koji rade paralelno ili distributivno.<br />
10
Poželjne karakteristike programskih jezika<br />
Gledano teoretski, kada programski jezik tretiramo kao dio stroja računala, tada su skoro svi programski <strong>jezici</strong> ekvivalentni<br />
i pomoću njih se mogu riješiti svi problemi koje je moguće riješiti računalom (Church –Turing teza). Ipak, <strong>jezici</strong> imaju i<br />
druge, mnogo značajnije funkcije a to je da omoguće apstrakciju, efikasne programe i ugodno programiranje.<br />
Koje svojstva jezika su poţeljna?<br />
Jednostavnost upotrebe jezika.<br />
o Programi trebaju biti jednostavni i razumljivi<br />
o Konstrukcije jezika trebaju biti ortogonalne, tj. da postoji samo jedan način izvršenja.<br />
o Zapis treba biti što bliţi duhu aplikacije koja se programira.<br />
Jezik treba podrţavati apstrakciju.<br />
o Postojeće strukture i operacije trebaju biti dogradive za nove apstraktne strukture.<br />
Jezik treba omogućiti jednostavno testiranje i debagiranje programa.<br />
Poţeljno je imati IDE sa sustavom pomoći, editorom i debagerom.<br />
Poţeljno je da jezik omogućuje portabilnost za različite operativne sustave.<br />
Opći su zahtjevi:<br />
o Brzina izvršenja i mali zahtjevi za memorijom.<br />
o PrevoĎenje brzo i modularno, s pripadnim bibliotekama.<br />
o Komponente jezika trebaju biti "reusable"<br />
11
Programske i jezičke paradigme<br />
Programske jezike dijelimo prema 4 fundamentalna stila - paradigme: proceduralni, objektno orijentirani, funkcionalni i<br />
logički.<br />
<strong>Proceduralni</strong> <strong>jezici</strong><br />
C, Fortran, Pascal, Ada, itd.<br />
Program se izvršava naredbu po naredbu, te očitava i mijenja sadrţaj memorije.<br />
Na isti način radi i procesor koji komunicira s RAM memorijom..<br />
Pitanje: Za segment programa<br />
a = a + 1;<br />
if (a > 10)<br />
b = 10;<br />
else<br />
b = 15;<br />
a = a * b;<br />
Zašto ovaj program pet procesora ne moţe izvršiti pet puta brţe?<br />
Uoči: ovisnost reda izvršenja i vrijednosti varijable.<br />
12
Kod proceduralnih jezika funkcije često iskazuju bočne efekte (side effects)<br />
int global=1;<br />
int Mul(int x) {<br />
global = global *x;<br />
return global;<br />
}<br />
// side effect – bočni efekt na globalnu var.<br />
int main()<br />
{ // Loše je što<br />
cout
Objektno-orijentirani <strong>jezici</strong><br />
C++, Java, C#, Smalltalk, Pizza i Python su objektno-orijentirani <strong>jezici</strong>.<br />
Podaci i funkcije zdruţeno odreĎuju svojstva i aktivnost objekata.<br />
Objekti su aktivni entiteti sa stabilnim stanjem, i sučeljem prema drugim objektima, s kojima se komunicira pomoću poruka<br />
ili metoda.<br />
U definiranju objekata koristi se princip nasljeĎivanja, princip komponiranja objekata i princip zajedničkog sučelja<br />
(interfejsa).<br />
Interface (sučelje) u JAVI ili virtualne funkcije u C++ jeziku odreĎuju način komuniciranja s različitim objektima, što<br />
omogućuje da se programi izvršavaju polimorfno (višeoblično).<br />
C++ takoĎer omogućuje programske tehnike:<br />
o Modularno programiranje kao podrška za „data hidding―<br />
o Generičko programiranje<br />
o Rukovanje iznimkama<br />
U C# i Javi sve mora biti deklarirano unutar klase, čak i Main() funkcija, od koje starta izvršenje programa<br />
14
C++ program<br />
int main()<br />
{<br />
cout
Funkcionalni <strong>jezici</strong><br />
U funkcionalnim <strong>jezici</strong>ma,<br />
procedure (funkcije) su entiteti prve klase<br />
Entiteti prve klase:<br />
Mogu biti pridjeljeni varijablama<br />
Mogu biti argumenti funkcija<br />
Mogu biti vrijednost koju funkcija vraća.<br />
Mogu biti elementi sloţenih struktura podataka.<br />
Lisp, Scheme i ML su "prirodno" funkcionalni <strong>jezici</strong>.<br />
> (define sqr (lambda (x) (* x x)) # varijabla sqr je funkcija(lambda)<br />
> (sqr 10) # apliciraj funkciju sqr na argument 10<br />
> 100 # rezultat je 100<br />
Program sadrţi izraze koji se "evaluiraju".<br />
Dizajn jezika minimizira bočne efekte uključujući i izbjegavanje upotrebe naredbe pridjele vrijednosti.<br />
16
Logički programski <strong>jezici</strong><br />
Prolog je logički programski jezik. U njemu korisnik zapisuje:<br />
o činjenice i<br />
o što program treba obaviti,<br />
o a ne zapisuje se postupak kojim se izvršava program<br />
Ne koristi se klasična kontrola tijeka programa.<br />
Primjer:<br />
inOrder( [] ).<br />
inOrder( [ _ ] ).<br />
inOrder([a,b|c]) :- (a < b),<br />
inOrder([b|c]).<br />
Ovo je kompletni program, kojim se odreĎuje da li je lista ureĎena.<br />
Primjetite da nema deklaracija, varijabli i eksplicitno zadanih petlji.<br />
17
Koncepti iz programskih jezika<br />
Deklaracija / Doseg / Životnost / Povezivanje - statičko/dinamičko<br />
Identifikatori varijabli i funkcija se deklariraju, eksplicitno ili implicitno iz konteksta prve upotrebe.<br />
Deklaracije povezuju (bind) tip i vrstu s identifikatorom. Primjerice<br />
static int var;<br />
int je tip, static je vrsta varijable var.<br />
Svaki identifikator ima doseg (scope ) u programu— to je dio programa u kojem je vidljiv identifikator<br />
Ţivotnost (lifetime) — je vrijeme u kojem identifikator referira memorijski objekt. Obično je ţivotnost povezana s<br />
dosegom identifikatora, tj. objekt traje za vrijeme izvršenja programa iz dosega identifikatora.<br />
Svojstva identifikatora (i objekta koji on predstavlja) se odreĎuju:<br />
1. Tijekom kompiliranja (Compile-time )<br />
Ta svojstva se nazivaju statična i ne mijenjaju se tijekom izvršenja programa<br />
Primjeri: tip varijable ili tijelo funkcije.<br />
2. Tijekom izvršenja (Run-time)<br />
Ta svojstva se nazivaju dinamička i mogu se mijenjati tijekom izvršenja programa.<br />
Primjeri: vrijednost varijable, dinamički alocirani objekti, argumenti funkcije itd.<br />
18
Dinamički alocirane varijable<br />
U C++ se koristi pokazivače i operatore new i delete. Primjerice, dinamički niz od 6 cijelih brojeva formira se naredbom:<br />
int *pa = new int[6]; // C++<br />
Kada nam više ne treba ova varijabla brišemo je iz memorije operatorom delete:<br />
delete [] pa; // C++<br />
U Javi i C# se svi objekti i nizovi formiraju dinamički - primjenom new operatora. Dealociranje memorije ne vrši korisnik<br />
već se vrši automatski pomoću mehanizma "skupljača smeća" (garbage collection). Zbog toga, jer u Javi i C# nema statičkih<br />
nizova i objekata, njihova imena, iako predstavljaju pokazivače, tretiraju se kao reference. To pojednostavljuje zapis<br />
programa na način da se članovima struktura i klasa uvijek pristupa pomoću točka operatora.<br />
class Test // Java program<br />
{<br />
public static void main(String[] args) {<br />
int[] arr = new int[6];<br />
for (int i = 0; i < arr.length; i++)<br />
arr[i] = i * i;<br />
for (int i = 0; i < arr.length; i++)<br />
System.out.println("arr[" + i + "] = " + arr[i]);<br />
}<br />
}<br />
19
U Javi i C# svi objekti se stvaraju dinamički<br />
class A<br />
{<br />
public void F() { System.out.println("A.F"); }<br />
}<br />
class Test<br />
{<br />
public static void main(String[] args) {<br />
A b = new A(); // dinamički alocirani objekt b<br />
b.F();<br />
// članovima se pristupa pomoću točka operatora<br />
} // iako b stvarno predstavlja pokazivač<br />
}<br />
20
Blok struktuirani <strong>jezici</strong><br />
Algol 60, Pascal, C, C++, Java.<br />
Identifikatori mogu imati lokalni i globalni doseg.<br />
Deklaracije mogu biti lokalne - unutar klase ili bloka.<br />
Ugnjeţdeni blokovi imaju različiti doseg. Identifikatoru se pridjeljuje leksički najbliža deklaracija.<br />
Povezivanje identifikatora i deklaracije je obično statično (ili leksičko), ali su moguća i dinamička povezivanja (npr.<br />
pretvorba tipa).<br />
Statičko (ili leksičko ) povezivanje se vrši prije izvršenja programa— za vrijeme kompiliranja<br />
Primjer (C jezik):<br />
int x,z;<br />
void A() {<br />
float x,y;<br />
print(x,y,z); // use global var z<br />
}<br />
void B(int y) {<br />
print (x,y,z) // use global vars x,z<br />
}<br />
21
Blok struktura<br />
U većini slučajeva blok struktura znači:<br />
Nije moguć pristup identifikatorima izvan njihova dosega.<br />
Primjenjuje se najbliţa prethodna deklaracija.<br />
Lokalne varijable se automatski alociraju i dealociraju<br />
Postoje varijacije od ovih pravila. U Javi se moţe koristiti objekt tek kada je kreiran pomoću new operatora,<br />
Primjerice,<br />
...<br />
Object Obj;<br />
...<br />
stvara referencu Java objekta ali ne i memoriju za taj objekt.<br />
Tek kada se izvrši stvaranje objekta s<br />
Object Obj = new Object();<br />
...<br />
njemu se moţe pristupiti.<br />
22
Dinamički doseg<br />
Pod dinamičkim dosegom podrazumijeva se da se za identifikator uzima deklaracija koja je najbliţe prema vremenu<br />
izvršenja programa. Taj se princip koristio u ranim verzijama jezika Lisp.<br />
Problem nastaje ako varijabla nije lokalno deklarirana. Primjerice, problem je ilustriran s kvazi-C jezikom<br />
int x;<br />
void print()<br />
{<br />
write(x);<br />
}<br />
main () {<br />
bool x;<br />
print();<br />
}<br />
Kod statičkog povezivanja x se ispisuje u funkciji print() kao tip int, jer je int x, globalno deklariran.<br />
Kod dinamičkog povezivanja, pošto print nema lokalnu deklaraciju za x, ispituje se pozvana funkcija u kojoj je x tipa<br />
bool.<br />
Dinamičko povezivanje je vrlo teško provesti, stoga se ono izbjegava. Ono čak izgleda i bizarno, ali se ipak koristi, i to kod<br />
virtualnih funkcija u C++, C# i Java jeziku.<br />
23
Virtualne funkcije<br />
Primjer: C# jezik – dinamičko povezivanje s virtualnim funkcijama<br />
using System;<br />
class C {<br />
public void DoIt() {PrintIt();}<br />
public virtual void PrintIt() {Console.WriteLine("C rules!");}<br />
}<br />
class D : C {<br />
override public void PrintIt() {Console.WriteLine("D rules!");}<br />
public void TestIt() {DoIt();}<br />
}<br />
class Test{<br />
public static void Main() {<br />
D dvar = new D();<br />
dvar.TestIt();<br />
}<br />
}<br />
//D rules! is printed.<br />
24
U jeziku Java – "sve metode su virtualne"<br />
Primjer:<br />
class C {<br />
void DoIt() {PrintIt();}<br />
void PrintIt() {System.out.println("C rules!");}<br />
}<br />
class D extends C {<br />
void PrintIt() {System.out.println("D rules!");}<br />
void TestIt() {DoIt();}<br />
}<br />
class Test {<br />
public static void main (String args[]) {<br />
D dvar = new D();<br />
dvar.TestIt();<br />
}<br />
}<br />
//D rules! is printed.<br />
25
Domaći rad: Napišite C++ program koji daje isti izlaz.<br />
26
Doseg i životnost<br />
Obično se zahtijeva da ţivotnost varijable bude barem jednaka vremenu koji odgovara izvršenu dosega varijable.<br />
Ţivotnost nekih objekata nadmašuje njihov doseg. Primjer za to su static ili own varijable.<br />
void f() {<br />
static int i = 0;<br />
print(i++);<br />
}<br />
Svaki poziv f() ispisuje različitu vrijednost od i (0, 1, ...) . Varijabla i zadrţava vrijednost izmeĎu poziva funkcije.<br />
Neki <strong>jezici</strong> dozvoljavaju inicijaliziranje varijabli u svakom dosegu.<br />
ML<br />
Let<br />
id = val<br />
in<br />
statements<br />
end;<br />
C<br />
{<br />
type id = val;<br />
statements<br />
}<br />
27
Strukture i blokovi<br />
Podaci se grupiraju u strukture:<br />
struct complex { float re, im; }<br />
a programski kod se grupira u blokove:<br />
{<br />
}<br />
float re, im;<br />
re = 0.0; im = 1.0;<br />
Iako slično izgledaju, blok i struktura su potpuno različiti entiteti:<br />
o Strukture su podaci,<br />
o Blokovi sadrţe programski kod i deklaracije,<br />
Ako u strukturu dodamo definiciju funkcija i inicijalizacijski kod (konstruktora i destruktora) dobije se definicija klase:<br />
class complex<br />
{<br />
public:<br />
float re, im;<br />
complex (float v1, float v2){ re = v1; im = v2; }<br />
}<br />
28
Klase<br />
Klasa se koristi za stvaranje jednog ili više objekata<br />
Deklarirane varijable se nazivaju članovi ili polja, a deklarirane funkcije se nazivaju metode ili članske funkcije klase,<br />
Dvije posebne funkcije, kojima se ne zadaje tip, i koje imaju ime klase , predstavljaju konstruktor i destruktor klase<br />
Unutar klase članovi se mogu grupirati s atributom public, private ili protected, što označava razinu dozvole pristupa<br />
članovima klase.<br />
Ekvivalentnost tipa za klase<br />
Klase dijelo moţemo tretirati i kao tipove podataka.<br />
U C++ i Javi, objekti neke klase su ekvivalentnog tipa i mogu se pridjeljivati jedan drugom, pr.<br />
class MyClass {<br />
...<br />
}<br />
MyClass v1, v2;<br />
v1 = v2; // Pridjela vrijednosti je OK<br />
Ova naredba pridjele vrijednosti ne mora biti uvijek u C++ izvršena s ţeljenim učinkom.<br />
Pogledajmo slučaj u Javi i C++<br />
29
JAVA<br />
Razmotrimo klasu Point kojom se može stvarati n-dimenzionalne točke:<br />
class Point { // in Java<br />
int dimensions;<br />
float coordinates[];<br />
Point () {<br />
dimensions = 2;<br />
coordinates = new float[2];<br />
}<br />
Point (int d) {<br />
dimensions = d;<br />
coordinates = new float[d];<br />
}<br />
}<br />
Point plane = new Point();<br />
Point solid = new Point(3);<br />
plane = solid; //OK u Javi<br />
U Javi je dozvoljeno pridjeljivanje objekata iste klase, iako u ovom primjeru, od dvodimenzionalne točke stvaramo<br />
trodimenzionalnu točku.<br />
30
U C++ postoji problem plitkog i dubokog kopiranja, koji se rješava tako da korisnik sam definira operator pridjele<br />
vrijednosti. Ortodoksni kanonički oblik klase u C++ zahtijeva da se definira a) konstruktor, b) destruktor, c) operator = i d)<br />
kopirni konstruktor:<br />
#include <br />
class Point {<br />
public:<br />
int dimensions;<br />
float *coordinates;<br />
Point (int d = 2) {<br />
dimensions = d;<br />
coordinates = new float[d];<br />
}<br />
~Point() {delete [] coordinates;}<br />
// mora se definirati za dinamički<br />
// alocirane članove<br />
Point &operator =(Point &p) {<br />
if(this == &p) return *this;<br />
if(p.dimensions != dimensions) {<br />
delete [] coordinates;<br />
coordinates = new float[p.dimensions];<br />
}<br />
for(int i=0; icoordinates[i]=i;<br />
plane = solid; //OK in if operator = defined<br />
// but plane is now 3d point<br />
for (i=0; idimensions; i++)<br />
std::cout coordinates[i]
Subklase nisu ekvivalentnog tipa<br />
Temeljna se klasa naziva superklasa, a izvedene klase se nazivaju subklase. TakoĎer se za temeljnu klasu koristi<br />
naziv roditelj (parent class), a izvedene klase se nazivaju djeca (child classes),<br />
U C++, C# i Javi subklase (ili subtipovi) se stvaraju pomoću nasljeĎivanja, ali to ne znači da se te klase istog tipa<br />
Primjer u Javi:<br />
class Point2 extends Point<br />
{<br />
Point2() {super(2); }<br />
}<br />
// super je konstruktor roditelja<br />
class Point3 extends Point<br />
{<br />
Point3() {super(3); }<br />
}<br />
Point2 plane = new Point2();<br />
Point3 solid = new Point3();<br />
plane = solid; //Illegal in Java<br />
32
C++:<br />
class Point2 :public Point {<br />
public:<br />
Point2() : Point(2) {}<br />
};<br />
class Point3 :public Point {<br />
public:<br />
Point3() : Point(3) {}<br />
};<br />
int main()<br />
{<br />
Point2 *plane = new Point2();<br />
Point3 *solid = new Point3();<br />
for (i=0; idimensions; i++)<br />
solid->coordinates[i]=i;<br />
plane =reinterpret_cast (solid);<br />
//OK if type cast<br />
for (int i=0; idimensions; i++)<br />
std::cout coordinates[i]
Izlaz je: 0 1 2<br />
Ako se deklarira u C++:<br />
class Point2 :public Point {<br />
public:<br />
Point2() { Point(2); } // umjesto Point2() : Point(2) {}<br />
};<br />
class Point3 :public Point {<br />
public:<br />
Point3() { Point(3); } // umjesto Point3() : Point(3) {}<br />
};<br />
Za main() isti kao prije<br />
izlaz je: 0 1<br />
Objasni: Zašto je nestala treća dimenzija?<br />
Problem je u korištenju konstruktora :<br />
Point3() { Point(3); } umjesto Point3() : Point(3) {}<br />
Zaključak: Dobro je da nas Java čuva od ovakovih grešaka.<br />
34
Generičke klase i parametrički polimorfizam<br />
Postavlja se pitanje, kako se moţe stvarati napredne strukture podataka koje se mogu primijeniti na različite tipove.<br />
Primjerice, moţe li se napraviti klasu za vezanu listu koja će moći sadrţavati različite tipove podataka.<br />
Najjednostavniji način je primijenjen u jeziku Java, na način da sve klase nasljeĎuju jedinstvenu temeljnu klasu Object.<br />
U Javi se onda vezana lista definira sljedećom klasom:<br />
class LinkedList<br />
{<br />
Object value;<br />
LinkedList next;<br />
Object head() {return value;}<br />
LinkedList tail(){return next;}<br />
LinkedList(Object O)<br />
{value = O; next = null;}<br />
LinkedList(Object O,LinkedList L)<br />
{value = O; next = L;}<br />
}<br />
Vidimo da ova klasa sadrţi objekte tipa Object. Pošto je referenca objekta u Javi zapravo pokazivač objekta tada se ovom<br />
objektu moţe pridijeliti objekt bilo kojeg tipa, ali:<br />
o Mora se vršiti pretvorba tipa Object u stvarni tip ako ţelimo dobiti objekt iz liste<br />
o Za pretvorbu tipa mora postojati definirana klasa. Primjerice ako ţelimo da lista sadrţi cijele brojeve za<br />
pretvorbu tipa nam je potrebna klasa Integer a ne primitivni tip int (jer primitivni tip nije klasa).<br />
35
Primjer, manipuliranje s vezanom listom koja sadrţi cijele brojeve :<br />
LinkedList l =new LinkedList(new Integer(123));<br />
int i = ((Integer) l.head()).intValue();<br />
Očito je ovaj pristup u Javi, a slično je bilo i u prvim bibliotekama C++, dosta nepraktičan. Zbog toga je u C++ uveden<br />
mehanizam predložaka (template) a sada se uvodi u C# i u Javu (probna verzija je dana u jeziku Pizza). Mahanizam<br />
predloţaka stvara generičke klase i to se naziva parametrički polimorfizam.<br />
Evo kako izgleda generički definirana vezana lista u jeziku Pizza:<br />
class LinkedList {<br />
T value;<br />
LinkedList next;<br />
T head() {return value;}<br />
LinkedList tail() {return next;}<br />
LinkedList(T O) {value = O; next = null;}<br />
LinkedList(T O,LinkedList L){value=O; next=L;}<br />
}<br />
LinkedList l = new LinkedList(123);<br />
int i = l.head();<br />
Isto kao u C++ parametrički tip se zapisuje u zagradama , a stvarni tip se definira pri deklaraciji objekta.<br />
36
Preopterećenje (Overloading) funkcija ili ad-hoc polimorfizam<br />
U klasama se često definira više funkcija (ili konstruktora) s istim imenom ali s različitim parametrima. To zovemo<br />
preopterećenjem funkcije. Primjer:<br />
class MyClass {<br />
int f(int i) { ... }<br />
int f(float g) { ... }<br />
int f(int i, int j) { ... }<br />
}<br />
C++ i Java ne dozvoljavaju de se preopterećene funkcije razlikuju po povratnoj vrijednosti, već moraju biti različiti<br />
parametri funkcije (broj parametara ili tip) To znači da<br />
class MyClass {<br />
int f() { ... }<br />
float f() { ... }<br />
}<br />
nije dozvoljeno.<br />
37
Preopterećenje operatora<br />
C++ i C#, dozvoljavaju preopterećenje (promjenu značenja) postojećih operatora. Primjer:<br />
class MyClass {<br />
int i;<br />
public:<br />
int operator+(int j) { return i+j; }<br />
}<br />
MyClass c;<br />
int i = c+10;<br />
int j = c.operator+(10);<br />
int k = 10+c; // Nije dozvoljeno!<br />
Izraz 10+c nije ispravan jer nije definirano djelovanje operatora + za objekte tipa int i MyClass&. To se moţe<br />
ostvariti u C++ pomoću friend mehanizma, koji omogućuje pristup private članovima:<br />
class MyClass {<br />
int i;<br />
public:<br />
int operator+(int j) {return i+j; }<br />
friend int operator+ (int j, MyClass& v) {return j+v.i; }<br />
}<br />
MyClass c;<br />
int k = 10+c; // OK!<br />
C++ dozvoljava preopterećenje postojećih operatora. Neki <strong>jezici</strong>, poput Algola 68 dozvoljavaju definiranje novih operatora.<br />
38
Prijenos argumenata (stvarnih parametara) funkcije<br />
Stvarni parametar ili argument funkcije je objekt koji se deklarira kao formalni parametar funkcije. On ima ime, i<br />
vrijednost i adresu (ukoliko nije konstanta). U funkciju se mogu prenositi sve tri značajke argumenta. Koriste se sljedeći<br />
nazivi za prijenos argumenata u funkciju:<br />
Prenosi se<br />
Vrijednost: Formalni parametar se tretira kao lokalna varijabla koja se inicijalizira na vrijednost argumenta. To je<br />
standardni oblik prijenosa vrijednosti konstanti i skalarnih varijabli u C i Javi.<br />
Referenca: Formalni parametre je pokazivač na stvarni parametar. Koristi se u C++ i C za prijenos nizova i varijabli.<br />
Rezultat: Formalni parametar se tretira kao lokalna varijabla. Njena konačna vrijednost se nakon završetka funkcije<br />
kopira u stvarni argument funkcije.<br />
Vrijednost/Rezultat: Kombinacija dva moda. Formalni parametar se tretira kao lokalna varijabla koja se inicijalizira<br />
na vrijednost argumenta. Nakon završetka funkcije rezultat se upisuje u stvarni argument.<br />
Ime: Formalni parametar predstavlja blok koda (zovemo ga thunk) koji se evaluira da bi se dobila vrijednost ili<br />
adresa argumenta. Koristi se jedino u jeziku Algol.<br />
Read-only (Const): Dozvoljen je argument koristiti samo kao konstantu.<br />
Koji se načini prijenosa argumenata stvarno koristi?<br />
• C jezik koristi se prijenos vrijednosti, jedino se nizovima prenosi referenca (adresa nultog elementa)<br />
• C++ dozvoljava prijenos reference varijable<br />
void swap(int &a, int &b) {int t = a; a = b; b = t:}<br />
39
• C#: koristi prijenos vrijednosti, reference i rezultata;<br />
int g(int a, out int b)<br />
• Java: Skalarni tipovi (int, float, char, etc.) se prenose po vrijednosti, a objekti po referenci.<br />
• Fortran: prenosi se referenca (čak i za konstante).<br />
• Ada prenosi vrijednost / rezultat, reference i readonly konstante.<br />
Zašto se koriste različiti modovi prijenosa argumenata funkcije?<br />
o Prijenos vrijednosti štiti aktualni parametar - on se ne mijenja već se mijenja formalni parametar, koji je lokalna<br />
varijabla.<br />
o Prijenos readonly je ekvivalentan prijenosu vrijednosti, ali se naglašava ―konstantni‖ karakter argumenta.<br />
o Prijenos reference omogućuje mijenjanje argumenta. To moţe stvoriti bočne efekte, pa se koristi samo u iznimnim<br />
slučajevima.<br />
o Prijenos vrijednosti/rezultata ima efekt kao prijenos reference, ali se to izvršava na drugi način. Umjesto neposredne<br />
promjene argumenta, on se mijenja tek po završetku funkcije..<br />
o Prijenos imena odlaţe promjenu aktualnog parametra dok on stvarno ne bude korišten u nekom izrazu ( moţda i<br />
nikada. Da bi shvatili tu vrstu prijenosa razmotrimo poziv f(i,j/0). Kod normalnog poziva prvo se evaluira<br />
j/0, što daje divide fault i program završava. Ako se j/0 prenosi po imenu tada se dijeljenje odlaţe dok ne<br />
bude potreban drugi argument, a to moţe biti nikada.<br />
Prijenos po imenu je sličan onome što se kod funkcionalnih jezika naziva "lazy evaluation" (odloženo evaluiranje<br />
argumanta). Kod "lazy evaluation", ne vrši se proračun vrijednosti argumenta već se definira posebna funkcija<br />
suspension— koja daje vrijednost kada ona bude potrebna. Suprotno od "lazy evaluation" je "eagger evaluation" gdje se<br />
argumenti evaluiraju čim su definirani.<br />
40
Ekvivalentnost tipova<br />
Provjera tipova se obično radi za vrijeme kompiliranja – to zovemo static typing.<br />
Provjera tipova se moţe raditi i za vrijeme izvršenja programa - to zovemo dynamic typing.<br />
Program je tipski-siguran (type-safe) ako nije moguće primijeniti operacije na nekompatibilne tipove podataka.<br />
Čvrsto tipizirani (Strongly-typed) programski jezik zabranjuje formiranje (ili izvršenje) tipski-nesigurnih programa.<br />
Slabo tipizirani (Weakly-typed) programski jezik omogućije formiranje (ili izvršenje) tipski-nesigurnih programa.<br />
Java je čvrsto tipizirani jezik, a C i C++ su slabo tipizirani <strong>jezici</strong> koji dozvoljavaju da se zaobiĎu tipska pravila, primjerice:<br />
int i;<br />
int* p;<br />
p = (int *)i * i;<br />
Sada se p moţe koristiti kao pokazivač na int premda mnoţenje moţe rezultirati nedozvoljenim pokazivačem.<br />
Kod kontrole tipova prvo se utvrĎuje da li su dva objekta, iz nekog izraza, koji imaju tipove T1 i T2, tipski ekvivalentan.<br />
Koristi se dvije definicije tipske ekvivalentnosti:<br />
o ekvivalencija po imenu<br />
o strukturalna ekvivalencija.<br />
41
Ekvivalencija po imenu<br />
Dva tipa su ekvivalentna ako označavaju istu vrst deklaracije.<br />
Primjer:<br />
typedef int i;<br />
int j;<br />
Očito su tipovi od x i y ekvivalentni.<br />
Primjer,<br />
type PackerSalaries = int[100];<br />
type AssemblySizes = int[100];<br />
PackerSalaries salary;<br />
AssemblySizes size;<br />
Sada salary = size; nema ekvivalenciju po imenu<br />
Formalno, definira se N (ekvivalencija po imenu) s:<br />
(a) T N T<br />
(b) Za deklaraciju oblika<br />
Type T1 = T2;<br />
T1 N T2<br />
U analizi se anonimni tipovi tretiraju kao da imaju jedinstveno ime, tako<br />
int A[10]; se razmatra kao typedef int[10] T;<br />
T A;<br />
42
Strukturalna ekvivalencija<br />
Dva tipa su strukturalno ekvivalentna ako imaju istu definiciju članova strukture . Strukturalna ekvivalencija se označava s<br />
S, a definira se na sljedeći način:<br />
(a) T S T<br />
(b) Za deklaraciju oblika<br />
Type T = Q;<br />
T S Q<br />
ako T i Q su definirani pomoću istih konstruktora tipa i na isti način.<br />
To znači da u prijašnjem primjeru<br />
type PackerSalaries = int[100];<br />
type AssemblySizes = int[100];<br />
PackerSalaries salary;<br />
AssemblySizes size;<br />
salary S size<br />
pošto su oba niza s 100=100 i int S int.<br />
C i C++ u kontroli tipova koriste strukturalnu ekvivalenciju osim za strukture i klase, kod kojih se koristi ekvivalencija po<br />
imenu. Kod nizova ignorira se veličina niza. Java koristi strukturalnu ekvivalenciju za skalarne tipove. Kod nizova<br />
zahtijeva ekvivalenciju po imenu, bez obzira na veličinu niza. Za klase koristi ekvivalenciju po imenu osim što se moţe<br />
koristiti podklasa na mjestu gdje je definirana klasa.<br />
43
To znači da za definiranu funkciju:<br />
void fun(Object O) { ... };<br />
poziv<br />
fun(new Integer(100));<br />
je ispravan jer je Integer subklasa od Object.<br />
Automatska pretvorba tipova<br />
C, C++ i Java dozvoljavaju pretvorbu tipova, od toga neke pretvorbe se vrše automatski<br />
In C, C++ i Java, float se automatski stvara od tipa int, u izrazu:<br />
float f = 10; // No type error<br />
Cjelobrojni tipovi (char, short, int, long) sa automatski "proširuju":<br />
int i = 'x'; // OK - char u int<br />
U C i C++ (ali ne u Javi), cijeli broj se moţe i "suziti" s mogućim gubitkom bitova:<br />
char c = 1000000; //dozvoljeno u C++ ali ne u Javi<br />
44