Programmeringsspråk for nybegynnere Krav til språket Hva om vi laget vårt eget språk til INF1000? Programmeringsspråket må være så enkelt som mulig. (Programmering er vanskelig nok som det er.) Hvilke ønsker ville vi ha? Hva slags språk ville jeg ha laget? Så få begreper som mulig Konsistent bruk av begrepene Ingen unntak fra reglene Krav til språket Krav til språket Språket må være uttrykksfullt nok. Må ha de vanligste begrepene (tilordning, tester, løkker, metoder,... ) Må kunne programmere de vanlige eksemplene fra lærebøkene Dessuten bør et undervisningsspråk ved Ifi kunne kjøre på Mac, Unix og Windows, være lett å installere, være gratis og være objektorientert.
Problem: Tall Problem: Syntax har ca 20 presedensnivåer for operatorer i uttrykk. Det er ikke lett å huske dem: har 6 ulike typer tall programmereren må forholde seg til. (C har 13!) Konklusjon a 1 << b == c & 1 >> d e Noen ganger trenger man allikevel parenteser på odde steder: Én type tall er nok (som på en kalkulator). ((klasse) p).f Konklusjon Enklere syntaks for uttrykk vil være en fordel. Problem: Reserverte navn Problem: Setninger og uttrykk har 53 reserverte ord med syntaktisk betydning. Brukeren kan ikke benytte disse som navn, selv om han eller hun ikke forstår hva de gjør. Konklusjon Språket bør ikke ha reserverte ord. De fleste språk har både setninger og uttrykk, men skillet er ikke alltid klart. I har vi Tilordning er både setning og uttrykk. Det finnes både if setning og if uttrykk; de gjør det samme men syntaksen er ulik: if (test) s else s test? e : e Konklusjon Hvis språket har både uttrykk og setninger, bør skillet være klart.
Problem: Alltid OO I kan man ikke «slå av» OO programmeringen, så enkle eksempler blir unødig kompliserte: class Hello { public static void main (String args[ ]) { System.out.println("Hello,!"); Mitt forslag til undervisningsspråk er i all ubeskjedenhet oppkalt etter Kristen Nygård og Ole Johan Dahl. *.SYS.Out.wln("Hello,!") i i I finnes bare én type struktur: objekter. De fungerer som datatyper prosedyrer og funksjoner klasser og instanser tabeller (tilsvarende HashMap) Point: { x: [1]; y: [2]; Alle objekter har en tabell over hvilke navn som er kjent. Når objektet skapes, starter man med en klon av et annet objekt. inneholder diverse uttrykk som evalueres når objektet dannes. Disse uttrykkene kan registrere navn: navn: uttrykk distance: { px: [1]; #.x. (px.x).^(2).+(#.y. (px.y).^(2)).^(0.5);
«Verdiobjekter» i Vanlige uttrykk Objektene false og true representerer sannhetsverdier «Sub objekter» av *.KNOD.Number inneholder en tallverdi. Vanlige uttrykk ser slik ut: factor suffix * En factor er ett av et tall: 3.14 «Sub objekter» av *.KNOD.Text inneholder en tekst. «Sub objekter» av *.KNOD.List inneholder en liste (normalt indeksert fra 1) en tekst: "Hello!" et navn: navn en liste: [ 1; 1; 2; 3 ] et objekt: { e; e;... Internt og eksternt skop Et suffix er ett av en indeks (i liste eller tekst): [e] en delmengde (i liste eller tekst): [e..e] et navneoppslag:. navn et navneoppslag: { e en objektskapelse: (e,... ) i et objekt kan bare referere til navn registrert der. Alle «globale» objekter står i en struktur som minner om et fil tre: KNOD SYS MyPackage List Number Text In Out * Top object Package objects Other objects The library User objects *.SYS.Out.wln ("Hello!") [1].= ( [2]) Alle objekter opprettes med navnet * som angir toppen. *.SYS.Out.wln("Hello, world!")
Mer spesielle uttrykk Andre spesielle uttrykk Valg Valguttrykkene er inspirert av «guarded statements»: test: uttrykk test: uttrykk?. Yield uttrykk Disse tilsvarer return hos og andre. Løkker Disse bygger også på Dijkstras forslag: uttrykk test: uttrykk test: uttrykk!. Nytt: Repetisjoner Alle uttrykk kan gis et løkkeprefiks: @ uttrykk: uttrykk Effekten avhenger av prefikset: En liste går gjennom elementene i listen. Et tall n går 1, 2,..., n. En tekst går gjennom tegnene i teksten. Klasselignende objekter skrives som objektliteraler: Point: { x: [1]; y: [2]; $; = «return this» men trengs ikke Andre objekter går gjennom navnene registrert der. Nye instanser lages ved å skape nye objekter: Navnet inneholder løkketelleren. origo: Point(0, 0); Resultatet er alltid en liste av uttrykkene beregnet i løkken.
Man kan ha metoder i slike klasser: Når man kaller en slik metode Point: { x: [1]; y: [2]; distance: { px: [1]; #.x. (px.x).^(2).+(#.y. (px.y).^(2)).^(0.5); p.distance(origo) vil man få disse referansene i det nye objektet: $ det nye objektet selv (= this) # konteksten (p) parametrene ([ origo ]) «Sub objekter» 8 dronningproblemet kan importere definisjonene fra andre objekter og slik bli «sub objekter» av dem: Pixel: { < Point > colour: [ 0; 0; 0 ]; class Queen { Queen (int n) { //... void solve (int c) { //... Queen: { n: [1]; solve: { c: [1];... set_colour: { #.colour: public static void main (String arg[]) { Queen q = new Queen(Integer.parseInt(arg[0])); q.solve(1); q: Queen( [1].num()); q.solve(1);
Inni klassen Queen finnes klassen Board: class Board { int col[] = new int[n+1]; boolean less (Board x) { for (int i = 1; i < n; ++i) if (col[i]!= x.col[i]) return col[i]<x.col[i]; return false; Board: { col: [ ]; <: { xcol: [1].col; @ #.#.n: #.col[ ].<(xcol[ ]): true; #.col[ ].>(xcol[ ]): false;?; false; boolean legal (int c, int r) { for (int cx = 1; cx < c; ++cx) { if (col[cx] == r) return false; if (cx c == r col[cx]) return false; if (c cx == r col[cx]) return false; return true; Board rot90 () { Board res = new Board(); for (int cx = 1; cx <= n; ++cx) res.col[col[cx]] = n cx+1; return res; legal: { c: [1]; r: [2]; @ c. (): #.col[ ].=(r): false;. (c).=(r. (#.col[ ])): false; c. ( ).=(r. (#.col[ ])): false;?; true; rot90: { res: #.#.Board(); @ #.#.n: res.col[#.col[ ]]: #.#.n. (, 1); res; void solve (int c) { if (c == 1) { int nhalf = (n+1)/2; for (int rx = 1; rx <= nhalf; ++rx) { b.col[1] = rx; solve(2); else if (c <= n) { for (int rx = 1; rx <= n; ++rx) if (b.legal(c,rx)) { b.col[c] = rx; solve(c+1); else { Board r90 = b.rot90(); if (r90.less(b)) return; Board r180 = r90.rot90(); if (r180.less(b)) return; Board r270 = r180.rot90(); if (r270.less(b)) return; if (b.mirrorver().less(b)) return; if (b.mirrordia1().less(b)) return; if (b.mirrordia2().less(b)) return; System.out.println(); System.out.println("Solution no "+(++nsolutions)); b.print(); solve: { c: [1]; c.=(1): @ #.n. (2).ceiling(): [ #.b.col[1]: ; #.solve(2) ]; c.<=(#.n): @ #.n: #.b.legal(c, ): #.b.col[c]: ; #.solve(c.++())?; true: r90: #.b.rot90(); r90.<(#.b): $?; r180: r90.rot90(); r180.<(#.b): $?; r270: r180.rot90(); r270.<(#.b): $?; #.b.mirror_ver().<(#.b).or( #.b.mirror_dia_1().<(#.b), #.b.mirror_dia_2().<(#.b)): $?; *.SYS.Out.wln(); *.SYS.Out.wln("Solution no ", #.n_solutions. ++()); #.b.print();?;
Hva er vellykket i? Har noen ulemper? Etter min mening er enkelt nok, dog kraftig nok til formålet; OO modellen lett å forklare og forstå (og tillater multippel arv!); meget fleksibelt og er svært dynamisk, så typefeil oppdages ikke før under kjøring. brukes ikke andre steder. skrevet i så greit å installere på alle systemer. Hva er ikke gode innvendinger mot? programmer er langsomme Ingen form for beskyttelse. Ingen parallellitet. Foreløbig(?) ingen støtte for GUI. Etter min mening hører ikke dette hjemme i et introduksjonskurs. Andre ting: Prosessortid for 8 dronningproblemet: Execution time (sec) 1000 100 10 Etter begynnerkurset må man lære andre språk enn. 1 er ikke spesielt raskt. 6 8 10 12 14 # queens Jeg mener dette er godt nok til nybegynnerprogrammer.
i dag Hva vil skje med i fremtiden? Språket er ferdig designet. Det eksisterer enβ versjon av referanseimplementasjonen i. Jeg kommer til å bruke det en del selv. Sannsynligvis intet annet!