Imperativ programmering Vad är det? Ett programmeringsparadigm att jämföras med funktionell programmering och logikprogrammering. Vanlig programmering Programmen skrivs som en sekvens av satser (kommandon) Programmen struktureras med hjälp av procedurer (subrutiner, underprogram, funktioner... ) Kommandon ändrar tillstånd och funktioner kan ha sidoeekter Den äldsta programmeringsmetodiken på grund av dess nära koppling till hårdvaran (von Neuman-modellen) De äldsta språken (Fortran, algol, C,... ) konstruerades för den tekniken (2008-12-03 13.1 )
Imperativ programmering forts Ett centralt begrepp i all programmering är abstraktion. Med detta menas att man döljer tekniska detaljer, nner gemensamma drag hos problem och hittar generella lösningar. Programmeringsspråken i sig innehåller abstraktioner i form av grundläggande operationer i själva språket (aritmetik på olika datatyper, selektion, iteration), fördenierade funktioner (t ex printf, getchar, sin... ) Funktioner är det äldsta sättet för programmeraren att skapa egna abstraktioner. Andra abstraktionsmekanismer: moduler, klasser, paket (2008-12-03 13.2 )
Imperativ programmering forts På 60-talet havererade många större programmeringsprojekt och andra drabbades av kraftiga förseningar skenande kostnader, Dessutom: Programmen uppfyllde inte kravspecikationen och koden gick inte att förstå och underhålla Motmedel: Software engineering Nya programmeringstekniker (2008-12-03 13.3 )
Strukturerad programmering Edsger Dijkstra: Go To Statement Considered Harmful. Böhm och Jacopini: Alla beräkningsbara funktioner kan implementeras med kontrollstrukturerna sekvens, selektion typ if (och/eller switch) och iteration typ while, (och/eller for, do). Handlar således mycket om att programmera utan goto. Dock brukar man acceptera strukturerade goto-satser som break, continue, return och throw. Pascal utvecklades av Niklaus Wirth som var en av profeterna för strukturerad programmering. Pascal resulterar i monolitiska program. (2008-12-03 13.4 )
Objektorienterad programmering (OOP) Hittills hade programmen strukturerats runt algoritmer. Ole-Johan Dahl och Kristen Nygaard utvecklade Simula 67 där programmen i stället (kunde) struktureras kring de data som skulle behandlas vilket lade grunden för det objektorientering. Språket innehöll väsentliga mekanismer som man förknippar med med OOP: klasser, klasshierarkier, inkapsling, information hiding, objekt, polymor (2008-12-03 13.5 )
Objektorientering: klasser Klassen är det mest centrala begreppet i OOP. En klass är en abstraktion av något begrepp ett program hanterar. Man kan också säga att en klass är en (ritning till en) modell av något. Exempel: Klassen Car i traksimlueringen. En verklig bil har många egenskaper men vi modellerar endast de egenskaper vi behöver. Klassen Queue är en abstraktion (modell) för en kö oavsett vad som nns i kön Klassen (egentligen interfacet) Map är en abstraktion av en avbildning Klassen Addition är en abstraktion av alla möjliga additioner Klassen SyntaxException är en abstraktion av alla syntaxfel användaren kan göra (2008-12-03 13.6 )
Klasser forts En klass-beskrivning innehåller en förteckning över attribut (data) operationer (metoder) som ingår. I Java nns denieras alltid metoderna i klassen (undantag: abstrakta klasser) men i t ex C++ ligger ofta denitionerna på annat ställe (.h respektive.c-ler) Klasser kan instansieras till objekt dvs man skapar en modell enligt ritningen. I denna process allokeras minnesutrymme för för attributen och dessa tilldelas attributen konkreta värden. Instansieringen initieras med operatorn new och själva initieringen utförs av koden i en konstruktor. (2008-12-03 13.7 )
Inkapsling En annan viktig princip är inkapsling eller information hiding vilket innebär att all åtkomst till objektet skall gå via ett väldenierade interface-metoder och att användaren av klassen inte skall behöva känna till detaljer i klassens implementation. Man vinner att problemet blir strukturerat man behöver inte tänka på allt hela tiden att klassen själv kan kontrollera att den används på rätt sätt att det går att ändra i implementationen (för att rätta fel, öka eektivitet mm) utan att användarkoden behöver ändras. (2008-12-03 13.8 )
Inkapsling forts Inkapsling åstadkommes genom att ge attribut och metoder har olika synlighet: private förhindrar access från alla andra klasser paket förhindra access från andra paket protected förhindra access från andra klasser än subklasser public inga hinder (2008-12-03 13.9 )
Klasshierarkier och arv De olika klasserna i ett program kan byggas i hierarkier (basklasser subklasser). Klasser högre upp i hierarkien representerar högre abstraktionsnivåer medan klasser lägre ner står för ökad specialisering. Exempel: Fordon > Motorfordon > Lastbil Component > Container > Window > Frame > JFrame (2008-12-03 13.10 )
Klasshierarkier och arv forts Collection<E> contains(...) add(...) remove(...) iterator()... Set<E>... SortedSet<E>... List<E>... Interface TreeSet<E> HashSet<E> LinkedList<E> ArrayList<E> Vector<E> Klasser............... Stack<E>... (2008-12-03 13.11 )
Klasshierarkier och arv forts Map<K,V> containskey(...) containsvalue(...) put(...) get(...)... SortedMap<K,V>... Interface TreeMap<K,V>... HashTable<K,V>... HashMap<K,V>... Klasser Properties<K,V>... (2008-12-03 13.12 )
Klasshierarkier och arv forts Sexpr abstract String getname() abstract Sexpr eval(map) abstract int priority() Sexpr diff(sexpr) double getvalue() boolean isconstant()... Command abstract Atom abstract Unary abstract Binary abstract String tostring() Sexpr argument String tostring() int priority() Sexpr left Sexpr right String tostring() Vars Sexpr eval(map) Quit Sexpr eval(map) Variable String ident Sexpr eval(map) String getname() Sexpr diff(sexpr) Constant Sin Cos Exp Log Evaluation Addition Subtraction Multiplication Division Assignment double value Quotation Differentiation Sexpr eval(map) String getname() Sexpr diff(sexpr) double getvalue() boolean isconstant() Negation Sexpr eval(map) String getname() Sexpr diff(sexpr) Sexpr eval(map) String getname() Sexpr diff(sexpr) int priority() (2008-12-03 13.13 )
Polymor Polymor existerar i många former (:-) De aritmetiska operatorerna är polymorfa eftersom de utför olika operationer beroende på operandernas typer (heltal, yttal) I bl a C++ kan man lägga till egna denitioner för olika datatyper (klasser) för alla operatorer (så kallad operatoröverlagring) Samma namn på funktioner (metoder) som har olika signatur Mest väsentligt för OOP: Man kan deniera en metod på era ställen i en klasshierarki och det är den som passar typen (klassen) bäst som som används dynamisk bindning. Exempel: tostring(), isconstant(), getvalue() Mallar (generics) kan ses som ett hjälpmedel för att åstadkomma polymor (2008-12-03 13.14 )
Andra viktiga begrepp i diskuterat Iteratorer Undantag Parameteröverföringsmetoder: värdeanrop, referensanrop Tekniken att bygga rekursiva strukturer. Exempel: inlägg i mängd organiserad som ett BST (dvs ett TreeSet): TreeNode insert(int key, TreeNode r) { if (r==null) return new TreeNode(key); else if ( key < r.key ) r.left = insert(key, r.left); else if ( key > r.key ) { r.right = insert(key, r.right); return this; (2008-12-03 13.15 )
Java-detaljer Struktur: en klass per l (huvudsakligen). Paket. Objekthantering: alltid med referenser Minneshantering: automatisk Alltid konstruktorer. super Metoderna tostring() och equals(object o) static Arvshierarkier med extends Abstrakta klasser Interface (interface, implements) Generics: klasser med typparametrar (2008-12-03 13.16 )
C-programmering Struktur: deklarationer på.h-ler, implementationer på.c-ler. Preprocessor: #include, #define, #ifndef, #endif struct Funktioner: värdeanrop, värderetur, kan returnera struct Pekare och pekararitmetik. Arrayer Minneshantering: explicit med malloc och free. Ingen skräpsamling! (2008-12-03 13.17 )
Hur programmerar man objektorienterat i C Exempel: Klassen Die Använd struct i stället för klass: typedef struct die { int numberofsides; int value; die, *Die; (2008-12-03 13.18 )
Die i C Implementera konstruktorer som funktioner som returnerar pekare: Die newdie(int nos) { Die d = (Die) malloc(sizeof(die)); d->numberofsides = nos; roll(d); return d; (2008-12-03 13.19 )
Die i C Skriv accessfunktioner där en parameter svarar mot this-pekaren. int getvalue(die d) { return d->value; int roll(die d) { return d->value = rand()%(d->numberofsides) + 1; Det går inte att dölja attributen utan man måste vara disciplinerad! (2008-12-03 13.20 )
Användning av Die int main() { Die t1 = newdie(42); Die t2 = newdie(42); int n = 0; while ( roll(t1)!=roll(t2) ) n++; printf("tärningarna blev lika efter %d slag\n", n); printf("värdet var %d\n", getvalue(t1)); return 0; /* Körresultat: vranx$ gcc -o die die.c vranx$ die Tärningarna blev lika efter 7 slag Värdet var 16 */ (2008-12-03 13.21 )
Exempel: En map i C /* map.h Avbildning från teckensträngar till VT */ #ifndef map #define map #define VT void * // Definierar värdetyp typedef struct listnode { char *key; VT value; struct listnode *next; listnode, *link; typedef struct mapobj { link first; link current; mapobj, *Map; (2008-12-03 13.22 )
forts map.h Map newmap(); // Skapa map void deletemap(); // Frigör allt allokerat utrymme VT put(char *key, VT v, Map m); // Lagrar nyckel-värde-par VT get(char *key, Map m); // Söker värde int containskey(char *key, Map m); // Undersöker om värde finns void printmap(map m, void vprint(void *)); #endif // end of map.h (2008-12-03 13.23 )
Klasshierarkier i C? /* sexpr.h - deklarationsfil för symboliska uttryck */ #include "map.h" typedef enum stype { CONSTANT, VARIABLE, NEGATION, QUOTATION, EVALUATION, EXP, LOG, SIN, COS, ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION, ASSIGNMENT, DIFFERENTIATION stype; typedef struct sexprobj { stype type; char *name; int priority; double value; struct sexprobj *left, *right; sexprobj, *Sexpr; (2008-12-03 13.24 )
sexpr.h forts // Konstruktorer Sexpr newconstant(double val); Sexpr newvariable(char *id); Sexpr newunary(stype type, char *name, int prio, Sexpr arg); Sexpr newbinary(stype type, char *name, int prio, Sexpr left, Sexpr right); Sexpr newnegation(sexpr arg); Sexpr newquotation(sexpr arg); Sexpr newevaluation(sexpr arg); Sexpr newexp(sexpr arg); Sexpr newlog(sexpr arg); Sexpr newsin(sexpr arg); Sexpr newcos(sexpr arg); Sexpr newaddition(sexpr left, Sexpr right); Sexpr newsubtraction(sexpr left, Sexpr right); Sexpr newmultiplication(sexpr left, Sexpr right); Sexpr newdivision(sexpr left, Sexpr right); Sexpr newassignment(sexpr left, Sexpr right); Sexpr newdifferentiation(sexpr left, Sexpr right); (2008-12-03 13.25 )
sexpr.h forts // Symbolisk aritmetik (klassen Symbolic) Sexpr negate(sexpr a); Sexpr sine(sexpr a); Sexpr cosine(sexpr a); Sexpr expe(sexpr a); Sexpr loge(sexpr a); Sexpr add(sexpr a, Sexpr b); Sexpr subtract(sexpr a, Sexpr b); Sexpr multiply(sexpr a, Sexpr b); Sexpr divide(sexpr a, Sexpr b); Sexpr diff(sexpr a, Sexpr b); (2008-12-03 13.26 )
sexpr.h forts // För utskrift (tostring-metoder) void print(sexpr s); // Evaluering (eval-metoderna) Sexpr eval(sexpr e, Map m); // Felhantering void evaluationerror(char *msg, Sexpr e); // end of sexpr.h (2008-12-03 13.27 )
Sexpr i C forts Axplock ur sexpr.c /* sexpr.c */ #include <setjmp.h> #include "sexpr.h" #include "map.h" extern jmp_buf environment; // Återstartsmiljö efter fel Sexpr newconstant(double value) { // Konstruktor för Constant Sexpr o = (Sexpr) malloc(sizeof(sexprobj)); char *s = (char*) malloc(15*sizeof(char)); o->type = CONSTANT; o->value = value; sprintf(s, "%0.4g", value); o->name = s; o->priority = 10; o->left = o->right = NULL; return o; (2008-12-03 13.28 )
sexpr.c : konstruktor för Unary Sexpr newunary(stype type, char *name, int priority, Sexpr arg) { Sexpr o = (Sexpr) malloc(sizeof(sexprobj)); o->type = type; o->left = NULL; o->right = arg; o->value = 0; o->name = strdup(name); o->priority = priority; return o; (2008-12-03 13.29 )
sexpr.c : konstruktor för Binary Sexpr newbinary(stype type, char *name, int priority, Sexpr left, Sexpr rig Sexpr o = (Sexpr) malloc(sizeof(sexprobj)); o->type = type; o->left = left; o->right = right; o->value = 0; o->name = strdup(name); o->priority = priority; return o; (2008-12-03 13.30 )
sexpr.c : några konstruktorer Sexpr newnegation(sexpr arg) { return newunary(negation, "-", 9, arg); // super Sexpr newquotation(sexpr arg) { return newunary(quotation, "\"", 9, arg); // super Sexpr newevaluation(sexpr arg) { return newunary(evaluation, "&", 9, arg); // super Sexpr newaddition(sexpr left, Sexpr right) { return newbinary(addition, "+", 3, left, right); // super (2008-12-03 13.31 )
sexpr.c : print void print(sexpr s) { if (s->left!= NULL) { if (s->left->priority < s->priority) putchar('('); print(s->left); if (s->left->priority < s->priority) putchar(')'); printf("%s ", s->name); if (s->right!= NULL) { if (s->priority >= s->right->priority) putchar('('); print(s->right); if (s->priority >= s->right->priority) putchar(')'); // På Sexpr-nivån! (2008-12-03 13.32 )
sexpr.c : eval Sexpr eval(sexpr e, Map m) { Sexpr result= newvariable("*error*"); switch (e->type) { case CONSTANT: result = e; break; case VARIABLE: if (containskey(e->name, m)) result = (Sexpr) get(e->name, m); else result = e; break; case NEGATION: result = negate(eval(e->right, m)); break; case QUOTATION: result = e->right; break; case EVALUATION: result = eval( eval(e->right, m), m); break; case SIN: result = sine( eval(e->right, m) ); break; (2008-12-03 13.33 )
sexpr.c : eval forts case ADDITION: result = add(eval(e->left, m), eval(e->right, m)); break; case SUBTRACTION: result = subtract(eval(e->left, m), eval(e->right, m)); break; case MULTIPLICATION: result = multiply(eval(e->left, m), eval(e->right, m)); break; case DIVISION: result = divide(eval(e->left, m), eval(e->right, m)); break; case ASSIGNMENT: result = eval(e->left, m); put(e->right->name, (void *)result, m); break; case DIFFERENTIATION: result = diff(eval(e->left, m), e->right); break; default: evaluationerror("eval not yet defined", e); return result; (2008-12-03 13.34 )
sexpr.c : add Symbolisk aritmetik: Sexpr add(sexpr a, Sexpr b) { if (a->type==constant && b->type==constant) return newconstant(a->value + b->value); else if (iszero(a)) return b; else if (iszero(b)) return a; else return newaddition(a,b); (2008-12-03 13.35 )
sexpr.c : di Sexpr diff(sexpr y, Sexpr x) { switch (y->type) { case CONSTANT: return newconstant(0.); case VARIABLE: if (strcmp(y->name,x->name)==0) return newconstant(1.); else return newconstant(0.); case NEGATION: return negate(diff(y->right,x)); case ADDITION: return add(diff(y->left,x), diff(y->right,x)); case SUBTRACTION: return subtract(diff(y->left,x), diff(y->right,x));... default: evaluationerror("kan inte derivera", y); return NULL; (2008-12-03 13.36 )
sexpr.c : evaluationerror void evaluationerror(char *msg, Sexpr e) { printf("*** Evalueringsfel: %s \n", msg); printf(" Vid operationen %s\n", e->name); longjmp(environment, 99); // Till återstartpunkten (2008-12-03 13.37 )
parser.h /* parser.h */ #include "tokenizer.h" #include "map.h" #include "sexpr.h" void statement(tokenizer t); Sexpr assignment(tokenizer t); Sexpr expression(tokenizer t); Sexpr term(tokenizer t); Sexpr factor(tokenizer t); Sexpr primary(tokenizer t); void syntaxerror(char *msg, Tokenizer t); (2008-12-03 13.38 )
parser.c : main /* parser.c */ #include <stdio.h> #include <setjmp.h> #include <string.h> #include "parser.h" #include "tokenizer.h" #include "map.h" #include "sexpr.h" jmp_buf environment; const int MAX_LINE_LENGTH=1000; int main() { char line[max_line_length]; Tokenizer tn = newtokenizer(line); Map map = newmap(); while (1) { (2008-12-03 13.39 )
parser.c : main forts setjmp(environment); // Återstart efter fel do { printf("? "); fgets(line, MAX_LINE_LENGTH, stdin); while (strlen(line)<=1); // Så länge tomma rader resettokenizer(tn); nexttoken(tn); if (strcmp(tn->sval,"quit")==0) break; else if (strcmp(tn->sval, "vars")==0 ) { printmap( map, print ); else { Sexpr e = assignment(tn); if ( tn->ttype!=tt_eos ) syntaxerror("förväntade radslut", tn); nexttoken(tn); print(e); printf("\n"); e = eval(e, map); print(e); printf("\n"); (2008-12-03 13.40 )
parser.c : statement void statement(tokenizer t) { Sexpr result; result = assignment(t); printf(" = "); print(result); printf("\n"); if ( t->ttype!=tt_eos ) syntaxerror("förväntade radslut", t); nexttoken(t); (2008-12-03 13.41 )
parser.c : assignment Sexpr assignment(tokenizer t) { Sexpr result = expression(t); while(t->ttype=='=') { nexttoken(t); if ( t->ttype!=tt_word ) syntaxerror("expected identifier after '='", t); else result = newassignment(result, newvariable(t->sval)); nexttoken(t); return result; (2008-12-03 13.42 )
parser.c : expression Sexpr expression(tokenizer t) { Sexpr sum = term(t); char c; while ( ((c=t->ttype)=='+') (c=='-') ) { nexttoken(t); if (c=='+') { sum = newaddition(sum, term(t)); else { sum = newsubtraction(sum, term(t)); return sum; (2008-12-03 13.43 )
parser.c : primary Sexpr primary(tokenizer t) { char *sval; Sexpr result = NULL; switch (t->ttype) { case '(': nexttoken(t); result = assignment(t); if ( t->ttype!=')' ) syntaxerror("förväntade ')'", t); nexttoken(t); break; case '-': nexttoken(t); result = newnegation(primary(t)); break; case '"': nexttoken(t); result = newquotation(primary(t)); break; (2008-12-03 13.44 )
parser.c : primary forts case '&': nexttoken(t); result = newevaluation(primary(t)); break; case TT_NUMBER: result = newconstant(t->nval); nexttoken(t); break; case TT_WORD: sval = strdup(t->sval); nexttoken(t); if ( strcmp(sval, "exp") == 0 ) result = newexp(primary(t)); else if ( strcmp(sval, "log") == 0 ) result = newlog(primary(t)); else if ( strcmp(sval, "sin") == 0 ) result = newsin(primary(t)); else if ( strcmp(sval, "cos") == 0 ) result = newcos(primary(t)); else result = newvariable(sval); break; default: syntaxerror("oväntat token", t); (2008-12-03 13.45 )
parser.c : syntaxerror void syntaxerror(char *msg, Tokenizer t) { printf("*** Syntaxfel: %s\n", msg); printf(" vid tokentyp %d '%s'\n", t->ttype, t->sval); longjmp(environment, 99); // Till återstarpunkten return; (2008-12-03 13.46 )
Annat för objektorientering Funktion med olika signatur? Nja. Man kan ha variabelt antal och variabla typer till funktioner. Se stdarg.h med funktionerna va_start, va_arg och va_end Måste själv hålla reda på antal och typer. Jfr t ex printf. Dynamisk bindning? Tja, man kan lagra funktionspekare i poster (2008-12-03 13.47 )
Funktionspekare: exempel typedef struct sexpr { int (*eval)(); sexpr, *Sexpr; Sexpr newsexpr(int (*eval)()) { Sexpr e = (Sexpr) malloc(sizeof(sexpr)); e->eval = eval; return e; int foo() {return 17; int fie() {return 42; int main() { Sexpr e = newsexpr(foo); Sexpr f = newsexpr(fie); printf("%d %d\n", e->eval(), f->eval()); /* Output: 17 42 */ (2008-12-03 13.48 )