Hejlsberg: Fusionskode er fremtiden

De almindelige objektorienterede koncepter skal fornys med funktionsprogrammering og SQL-agtige forespørgsler. Det er Anders Hejlsbergs bud på den kommende version 3 af C#.

»Hvis man ser, hvad der sker rent geopolitisk med programmeringssprog, så peger tendensen i øjeblikket på en fusion af alle de forskellige arter: Klassisk, objektorienteret, funktionsprogrammering og dynamiske sprog, og den bølge prøver vi selvfølgelig at være med på hos Microsoft.«

Det siger Anders Hejlsberg, som er Microsofts hovedarkitekt bag C#, efter en lang karriere som blandt andet har omfattet succes-sprogene Turbo Pascal og Delphi.

Men er det en god ide at fusionere forskellige programmeringsparadigmer?

»Ja, det synes jeg helt bestemt,« siger Hejlsberg i et interview i det kommende nummer af magasinet Version2.

»Der er jo forsket meget i funktionelle programmeringssprog, og der er utroligt meget, der kan bruges i almindelige problemstillinger i forretningsverdenen i dag.«

Læs hele interviewet med Anders Hejlsberg i Version2, som kommer på gaden fredag den 1. december.

Tips og korrekturforslag til denne historie sendes til tip@version2.dk
Følg forløbet
Kommentarer (26)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
Hans Schou

Ja det er fint med C++ (eller rettere objekter), men som der også står i starten (SQL-agtige forespørgsler), så er det vigtigt at data bliver en mere integreret del af hele systemet, så vi ikke bare tænker "kode her og data der". Det skal hænge bedre sammen. På en sådan mere ++ agtig måde.

Det kunne man godt ønske sig.

Det giver nok også en hel del ulemper, men forhåbentlig så mange fordele at det er ganske udbredt om 10 år. (eller 20 - det tager altid lang tid)

/hans

  • 0
  • 0
Jens Madsen

Bærer det her ikke præg af, at man vil undgå forskning? Der skal ikke nye algorithmer, og metoder til, for at "fusionere" sprog. Du tager noget fra et sprog (et modul), måske allerede skrevet i C++, og tilføjer et nyt? Det er nemt, billigt, og behøver ingen forskning i metoder, og algorithmer. Fusionskode, er billigst - men er det fremtiden?

Jeg mener ikke, at det er fremtiden. Fremtiden, er baseret på forskning. Den er ikke baseret på at fussionere kode.

Forskning i algorithmer, gør at sprogene bliver mere intelligente. Se på, hvilke problemer der er, med nuværende sprog - og løs dem. I stedet for, at "bare" slå flere programbiblioteker sammen, og tro det løser problemet.

a) Eventdrevet programmering. Et typisk problem: Vi ser, at programmørerne "glemmer" at fyre en notifikation/trigger af sted. Ofte, kan det være at fejlene ikke opdages, fordi notifikationen sendes af sted senere. Men, ikke korrekt. Hvordan udvikles sprog, således disse problemer ikke findes, og så det er nemmere at håndtere?

b) OOP er på en måde forældet håbløst. Det er forståelsesmæssigt "interrupt trigget". Du kalder en funktion i et objekt, som kan sammenlignes med, at sende data med et interrupt. Hvis du har et objekt, der som resultat skal aktivere tre nye objekte, så vil du typisk sige "kald objekt 1", "kald objekt 2", og "kald objekt 3". Dette forstås hermed typisk i rækkefølge. Og, det er ikke egnet for, at sproget kan udføre dette parallelt. I nogen tilfælde, kan du analysere dig til det - men det leder ikke programmøren til at tænke i parallele baner. Derfor, er sproget ikke egnet til større projekter.

c) Lær, af gamle sprog, som VHDL. På mange måder, kan VHDL meget, som er lidt specielt. Du beskriver alt, som processer, der eventuelt aktiveres af signaler (events). Og alt, betragtes som parallele rutiner. Du kan have millioner, eller milliarder af parallele rutiner, uden det tvinger sproget i knæ. Enhver gate, i VHDL, er reelt en parallel process. Og dem kan der nemt være millioner, og milliarder af, i moderne designs. Ikke noget med, at gå ned ved mere end 7 parallele processer.

d) Tænk på fejl. Hvad fører til fejl i sprog? Typisk, vil du se, at fejl er ikke deteterministiske. Man ser ofte "beta software", benævnt som "endnu ikke stabil" program. Hvordan opstår ikke stabilitet? Du skal sikre dig, når du udvikler et sprog, at det er deterministisk, og at det er tydeligt i koden, hvor ikke determinisme opstår. Du skal sikre dig, at tilfældighed er forbudt, for programmører. Og, kun hvis det tillades på et overordnet niveau kan det eventuelt for nogle blokke eller metoder accepteres.

e) Det er meget vigtigt, at opnå "logik" i sproget. Prøv at analysere hvor "ulogisk" sprog som C++ er. Hvis du sidder med kode, og der indgår arrays, og disse laves om, fra at bruge statiske arrays, til at bruge dynamiske arrays, så vil du opdage f.eks. sizeof returnerer med forkert værdi - hvor den ved statiske arrays returnerer med størrelsen af arrayet, vil den når du ændrer det systematisk til pointere, returnere med størrelsen af en pointer. Her, findes ikke et sådant problem i Pascal, og det er et logisk sprog. Typen, af "fejl" i sprog, som dette, giver også anledning til problemer i software. Ideelt, bør brug af statiske variable, og dynamiske variable være ens. Det betyder, at du ikke bør have alle disse pointer tegn rundt i koden - de bør faktisk ikke eksistere. I stedet, skal du angive at variablen, er en pointer, under erklæringen. Og så er det "gjort for altid". Nu kan du så tildele addressen en værdi. På den måde, opnås at koden er ens, uanset om det er statisk eller dynamisk. Det svarer til brug af refferencer, men hvor du kan tildele dem en værdi. Har du ikke tildelt en pointer en værdi, kan du eventuelt lave automatisk new. Men, det væsentlige er, at analysere, om dette føre til programmeringsfejl, og det har vist sig, at det bedste er at indføre to "typer" af pointere, som henholdsvis bruges til at "holde" variable og deres værdier, men ikke kan bruges som pointer, og andre, som bruges som pointere, men ikke kan holde værdi. Den slags ting, er nyttigt at vide, når man udvikler et sprog, da man ellers ikke kan udvikle et sprog, som fører til en mindre rate af software fejl. Specielt har vist sig, at brugen af dynamiske variable fører til fejl, når de implementeres forkert, og det er gjort i alle "moderne" sprog.

f) For at et sprog er deterministisk, er det også vigtigt, at du ikke kan bruge ikke initialiserede variable, eller pointere. Sproget skal gøre, eksakt hvad du skriver, og må ikke tage et vilkårligt valg.

g) Det er vigtigt, at et sprog, ikke afspejler hardwaren. Du må ikke have konstruktioner, som skal ændres, fordi computeren får "flere bits", eller "bedre CPU". I så fald, er det ganske simpelt ikke et "høj niveau sprog". C++ er som eksempel ikke et højniveau sprog, men lavnivau sprog, der er låst fast til computerens akitektur og CPU. Du kan ikke flytte et C++ sprog, mellem platforme - så vil det typisk ikke fungere. Du vil opdage, at hvis du "forsker" lidt i, hvad dette fører med sig, så vil opnås sprog, der er langt bedre og giver mindre fejl, også selvom det bruges på samme platform. Som eksempel forhindrer det brug hvor du "placerer" bits ovenpå andre, og bruger disse, og hvor betydningen besluttes af underliggende hardware. Det er altid bedst, at ikke give adgang til det underliggende lag, f.eks. at selve det interne format af float ikke er defineret i sproget specifikation. For det giver hardware ingeniørerne større mulighed for frihed, at kunne bestemme det selv. Derfor, må den slags indformation, ikke være forud defineret for et sprog. Det gør den også mindre fleksibel, at du ikke kan angive præcision for dine beregninger, så compileren kan tilpasse det din hardware.

Det at fussionere sprog, svarer mest til, at blot gøre C++ bibliotektet større. Det er en sølle måde, at lave nye sprog. Og, det er vel egentligt ikke at betragte, som nogen sprogmæssig gevindst.

Fussionssprog, er ikke sprogforskning, men blot sammenkopiering af eksisterende rutiner. Det burde ikke have nogen fremtid.

  • 0
  • 0
Karsten Nyblad

Jens, du skriver at sproget ikke bør definere floatingpoint formater. Der kommer du en på et problem, som ikke har nogen rigtig god løsning. Hvis sproget ikke har floatingpoint formater defineret, kan programmører ikke ikke vide, om de får et floatingpoint format, med en tilstrækkelig præcission til at løse deres problem. De kan heller ikke vide om de render ind i problemer med over- eller underflow, pga at floatingpointformatet ikke kan håndtere store og små nok eksponenter.

Jamen lad os så gøre som i Ada, og lade brugeren selv definere, hvor store eksponenter og hvor lang mantisse der er brug for. Så render du ind i det problem, at en algoritme der virker stabilt på en platform, fejler på en anden, fordi programmøren har undervurderet kravene til floatingpointformatet - eller disse har ændret sig siden koden blev skrevet - eller at koden virker ved nogen implementeringer af floatingpoints men ikke andre.

Jeg tror, vi må til at erkende, at floatingpoint altid vil være et problem. De er og bliver kun en dårlig tilnærmelse til matematikkens reelle tal. De kan ikke en gang håndtere rationelle tal korrekt, og lige meget hvad vi gør, kan vi ikke skjule det problem.

Så har du nogle kommentatrer om at programmer ikke skal ændre betyding, bare fordi koden bliver flyttet til en platform med flere bits. Igen render du ind i problemer. Folk flytter til 64-bit for at få adgang til mere hovedlager, men er man i pladsproblemer er det naturligt at lave en version af programmet til 32-bit computere, som bruger mindre variable, samtidigt med at man har en version af programmet, der kan udnytte alt det hovedlager, der er på den store maskine.

Spørgsmålet er, om man ikke i stedet skal gøre mere for at folk bedre kan vælge præcis den datatype, de har brug for til et givent formål, samtidigt med at compileren tjekker, at programmøren gør det konsekvent. I sprog som C kan du definere nye integer typer, men compilerne gør intet for at sikre, at du ikke lægger æbler og pærer sammen eller at du pludseligt gemmer et kronebeløb i en tæller af frugt. I Ada kan man definere forskellige integer typer, f.eks. en til frugt og en til beløb, og så kan man ikke lægge frugt til et beløb, men man kunne tage det skridtet videre, og lade compileren regne på typer. Hvis man vil dividere en afstand med en hastighed, ved vi mennesker udemærket, at hastigheden er i m/s og afstanden er i meter, og at resultatet derfor er i sekunder. Det skulle ikke være svært at lave et sprog, der kan det samme beregning af typer.

Endelig så er det kun muligt at lave 100% uafhængighed af de underliggende heltalsformater, hvis man implementerer heltal uden øvre og nedre grænser. Tro ikke at bare fordi vi har fået 64-bit, kan vi håndtere alle de heltal, der forekommer i praktiske situationer. I regnskabssystemer er det almindeligt at gemme beløb i ører, cent, eller hvad nu den mindste enhed hedder i den pågældende møntsort. Skal vi nu veksle et stort beløb fra en møntsort til en anden, vil man først gange vekselkursen med en stor tier-potens til at kursen er et heltal. Derefter ganger man vekselkursen med beløbet og dividere med tierpotensen igen. Hvis vi kalder beløbet for b, vekselkursen for v og tierpotensen for t, udregner vi altså (b(vt))/t. Problemet er, at b(vt) ofte vil være for stor til at være i 64-bit. Det er ikke bare kursberegninger, der kan give problemer. De kan også opstå i forbindelse med renteberegninger. Det her problem kan du reelt kun løse ved at gå over til heltal uden øvre og nedre grænser, men det vil have en høj pris på effektiviteten.

  • 0
  • 0
Simon Holm

Jeg bliver nødt til at spørge Jens, du er vel klar over C# adskiller sig væsentlig fra C++ og at mange af de udvidelser der kommer med i version 3 absolut ikke blot kan kaldes sammenkopiering af eksisterende rutiner?

"Fusionskode" skal forståes som et mix mellem de klassiske producerale og objektorienterede paradignmer der præger eksisterende populære programmeringssprog og andre som fx det funktionelle paradigme. Der er forsket rigtigt meget i funktionelle sprog da de på mange måder er elegante, men også har sine store svagheder på andre punkter. I udviklingen af C# har de netop brugt resultater fra den forskning og kan derfor tilbyde statisk typestærke anonyme lambda udtryk.

Hvad det mere konkret betyder er at SQL-lignende syntax kan anvendes direkte i koden, med typesikkerhed vel og mærke (det kræver selvfølgelig man har en stub der afspejler sit database layout, men det kan let autogenereres).

C# version 3 kunne naturligvis løse endnu flere problemer end det gør, men at gøre tilgang af data til en førstehåndsegenskab i sproget er absolut en rigtig god ting.

I øvrigt er de tre vigtigste designmål for programmeringssprog bagudkompabilitet, bagudkompabilitet og features. (I styresystemer er det tre gange bagudkompabilitet).

  • 0
  • 0
Troels Arvin

Uden at have arbejdet med embedded SQL i C++:

Kan man ikke sige, at embedded SQL allerede opfylder ønsket om at kunne foretage SQL-forespørgsler direkte i programmeringssproget?

Eller er embedded SQL i praksis dødt?

  • 0
  • 0
Simon Holm

Nu kender jeg ikke til embedded SQL, men fandt og kiggede lidt på embedded SQL til IBM's DB2[1]. Det ser ud til at fungere ved at et database specifikt værktøj (her til DB2) præprocesserer dine kodefiler og blandt andet kan afgøre typerne på statiske forespørgsler. Dette virker meget platformsbundet, selv om der er i princippet ikke noget i vejen for at et standardiseret værktøj til sagen, men jeg tvivler på det findes. Omvendt virker det i C# version 3 for SQL-databaser generelt, XML-filer og mange flere "backends", på en elegant vis (for det mest synlige af dets vedkommende) ved hjælp af typestærke anonyme lambda udtryk og stubs af data-baselayoutet. Så selv om det også ser ud som om embedded SQL opfylder en del af integrationen gør C# det i hvert fald langt bedre.

[1] http://publib.boulder.ibm.com/infocenter/db2luw/v9/topic/com.ibm.db2.udb...

  • 0
  • 0
Jens Madsen

Vedr. floating point problemet: Når du definere en float, bliver du nød til, at angive præcisionen (f.eks. antal bits for mantisse), samt interval. Dermed er ikke et stort problem. Hvis vi ønsker "float" skal være uendelig nøjagtig, har vi selvfølgeligt et problem, og det er uløseligt. Netop derfor fungere begrebet float ikke, uden der angives præcision og interval. At bare skrive "float" som i C og C++ giver reelt ikke indhold nok til løsning af opgaven, og defineres en float nøjagtighed i sprogets ansi standard, begrænser sproget muligheden for hardwaren forbedres uden software skal omskrives. Når du har angivet præcision og interval i kode, er problemet eksakt beskrevet for dit problem og uafhængig af underliggende hardware. Jeg så også gerne, at der kunne indføres en type, som holder styr på nøjagtigheden. Vi ser ofte, at nøjagtigheden går fløjten, uden nogen bemærker det. Og pludseligt står vi med utrolige beviser, der skyldes afrundingsfejlene. Computeren kan godt, holde styr på, hvor stor fejl der er på beregningen, og tage hensyn til de afrundingsfejl der er undervejs i beregningen, og den bør gøre det. Dermed håber jeg sandeligt også, at dit problem med algorithmer er løst - ellers er implementeringen en sand hån mod den numeriske matematik og datalogien. Udregnes nøjagtigheden af resultatet, skal denne nøjagtighed altid være opfyldt. Normalt bør ikke være store problemer med algoritmerne. Det er rimeligt veldefineret, hvordan de skal fungere. Udfører du (A operation B), så skal du i princippet udregne med nogen ekstra "bits" og afrunde, ellers er resultatet forkert, og ikke indenfor den pågældende nøjagtighed. Compileren burde nægte at oversætte, fordi resultattypen har for stor nøjagtighed, end operandtyperne muliggør. Det burde den kunne afgøre. Endeligt, indeholder matematiske - og specielt fysiske udregninger - ofte enheder. Dette svarer desvære ikke til type begrebet i højniveau programmeringssprog, og der laves ikke et reelt enhedstjek. Atter, en stor mangel for programmeringssprog, med hensyn til sproget sikkerhed. Enheder, går videre, end kun den fysiske verden, og når vi bliver vandt til det, kan vi ofte skrive enheder på "alt".

Jeg syntes ikke om begrebet "integer" i C+, eller "int" i C++. Atter har det samme fejl som float: Det definerer en uendelig antal bits som er ubeskrivelig i forbindelse med data. Atter løses problemet ikke godt, ved at definere nøjagtigheden i en ansi defination. Det er en forkert måde, at gøre det, og det er ikke fleksibel nok. Pludseligt, laves computere med 128 bits databredde for integer, og endnu er 128 bits, ikke implementeret som en type int i C++. Da vi lærte programmeringssprog i sin tid, var integer forbudt - det var "før" C. Sproget var pascal. Og integer, var ikke "rigtig" pascal. I pascal, skulle du angive intervallet f.eks.
int = -32768..32767 - og jeg mener vi endog fik et minus, hvis vi brugte "integer".

I mange pascal compilere, lå "desvære" typen integer prædefineret. Men, det var ikke "rigtigt" pascal, og klart ikke datalogi. I datalogi, skulle størrelse deffineres.

Jeg har samme opfattelse, som vores lærer: I datalogi, bør man ikke have en "magisk" type, med en given præcision, eller som går fra et sjovt negativ tal, til et morsomt valgt positivt tal.

Hvis vi ønsker integer, angiver vi det som integer = -32767..32767 og så er størrelsesområdet defineret. Har vi brug for flere tal, kan angives større interval, så stor vi ønsker. Et programmeringssprog, skal være abstrakt, og må ikke have nogen "indbyggede natur konstanter" der lægger begrænsninger på sproget.

Når du arbejder med pointere, skal det i højnivau sprog være "abstrakt". Det må ikke være defineret til, at optage 4 bytes i lageret. Vi kender ikke størrelsen på vores datatyper. I princippet, har vi adgang til hele Internettet, som addresseringsområde. Der er ikke nogen bits og bytes. Dog, kan måske være begrænset, hvor mange bytes du kan få lov at gemme på harddisken, og hvor mange bytes filer du kan have åben samtidig.
Her bør programmet fortælle, hvor store krav den har, og så er det op til computerens operativsystem at undersøge, om de pågældende krav til harddisk, og samtlige åbne filer, kan opfyldes af operativsystem og af computerens hardware og operativsystemsoftware. Egentligt, bør en "simulator" i hardwaren helst muliggøre alt, men desvære kan man ofte ikke tillade brug af uendeligt lagerplads, hverken på harddisk, på Internet, eller eventuelt i hukommelsen, og så må brugeren forklare hvor store krav man ønsker at stille, og softwaren forklare på forhånd, hvor store der er behov for, så programmer nægtes at blive indstalleret, eller bruge større resourcer, end de beder om ved indstallation.

Med hensyn til fusionskode, og C#: Af artiklen, forstod jeg "fusionskode" som sammensmeltning af egenskaber fra f.eks. SQL og normale programmeringssprog - ikke som den teoretiske baggrund for, at en implementering af SQL i et C# var muligt.

Desvære mener jeg ikke (mere), at det sidste er så vigtigt, indenfor sprogforskning. For mange år siden, var det netop noget, som var til stor irritation for mig, at man ikke kunne implementere f.eks. et bibliotek, der muliggjorde en del af koden kunne være Basic, Java, eller Pascal, midt i C++ koden. Da jeg spurgte læren, fik jeg imidlertid et "godt" svar, der gjorde jeg hoppede lidt fra idéen. Han mente, at hvis sproget blev gjort så fleksibelt, at dette var muligt, så vil det ødelægge sprogets grænser og karakteristik. Vi vil ikke have C++ mere. Han mente, at det var lidt som define i C, og at det jo var muligt, at så implementere hvad som helst, hvilket kunne blive et problem for sikkerhed. Sproget, kunne nemt gøres uoverskuelig. Et sprog, skulle have et udseende. Selvom idéen netop var, at det skulle gøres udfra typer, og at det dermed ikke var ødelæggende, så fik han mig overbevist om, at fleksibiliteten kunne ses som ulempe.

Vi kan tage eksemplet, hvor du tillader omprogrammering af en I/O port, så den kalder noget kode, der snuser op det som sendes ud. På samme måde, kunne man frygte, at de indbyggede og normale komandoer, blev totalt omdeffineret, og fik ny mening. Det vil kunne skabe uoverskuelige bagdøre, som gjorde sproget ikke var ordentligt defineret.

Ialt, var resultatet, at jeg blev overbevist om, at "idéen" med at kunne implementere alt, og integrere et andet sprog, i sproget, var dårligt sikkerhedsmæssigt. Og, at det derfor ikke havde nogen stor fremtid.

I dag, betragter jeg sikkerheden for et sprog, som værende det bærende element. Det, som man skal satse på, er at undersøge, hvordan fejl undgås. Og, software skal være uden fejl, og uden problemer.

Alligevel, har jeg stadigt facination, af muligheden for at "implementere alt", i et sprog, så man bare kan lave sin egen defination af et sprog, i sproget, og implementere dette. Men, desvære er jeg ikke mere overbevist om, at sikkerheden er i orden. Det kan dog være et sjovt lille værktøj, som måske kan bruges ved udvikling af sprog.

Det vi skal nå frem tid, er vigtigheden af færre programmeringsfejl for fremtiden.

I dag, er oversætter blevet så frygtelige, at de oversætter selv simple programmer, til meget kompleks kode. Og det fylder halve megabytes, for selv ganske simple programmer. Det er helt uoverskueligt, at gennemskue en sådan oversættelse, og det vil ikke være muligt, at udfra en assembler output, at gennemskue om compileren gør det som den skal. Også dette, er et stort problem, for sikkerheden. I mange sammenhænge, er det hensigtsmæssigt med noget simpelt, som giver kode, du kan verificere manuelt, indeholder det samme som det du har kodet. Biblioteker, der giver kode på mange megabytes, bør kunne "optimeres bort", så så lidt som muligt, er med i koden, og dermed at sproget bliver overskuelig. Her er måske også et vigtigt aspekt, indenfor sprog udvikling. Selv meget komplekste biblioteker, bør ikke kunne føre til, at sprogets oversættelse bliver kompleks, hvis det ikke er nødvendig for opgaven. For det går ud over sikkerheden. Risikoen for, at programmører har indbygget fejl - enten med vilje, eller ved uheld - er sandsynlig. Og det er sandsynligt, at fejlen ikke opdages i tide. Det er forholdsvis simpelt, at udvikle koder der indeholder fejl, som "går af", under bestemte forudsætninger, eller på et tidspunkt i fremtiden. Det vil kunne føre til samfundets totale kolaps. Selvom mange stærke kræfter, finansere dette, så er det noget som et godt sprog, bør arbejde på, at forhindre. Det er jo ikke ønskeligt, hvis den økonomiske tankegang, reelt lægger verden i grus, fordi pengene og viljen findes.

  • 0
  • 0
Jens Madsen

Du skriver, at der er forskelle på floating point algoritmer, og deres resultat. Det kan jeg godt bekræfte: Det er fejl, i de fleste.

Da jeg lærte fysik, i gymnasiet, havde jeg fået et stort tydeligt minus, hvis jeg regnede floating point som computeren. Læren sagde, at nøjagtighed for floating point, hørte desvære under fysik, og var ikke noget vi lærete i matematik undervisningen - og derfor fik vi en række lektioner, i behandling af flydende tal beregninger, og nøjagtighed.

Det var meget vigtigt, at ikke angive flere "bits" nøjagtighed, eller decimalers nøjagtighed, end man reelt havde fysisk. Lavede vi beregninger, var det en større fejl, at skrive 7.3 end at skrive 7 hvis resultatet var 7.1 eller 7.0. Årsagen, var at vi havde angivet flere decimaler, end lovligt. Forestil dig, at en fysikker har målt lysets hastighed, og herunder lavet nogen udregninger, på grund af målemetoden - og nu har han altså fået 2 ekstra cifre, som ikke fandtes før. Imidlertid, er de sidste 4 cifre forkerte. Det er jo naturligvis ulovligt. Aldrig, angiv større præcission, end du kan stå inde for. Naturligvis må mellemudregninger have større præcision, men KUN hvis du tager hensyn til dette, og udregner nøjagtigheden. Herefter, angives resultatet, med det antal cifre, som der er korrekt, eller nøjagtigheden står anført.

I computersammenhænge, er antal cifre lig nøjagtighed. Altså, de er repræsenteret ved exponenten. Ønsker du nøjagtigheden, for et ciffer, bruger du reelt eksponenten, og dertil lægger antallet af bits, som mantissen er på, med mindre eksponenten er forskudt, og direkte angiver nøjagtighed.

Det betyder, at når du summerer, og trækker fra, så angives resultatet med den største eksponent af de forekommende, og ved addition, må eksponenten aldrig sættes ned. Årsagen er, at dette er videnskabeligt svindel, og svarer til at tilføje ekstra nøjagtighed. Eksponenten, er jo den, som angiver nøjagtighed.

På computeren, prøvede jeg at udføre de sædvanlige udregninger:
1 + 1 = 2.
Herfra blev trukken 2. Resultatet, var 0.
Imidlertid, så kan dette nul, ikke angives med flere betydende bits, end 2 tallet blev opgivet med. Og det betyder, at computeren angav tallet forkert - for blev der lagt 2E-100 til dette 0, gav det 2E-100. Det er svindel.

Såvel lommeregneren, i Windows, som programmeringssproget, indeholdt således videnskabeligt svindel i dens udregning, fordi den gjorde tallet mere nøjagtigt end det var. Den satte eksponenten ned, ved subtraktion. Det er ulovligt, og vi havde ikke bestået gymnasiets fysikundervisning, hvis vi havde gjort noget tilsvarende. Det svarer fuldkommen til, at angive for mange cifre for lysets hastighed, og flere end man har.

Indenfor computerbranchen, er svindel og fup, desvære ekstremt udbredt.

  • 0
  • 0
Jens Madsen

Jeg skrev:
og ved addition, må eksponenten aldrig sættes ned

Det skulle naturligvis stå
og ved addition, og subtraktion, må eksponenten aldrig sættes ned. (eksponenten er lig tallets nøjagtighed)

Netop dette, er fejlen i mange floating point algoritmer - ved subtraktion, hvor de øverste bit er "nul", øges opløsningen ved eksponenten sættes ned, og dette giver videnskabeligt fup. Samtidigt gør det endvidere hardwaren mere kompleks, at den udvikles til denne form for svindel.

Du kan relativ nemt se, om din computer er udstyret med en sådan fejlbehæftet hardware eller software. Trækkes to ens to store tal fra hinanden, er dette resultat ikke et nul, med samme nøjagtighed, som når der skrives "0". Og derfor, vil summering med et lille tal, stadigt give 0. Hvis du undersøger eksponenten, får du nøjagtighed. Og det findes der en funktion til, hvis det er et godt sprog.

  • 0
  • 0
Rasmus Kaae

Personligt kan jeg ikke se problemet med floats, ints og doubles som andet end en teorektisk fikumdik. I praksis virker den teknik glimrende for almindelige applikationer, der findes naturligvis applikationer der behøver finere grannularitet på datatyperne (hej mars rover) men den type applikationer hører i en gruppe for sig.

Blandt JM's utallige indlæg er der et par ord jeg undrer mig over. Hvad er din udlægning af forskning og hvorfor er det overhovedet relevant for diskussionen? I første omgang mener du ikke det er forskning når man undersøger elementer i forbindelse med fusioneringer af programmeringssprog og programemrings-paradigmer. Samtidig opfordrer JM til at man "forsker" i en meget specifik problemstilling, som jeg personligt ikke kan se har nogen relevans da da ens C++ program's porterbarhed blot er en parameter der skal vægtes når man skriver kode og designer arkitektur.

Summasumarum på det hele er formentlig at der for tiden FORSKES i nye anvendelses muligheder af eksisterende teknologier og teknikker. Denne forskning ser jeg som yderst relevant og faktisk meget interessant. Én af de ting jeg synes er mest interessant er at man kan mixe forskellige programmeringsparadigmer vha. templates og generics i C++ og Java (og jeg kender ikke til C# og evt. andre sprog der har samme kvaliteter).

  • 0
  • 0
Karsten Nyblad

Jens, jeg mener, du er i gang med at gøre som Marianne Jelved: Holde fanen så højt at fødderne ikke når jorden. Tricks som at lære de studerende ikke at bruge integer kan være meget gode til at lære folk svaghederne ved computere, men programmeringssprog skal fungere i en verden, hvor mange programmerer uden at have mere end korte kurser i kunsten bag sig. Det hjælper ikke, at at bede en ingeniør eller fysikker om at lave teoretiske udregninger af om de numeriske beregninger holder. Han vil i de fleste tilfælde svare dig, at han ikke ved, hvordan han skal gøre, og at han chef vil have resultatet i går.

Den normale måde at løse et nummerisk problem på, er at finde et bibliotek af kode, der implementerer en algoritme, som løser den klasser af problemer. Jo, fysikeren og ingeniøren kan sagtens finde den videnskabelige artikel frem, der beskriver algoritmen, men tiden er ikke til det.

Angående udvidbare sprog: Der er ikke ret mange ideer, der er nye, og man har selvfølgelig også forsøgt sig med udvidbare sprog. Erfaringerne er ikke gode. Det er ikke til at vedligeholde kode, når man aldrig ved, om en konstruktion betyder dit eller dat. Programmørerne bliver tvunget til, hele tiden at kigge efter om det ene eller det andet er tilfældet, kun for at opdage, at grunden til at de ikke kunne finde fejlen, er, at der hvor de troede, konstruktionen betyd dat, betød den i virkelighed dit.

  • 0
  • 0
Karsten Nyblad

Problemerne omkring forskellige floating point og heltals formater er særdeles reele, hvis du ønsker at skrive kode, der kan flyttes fra en platform til en anden, ja selv indenfor samme platform kan sådan noget som at skifte compiler give problemer.

Tager vi f.eks. C og C++, kan man aldrig være sikker på, om en long er 32 eller 64 bit, om long long er implementeret, er long double 10 eller 16 bytes, osv. I praksis bliver man nødt til at lave en header file, hvor man definere sine egne typer. Jamen så skulle problemet vel være løst? Ja, hvis programmører kunne finde ud af at bruge typer konsekvent og aldrig lavede fejl med at bruge den gale type. Oven i det er der nogle ubehagelige egenskaber ved C og C++. Hvad er der f.eks. galt med den følgende kode?

int a;
double b = (float)a;

Eller med:

int a, b;
long c = a*b;

  • 0
  • 0
Karsten Nyblad

Jens, jeg glemte at skrive, at jeg synes, de nuværende platforme gør det alt for svært at skrive programmer i flere forskellige sprog. De arme programmører skal forstå alt for meget af den underliggende implementering af programmereingssprogene for at kunne kalde rotiner skrevet i et sprog fra et andet. Det burde være muligt at lave omgivelser, så man bare skulle fortælle, hvilket sprog en given routine var skrevet i, og så fandt compiler og linker selv ud af resten.

  • 0
  • 0
Rasmus Kaae

Jeg kan endnu ikke forstå din bekymring for datatyper. Hvis man skriver programmer der afhænger af bestemte datatypers størrelser, så har man taget en designbeslutning som medfører en straf i porterbarhed. Det er ganske enkelt et spørgsmål om valg. Hvis man vil lave programmer der er uafhængige af den underliggende PC's arkitektur, så må man naturligvis tage sine forbehold (altså vægte porterbarhed højere end f.eks. hastighed). Jeg ser det faktisk som en styrke i f.eks. C og C++ at datatyperne er bundne til en given maskine, det betyder at man har mulighed for at udnytte systemet maksimalt. Ville det måske være rart om C++ definerede datatyper til at være 8/16/32/64 bit hvis koden skulle køres på en 7-bits maskine?

  • 0
  • 0
Jens Madsen

Indrømmet: Der forskes i meget, jeg ikke opfatter som "rigtig forskning". Her, mente jeg ikke andet, end det var meget letkøbt, at implementere et sprog (sql), i et andet, og påstå det skulle være fremtiden. Hvis problemet løses generalt, mener jeg dog det er forskning, fordi andre sprog (pascal, VHDL, og basic, assembler) og ethvert andet sprog, dermed kan implementeres. Men først, og kun, hvis ethvert sprog kan implementeres som "metode", betragter jeg det som godt nok. Du nævner forskning i "anvendelse" - og ganske korrekt nævner du dermed noget, som kan betvivles om er på høj forskningsmæssig niveau. Med hensyn til udvidbar kode, er jeg helt enig med dig i dets problemer. I nogen grad, skal man passe på, at tilsvarende problemer ikke opstår i sprog som C og C++. Der kan være mange biblioteker der "importeres" uden nogen reelt ved, hvad disse gør "ved sproget". Hvor mange læser reelt koden igennem, og ser hvad den gør? Jeg tror ikke mange, har læst selv de faste C++ biblioteker, der følger med sproget som standard. Alle importerer, uden at vide hvad de gør.

Med hensyn til hvor mange bytes en long er - så er det ligegyldigt, hvis det er et godt sprog. Problemet med C++, er at det er maskinkode. Det betyder, at det er maskin og akitektur specifik. Du kan ikke skifte platform, til anden bitbredde. Sproget er ikke højniveausprog.

Det er intet problem, at definere et sprog, der ikke har disse problemer. Og hellerikke problem, at lave compilere der fungerer, med disse definationer. Du kan i princippet have nogen grænser, som f.eks. computerens maksimum lager, og harddisk, der sætter nogen fysiske grænser for hvor mange bytes åbne filer der må være, og som allokeres ram plads, men i praksis, giver det ikke et problem for kompatibiliteten, da det vil fungere på enhver computer, der er stor nok. Og, det giver ikke anledning till at programmet kan aflæse brugerens computers hardware specifikation, fordi brugeren selv angiver den plads, og ram, han mener programmet har lov at bruge, samt at programmet aldrig får lov at køre, hvis ikke der er nok ram og harddisk, og cpu, som den specificerer. Til gengæld, kører den altid, med disse krav.

I browsere, angives sproget, så det reelt er muligt at "mikse" sprog der. Men, ellers burde være bedre mulighed for at blande kode. Det er ingen grund til, at en god programmør i et sprog, skal til at lære et nyt sprog. Og, egentligt, burde alle compilere kunne "importere" andre sprog, og oversætte dem.

Med hensyn til datastrukturer, må du aldrig få kendskab til bytes fra koden, med mindre den størrelse du får er "fiktiv". Typisk, er det mere interessant, at måle ting som "antal elementer".

Lad os tage et sprog, hvor New ikke er defineret. I stedet, laves new automatisk, så snart en pointer får en værdi. Vi har strukturen (pascal like syntax):
type
tree =
record
gren1: %tree;
gren2: %tree;
vaerdi = 1..100;
end;

var
x : tree;
y: %tree;

En sådan struktur viser, hvorledes vi undgår new, og pointere. % tegnet, svarer mest til vores reference symbol i C++. Når du tilskriver en værdi, oprettes automatisk en pointer, ved brugen. Her, er pointertypen altså en, der ikke bruges som pointer, men som "holder" af rigtige tal.

Hvilke tilskrivninger kan vi lave? Eksempel: x.vaerdi:=5; (det må være logik). Men, vi kan også lave følgende: x.gren1.gren1.gren2.gren1:=99; Denne vil automatisk oprette en række pointere, for at muliggøre dette.

Jeg har også taget en variabel y med. Den fungere præcis som x, og accepterer samme struktur, og tilskrivninger. Men, der er en forskel - nemlig forbruget. X fylder altid plads til to pointere, og en værdi som minimum. Medens y, er en pointer, og som start ikke har noget indhold (NIL). Den fylder derfor mindre, indtil der sættes data i - så fylder den reelt en pointer mere.

Nu kommer så det interessante - hvor du i mange sprog, som C++, ikke nemt kan få adgang til, hvor meget dynamiske variable fylder, så har du mulighed for det her. Du kan lave en sizeof på dit træ, og du får størrelsen af alt det, som er fra det pågældende sted, og ned. Derfor, kan du opdele brugen af dynamisk plads mere strukturet, og få at vide, hvad en del af din struktur "koster".

Denne sizeof, er som sådan abstrakt, og vi må ikke for pointere returnere noget der er maskinspecifik. Det betyder, at det mest nærliggende er, at tælle elementer. En pointer, fylder kun "1" element. Og det samme med vores værdi. Vi har ikke adgang, til størrelsen i bytes. Alligevel, er det nok til, at memory leaks nemt kan detekteres for træstrukturer.

Hvis du ønsker, at slette en del af træstrukturen, gør du det ved at sætte pointeren til NIL - du bruger så pointer symbolet & foran, og nulstiller den, eller bruger en ordre som delete(x.gren1.gren1), hvilken sletter alt under denne, ved at sætte til NIL, og slette alle underliggende data, hvis intet peger på dem.

Vi kan forestille os, at vores pointer som y kan bruges som rigtige pointere. I stedet for at tildele en værdi, kan vi f.eks. sætte &y:=x.gren1 hvorved den bruges som peger. Struktur mæssigt, er det dog bedst, at ikke tillade denne funktion, og påbyde en anden type variable til at pege, end at holde, og det menes at føre til færre fejl.

Fordelen ved ovenstående strukturer, er at de er mere strukturerede end normale pointer strukturer. Du tillader f.eks. at nemt deffinere et træ, så det kan ses, at det faktisk er et træ. De normale måder at bruge pointere, er faktisk ustruktureret programmering. Du får også mulighed, for at tjekke en del af dine dynamiske strukturer for brug af hukommelse, og eventuelle memory leaks - i stedet for at skulle tjekke hele lageret på en gang. Din compiler/debugger, kan simpelthen vise dig størrelsen for en given struktur.

Samtidig, når du tæller elementer, så er det ens for alle sprog, og alle compilere. Uanset, om compileren finder på, at bruge 8 eller 16 bits, når du kun skal have 7.

Vi kunne også måle det i bits, ved vi måler log2 af størrelsesområdet. Men, hvor stor skal det så vælges, for en pointer?

Nå du er systematisk, er det intet problem, at lave sprog, der er fuldkommen uafhængig af computerakitektur. Float, har vi set, kan være et problem at definere en algorithme for - men hvis vi sætter en defination af afrunding til antal bits, og angiver antal bits for eksponent, og mantisse, så kan man godt opnå en deterministisk float.
Det viser sig, at mangel på system, er det der har ført til flest fejl i verden. Manglen gør, at selv sproget, er et spagethi sprog, og f.eks. C++ er langtfra logisk. Når du sætter dig ned, og finder uoverensstemmelserne mellem C++ og logik, finder du ud af, at de pågældende uoverensstemmelser nemt fører til uheld. Og mange, er så godt skjulte, at selv gode C++ programmører, ikke er bekendt med problemerne.

Når du laver nye sprog, mener jeg stadigt, at det du skal satse på, er at forske i hvordan fejl undgås. Derved, kan du spare milliarder. Du må antage, at det i fremtiden sættes bøder - og måske fængselsstraffe på fejl. Og, så betyder det, at have et godt sprog, og en god compiler, måske forskellen mellem liv og død. For virksomheden - og i nogen lande, måske også for programmører. Og ellers lange fængselsdomme.

  • 0
  • 0
Karsten Nyblad

Tja, hvis man som jeg forsøger at skrive portabel kode i C, finder man hurtigt ud af, hvor svært det er altid at vælge den korrekte integer type. Det virker heller ikke særligt godt med at definere typerne i header filer, for når man seks måneder senere skal vælge den rigtige integer type til et felt i en record, kan man ikke huske, hvad man tænkte et halvt år tidligere. (Gud forbyde, at header filen er skrevet af en anden programmør, der har skiftet job og har været en snøbel til at skrive kommentarer.)

Jamen hvorfor skriver jeg i C? Fordi projektet startede i midtfirserne, og den gang var valgmulighederne ikke så store. F.eks. var Ada compilere dyre og genererede ikke så god kode. Hvis man vil skrive portabel kode, ender man ofte med at bruge gamle sprog, for det er disse sprog der findes gode compilere til på mange platforme.

Jeg vil så absolut mene, at det er et problem med C og C++, at man ikke kan være sikker på, at to compilere, der selv kører på samme platform og generere kode til samme platform, ikke giver samme betydning til samme indbyggede datatyper.

  • 0
  • 0
Karsten Nyblad

Jens, jeg er ikke sikker på, at dine ideer til automatisk generering af pointere er så gode i praksis. Det C program jeg sidder med gemmer data i et hav af record typer, der er hægtet samme på kryds og tværs og totalt sammenfilteret. Langt hovedparten af datastrukturerne er cykliske. Jeg talte lige antallet af * i disse record erklæringer og kom til 278. Hvad gør man med din sizeof operator, hvis datastrukturerne er cykliske og refererer videre til andre datastrukturer? Jeg tvivler på, at din operator kan give et svar, jeg kan bruge til noget i mit program.

Sandt at sige tror jeg den ide med sizeof er bedste til små eksempler, der kan være på en overhead planche.

Mht C, C++ og logic, så er de sprog rent faktisk logisk veldefinerede. At det så kan være en hestearbejde og i praksis mere eller mindre umuligt at lave formelle beviser om C og C++ programmers korrekthed er noget andet.

  • 0
  • 0
Rasmus Kaae

Karsten, igen, det er en vægtning (eller valg om du vil) som nogen har foretaget på et tidspunkt. Her hvor jeg sidder har vi store mængder legacy kode der oprinder fra Ada og som er konverteret til C på et senere tidspunkt. Jeg kender ganske udemærket til problematikken, det jeg siger er blot at det er spørgsmål om hvor vigtigt virksomheden mener parameteren er i selve udviklingen. Det er ikke en hindring i sproget, det er en force der åbner for optimeringsmuligheder. Jeg kan se det har en række pædagogiske uhensigtsmæssigheder, men sådan er der jo så meget.

Jens, fat dig i korthed, jeg orker ikke at læse 400 linjer når din pointe kunne være skrevet på 2. Desuden forstår jeg ikke hvor du vil hen, hvis du anvender en fornuftig datastruktur har du også mulighed for at forespørge dens størrelse. Yderligere skriver du at standard biblioteker gør uhensigtsmæssige ting ved sproget -- hvad er det for noget nonsens?!

  • 0
  • 0
Jens Madsen

> Jens, jeg er ikke sikker på, at dine ideer til automatisk generering af pointere er så gode i praksis. Det C program jeg sidder med gemmer data i et hav af record typer, der er hægtet samme på kryds og tværs og totalt sammenfilteret. <

Ustruktureret?

> Langt hovedparten af datastrukturerne er cykliske. Jeg talte lige antallet af * i disse record erklæringer og kom til 278. Hvad gør man med din sizeof operator, hvis datastrukturerne er cykliske og refererer videre til andre datastrukturer? Jeg tvivler på, at din operator kan give et svar, jeg kan bruge til noget i mit program. <

Det er 100% kompatibel med normal C++. Du kan lave en NEW funktion, der indeholder en pointer, til de nye data du laver, og linke disse. Altså, du laver en struktur med to pointere - en til den næste dataklynge, og en til de pågældende data. Hver gang, du kalder din new funktion, tilføjes det denne linære liste. Hvis du undersøger sizeof fra roden, får du alt, som er kreeret med den pågældende NEW funktion.

Hvis du kan bruge det, at have flere NEW funktioner, der tilføjer til hver sin "stak", så kan du opnå det, ved at lave flere new objekter. Eller, hvis du ikke kan lige OOP, så lave en statisk variabel, der indeholder roden (og træet), og overføre denne struktur, til new funktionen, så samme new bruges, på forskellige strukturer, du ønsker at tilføje.

Det er simpelt og muligt - helt kompatibelt, med nuværende C++ funktioner, hvis en new funktion eller objekt tilføjes. Men vil du have "goderne", må du opdele dit dynamiske forbrug, på flere træer, f.eks. en i hver objekt, du bruger dynamiske strukturer i.

Læg samtidigt mærke til, at jeg har udrydet alle pointertegn, ved at lave alt til normale variable. Dog, hvis du vil sætte en pointer værdi, gøres det modsat, ved du sætter pointer symbolet foran pointeren du vil ændre. Bruges pointeren, fungerer den som normal variabel, og det bliver derfor mere gennemskueligt hvordan koden fungere. Alle de pointertegn, og operatorer af forskellige typer, gør det faktisk mindre overskueligt, end hvis du bruger normale variable.

  • 0
  • 0
Jens Madsen

> Det er ikke en hindring i sproget, det er en force der åbner for optimeringsmuligheder <

Hvis noget ikke gøres godt, kan det altid optimeres...

Hvis du påstår, at det er nogen ulemper forbundet med, at lave et sprog, som du kan flytte 100% og som er 100% kompatibelt, så er du helt galt på den. Oftest, vil det have hurtigere compileringstid, det vil være hurtigere at udføre, osv. Det som gør ting sløvt, er at gøre det forkert. Selv fortolkere er hurtigere end C++, fordi C++ læser alt for mange data ind i processoren og misbruger cachen, og ram.

> Desuden forstår jeg ikke hvor du vil hen, hvis du anvender en fornuftig datastruktur har du også mulighed for at forespørge dens størrelse. <

Jeg mener ikke, at dynamiske datastrukturer er særligt strukturerede i hverken C++, C, eller Pascal. Du har i nogle sprog memavail, for at få den samlede lager der er ledig, men ellers kan være svært at få overblik over en kompliceret samling af dynamiske pointer strukturer og forbruget. Mest af alt, syntes jeg dog det er et ustruktureret rod med dynamiske objekte, og det er ikke struktur i det.

> Yderligere skriver du at standard biblioteker gør uhensigtsmæssige ting ved sproget -- hvad er det for noget nonsens?! <

Nej - det har jeg ikke just påstået. Men, jeg påstår, at når du ikke kender indholdet, og de resulterer i mange hundrede kilobytes assemblerkode, som du ikke tjekker, så er der risiko.

Desuden er mulighed for, at enhver kan omdeffinere de eksisterende funktioner i et bibliotek, og da de færreste gennemlæser og forstår alt de bruger, er der risiko. Jeg har set mange smarte programmører, der bare lige gør noget, ved de grundlæggende funktioner, for at få deres eget til at fungere. I sin tid, var det at gå så vidt, som til at modificere command.com i dos. Ellers vil deres software ikke fungere. Nu er det C++, der udsættes for samme terror, og sproget kan ikke stå mod, men lægger nærmest op til fejl som standard.

Tænk på, hvor meget ustabilt software der findes. Og tænkt på, at der kan laves sprog, der umuliggør alle former for ustabilt opførsel. Java er ikke min favorit, da jeg kender dem, der har udviklet software i Java, som er ustabil allerede ved opstart.

  • 0
  • 0
Karsten Nyblad

En ting, der undrer mig ved programmeringssprog, det er de primitive heaps, der bliver tilbudt. Der er masser af C, C++, Pascal og Ada programmer, der har problemer med memory leaks. Det er svært at sikre sig, at man har fået frigivet al lager, når man ikke mere har brug for den og programmerer i de sprog. Meget ofte har man bruge for data i en forholdsvis veldefineret periode. I database server har brug for data, mens den svarer på en query, hvorefter de kan glemmes. En web-server har brug for data, mens den regner ud, hvordan en dynamisk side skal se ud, hvorefter de kan glemmes. En compiler har brug for data, mens den oversætter en procedure, og derefter kan størstedelen smides væk.

Jeg kunne godt tænke mig et programmeringssprog, hvor jeg kan fortælle levetiden af data allokeret på heapen, i det øjeblik jeg laver min new operation. Når min database server skal besvare en query, opretter den data med en levetid, der ophører, når queryen er besvaret. Når min web-server danner en dynamisk side, opretter den data med en levetid, der ophører, når siden er sendt. Når min compiler oversætter en procedure, opretter den midlertidige datastrukturer, hvis levetid ophører, når oversættelsen af proceduren er færdig. De permanente datastrukturer gemmes et andet sted.

Den ide leder naturlig til at arbejde med mange heaps. Når man vil oprette midlertidige data, begynder men med at oprette en heap, som man derefter allokerer datastrukturerne på. Når man er færdig med at bruge disse data, sletter men bare hele heapen.

Der er flere fordele ved at arbejde på den måde. For det første er det lettere at sikre sig, at man for slettet alle midlertidige datastrukturer. For den andet er det lettere at kode. For det tredie skal computeren ikke udføre nær så megen kode. For det fjerde bliver heapen ikke så nemt delt op i en masse små, ubrugelige småbider.

Så vidt jeg kan se, kan dine ideer med sizeof operatoren med fordel kombineres med mine ideer. Hvis man allokerer fra en masse mindre heaps, ville en naturlig operation på disse heaps være, at besvare spørgsmål om, hvor meget der i øjeblikket er allokeret på en heap, og hvor meget der maksimalt har været allokeret på en heap.

Og så til dine kommentarer. Der er sikkert programmører, der ikke vil kunne lide min programmeringsstil. Min erfaring er, at hvis man skal skrive effektiv kode, skal man fra starten tænke sine datastrukturer, så man altid let kan finde de data man har brug for. Det skal ikke være nødvendigt at kalde en funktion, der skal gennemløbe lange lister, før den finder data. I det hele taget skal man holde ordenen af funktionen nede, altså hellere en funktion af orden o(n) end en af o(n2) eller o(n3). Data skal så vidt muligt være tilgængelige ved nogle få pointeropslag. Det gør så, at alle records skal indeholde pointere til de andre records, man typisk vil få brug for sammen med den aktuelle record. Tegner du en graf over, hvordan datastrukturerne hænger sammen i mit program, vil du ikke blive meget klogere. I stedet er du nødt til, først at se bort fra en stor del af alle disse pointere.

Det kræver, at man er 100% fortrolig med pointerprogrammering for at programmere i min stil, men det bliver man også, når man som jeg i en årrække har programmeret en compiler i BCPL. Det kræver også, at man kan fokusere på de data, man arbejder med her og nu. Det sværre ved at lære programmering af recursive procedurer, er at lære kun at tænke på de data proceduren arbejder med her og nu. På samme måde skal du lære at tænke på de data, du arbejder på her og nu, og ikke alle de data, du kan komme til ved at dereferere en enkelt pointer, men som du ikke har brug for.

Så skriver du i dit svar til Rasmus Kaae, at det giver problemer af forskellig art, når man redefinere standardbiblioteker. Der er vi helt enige, men det forekommer mig, at du selv er i gang med at foreslå noget af det samme. Hvis man redefinerer new og delete operatorerne i C++, ender man hurtigt i en situation, hvor der venter nogle grimme overraskelser til dem, der skal vedligeholde programmet.

  • 0
  • 0
Rasmus Kaae

Jeg kan ikke længere følge jeres argumenter. Efter min mening bruger I meget lange indlæg på at fortælle noget der kan gøres ganske kort.

Hvis I er tilfredse der hvor I er, f.eks. i Java som er porterbart i det omfang at der findes en VM til den givne platform, jamen så bliv da der. Min intention var blot at understøtte Hejlsberg og tilføje at en del af fusioneringen af programmeringsparadigmer kan ses og anvendes i C++.

Om C++ er et fornuftigt sprog at definere en datastruktur i eller ej, det er for mig uvedkommende og lige så relevant for denne diskussion som at sige at det regner i dag.

  • 0
  • 0
Jens Madsen

Jeg er helt enig med dig Rasmus i alt hvad du skriver.

Måske er jeg lidt skeptisk, ved at direkte sætte levetid på data (f.eks. 20 minutter)... Men det er vigtigt, at fjerne data omhyggeligt, og det er godt at kunne bruge flere heaps og eventuelt bruge det.

Og jeg tror, at netop denne måde er den bedste. Fremfor, at man fortæller, at nu har du 10 minutter, og så er data ovre - så er det bedre, at programmøren styrer metoden. Vi skal tænke på, hvor vigtigt det er med hardwareuafhængighed, og så nås det ønskede måske ikke på de 10 til 20 minutter. At sætte tid på, kan derfor være i konfligt med uafhængigheden af hardware, fordi vores CPU kan kræve en vis tid. Normalt vil man forlange, at programmet ikke styres af tid. Netop, at styre forskellige processer, med tid, har vist sig, at give masser af problemer. Måske bliver den ene færdig før den anden, og så opstår kaos.

Idéen var ikke at lave en "new" metode, og det er end ikke pænt at gøre på den måde. Tanken var kun, at forklare, at det du kan gøre med new, også kan gøres på min måde.

Hvis du vil lave en new, løber du faktisk ud i en række problemer. Med new, kan du håndterer mange forskellige datatyper - og disse har forskellig størrelse. Jeg har ikke direkte angivet, hvordan du kan klare problemet, men naturligvis kan man godt det. Det er meget naturligt, at når du har mulighed for en pointer variabel, der først får værdi, når data sættes ind, så kunne du godt have en type, der tager forskellige typer. Hvis vi f.eks. kalder vores specielle type, for %type, så kan der nu sættes enhver type data i denne variabel, og den opretter sig selv, ved at lave en pointer. På det tidspunkt, at pointeren slettes (hvis den holder data), så vil dataene følge med. Hvis vi vælger et system, hvor pointere der holder data, og peger på data er rodet sammen, så er ikke nogen decideret pointer at slette, men vi må slette alle pointere der peger på data, og så vil det rydes op som i Java. (Jeg syntes det er lidt ustruktureret). Selvom du ikke har adgang til en sådan type, er det dog muligt, at gøre alt, som kan gøres med new. Vi må dog lave et "træ" for hver type vi håndterer. De kan så til gengæld, sættes sammen i et overordnet træ, så vores struktur hænger sammen.

Jeg mener, at det giver langt flere muligheder, end C++ - og ikke mindst, er det nemmere at slette data. I princippet er alle uendelige datastrukturer, almindelige strukturer, der indlejrer sig selv, og derved er uendelige. Indlejringen sker dog, ved hjælp af en pointer, og strukturen vokser, når der sættes data i. Vi kan have en pointer, til et bestemt sted i strukturen, og f.eks. vælge at have en slags deltree, der sletter alt, efter et bestemt sted (sætter den pågældende pointer, der inkluderer undertræerne til NILL og sletter alle data, der er under), og derved bliver det nemt, at slette undertræer.

Jeg mener egentligt ikke, at det er en god idé, at implementere new, og delete, for at opnå noget der ligner C++. Det er bedre, at lære alle, at programmere på en mere struktureret måde.

Med hensyn til, at implementere SQL, går jeg ikke direkte 100% imod sådanne "tiltag". For der er mange, som ikke kan programmere algoritmer og søgetræer, der er O(log(n)). Det er muligt, at lave så godt som alt, med O(log(n)) træer. Og jeg plejer at sige, at skal et program have svartid, må det aldrig være sløvere, end O(log(n)).. Ellers, skal parameteren for svartiden tages med, og dermed har den ikke acceptabel svartid, men en svartid, der f.eks. afhænger af datastørrelse.

Prøv at tænke tanken, at du har en bibliotikar, der bruger samme algorithm, som en programmør. Prøv at regne ud, hvor mange millioner år, der tager at finde en artikkel i tidsskriftsamlingen på bibiliteket?

Det kræver simpelthen en Pentium.

Hvis du bruger en O(log(n)) algorithme, ligesom din bibliotekar, så vil du ikke behøve andet end en gammel sløv 286, eller langsommere.

  • 0
  • 0
Log ind eller Opret konto for at kommentere