I förra avsnittet gick vi igenom datorns och programmeringsspråkens historia. Vi fortsätter vår serie om programmering med att titta lite på vad som skiljer de olika programmeringsspråken åt.

Till att börja med finns det lågnivåspråk och högnivåspråk. Lågnivåspråk ligger närmare maskinkod (tänk ettor och nollor, för att förenkla), och är således svårare att programmera i eftersom det krävs fler kommandon för att göra samma sak, och koden är även svårare att läsa och förstå. Högnivåspråk abstraherar lågnivåspråk och gör det enklare att programmera och läsa koden. Ett av de enklaste program man kan skriva är “Hello World“, och för att demonstrera skillnaden mellan ett högnivåspråk (C) och ett lågnivåspråk (Assembler) har ni här samma program i de två språken:

C-kod och Assembler-kod som gör samma sak. Källa: http://assembly.ynh.io/

Som synes är C-koden betydligt lättare att förstå, och mindre kod krävs. Nackdelen är att om man vill att koden ska vara så effektiv som möjligt kan Assembler vara bättre, då exempelvis “puts()”-kommandot i C motsvaras av två rader i Assembler. Om någon vill veta mer exakt vad raderna i C-koden gör, säg till i forumet! Assembler-koden tänker jag inte ens försöka tolka 😉

En programmeringsparadigm kan man säga är en teori om hur ett programmeringsspråk, och programkoden man skriver i detta, ska vara uppbyggt. Några olika sådana är  imperativ programmering, funktionell programmering, logikprogrammering och objekt-orienterad programmering.

Imperativ programmering

Det första högnivåspråket hette Fortran, och ligger fortfarande på plats 24 på listan över de mest använda programmeringsspråken. Detta språk är ett imperativt sådant, och ett kännetecken för detta är att man skriver koden i samma sekvens som den sedan exekveras (körs). I princip kan man alltså säga att koden körs uppifrån och ner, med vissa hideösa undantag som kommandot GOTO. GOTO kan man säga flyttar vilken rad koden läses från, här är ett exempel i någon form av BASIC-liknande kod:

1 PRINT "HEJ"
2 GOTO 1

Den här koden kör en oändlig loop som skriver ut “HEJ” tills programmet stoppas. Nu kanske det här ser relativt oskyldigt ut, men föreställ dig att man har 10.000 rader kod och några stycken GOTO-kommandon. Det blir då väldigt bökigt att läsa koden eller felsöka om man måste leta upp rätt rad så fort det dyker upp en GOTO.

Funktionell programmering

Funktionell programmering växte fram redan under slutet av 50-talet och ett stort sådant språk är Lisp. Lisp har enkel och vacker semantik som grundar sig i matematiken, och har genom åren inspirerat massor av andra programmeringsspråk. När man programmerar funktionellt vill man bryta ned större problem i små funktioner som tar en input och skickar tillbaka en output, ungefär som en matematisk funktion. Ett enkelt exempel på en matematisk funktion, f(x) = x*x , implementerad i Lisp:

(defun x2 (x)
 (* x x))

Här ser man också något som sticker ut i Lisp, nämligen att gånger-tecknet står före de värden man vill multiplicera. Detta är praktiskt när man vill beräkna fler värden på samma gång och slipper skriva exempelvis multiplikation mellan varje. Funktionen evaluerar uttrycket och returnerar sen resultatet.

Paranteser omsluter alla funktionsanrop och definitioner i Lisp, vilket gör att koden ibland kan vara svårläst. Vanligt inom funktionell programmering är också rekursion, där man kan säga att man åter-itererar över indata tills ett givet villkor uppnås, men mer om detta i senare avsnitt.

Logikprogrammering

Logikprogrammeringen skiljer sig lite från övriga, på så sätt att man exempelvis kan ange en mängd predikat som beskriver en mängd, och sedan låta datorn lösa ut vad man är ute efter. Ett vanligt logikspråk är Prolog, som också var det första som kom. Ett väldigt enkelt exempel på Prolog-programmering är följande:

katt(X) :- djur(X).
katt(nisse).

Våra predikat säger att alla katter är djur, och att “nisse” är en katt. Om vi nu ställer frågan “djur(nisse).” (“Är nisse ett djur?”) kommer vi få svaret “True”, dvs sant.

Objekt-orienterad programmering

Hela grundtanken med objekt-orienterad programmering är att koden ska vara lättare att beskriva och återanvända på ett enhetligt sätt.

Tänk till exempel att du vill beskriva ett godtyckligt fordon, programmatiskt. Det är inte så svårt, man får bestämma vilka attribut som är gemensamma för fordon. Topphastighet kanske? Samt att de kräver ett drivmedel, men vi bestämmer inte vilket än. Ett objekt “fordon” skulle då i Java kunna se ut så här:

public class Fordon {
	private int topphastighet;
	private String drivmedel;

	public Fordon(int topphastighet, String drivmedel) {
		this.topphastighet = topphastighet;
		this.drivmedel = drivmedel;
	}

	public int visaTopphastighet() {
		return topphastighet;
	}

	public String visaDrivmedel() {
		return drivmedel;
	}
}

Lite krångligt, med så mycket kod, eller hur? Java är inte så smidigt när det kommer till kodmängd, men det har andra fördelar. Men! När vi nu har den här koden, säg att vi vill skapa ett mer specifikt fordon som har samma attribut, men lite till. Säg, en motorcykel. Istället för att skriva om klassen från början kan vi istället “ärva” från Fordon, och skriver då så här istället:

public class Motorcykel extends Fordon {
	private int antalHjul;	

	public Motorcykel(int topphastighet, String drivmedel, int antalHjul) {
		this.antalHjul = antalHjul;
		super();
	}
}

Vi har nu skapat ett motorcykel-objekt som innehåller samma attribut som Fordon, men också har ett eget attribut, “antalHjul”. Vi kan skapa hur många nya fordonstyper som helst på det här sättet. Dessa objekt kan man sen i sin tur skapa hur många kopior man vill av, och ha olika attribut på alla.

Jag tänkte inte gå igenom Javas syntax så mycket, men kan kort nämna att private/public anger huruvida ett attribut eller en metod kan nås utifrån klassen eller bara inuti. public Fordon() är objektets konstruktor, som anropas när man vill skapa ett objekt av den typen. i Motorcykels konstruktor anropas super(), vilket i princip säger att man efter att ha lagrat antalHjul i objektet ska sköta resten av objektkonstruktionen på samma sätt som superklassen, dvs Fordon.

Säg som motexempel att man skapar en motorcykel programmatiskt utan att använda objektorientering, och i efterhand kommer på att man vill göra en bil också. Då måste man kopiera all Motorcykel-kod och modifiera den för att passa ett bilobjekt. Med andra ord blir det mycket repeterad kod, och det är en av det saker man vill undvika för att skriva så lättläst kod som möjligt.

 

Nu förstår du förhoppningsvis lite mer om vilka olika sätt att programmera som finns. I nästa avsnitt (som utkommer 1/10) ska vi börja titta lite på Python och vilka olika programmeringsbegrepp man bör kunna, de olika typerna av värden man kan lagra och använda och vad som händer när man importerar ett bibliotek!

Uppdatering: Nu finns nästa del i introduktionen här!