Dart-pilen sidder lige midt i skiven

Dagen startede godt med en spændende keynote af Kasper Lund fra Google, som fortalte om, hvor udviklingen af JavaScript-afløseren (forhåbentlig) Dart pt. er nået til.

JavaScript er dejligt nemt at komme i gang med på grund af sin tilgivende natur - faktisk var det også det første programmeringssprog, jeg kastede mig ud i, bl.a. fordi det var nemt at kigge efter andre menneskers kodestumper ude på internettet - men når man når lidt videre end de første Hello World, JavaScript-lommeregnere og små valideringseksempler, bliver JavaScript noget tung at danse med.

Dart ser ud til at være nem at komme i gang med for Java/C#-programmører pga. sin genkendelige syntaks, klasser, interfaces og ikke mindst curly brackets som Kasper mindede os om tilsyneladende er et krav for at opnå Java-programmørernes kærlighed ;-)

Dart giver mulighed for statisk at specificere typerne på variable og parametre NÅR MAN FINDER DET BELEJLIGT; en herlig mellemvej mellem Java-programmørens kamp for at få skåret typerne tilstrækkeligt ud i pap til at compileren er HELT SIKKER, og JavaScript-programmøren, der er henvist til at skrive eventuelle type-begrænsninger som ikke-checkbar dokumentation.

På nuværende tidspunkt er Dart måske stadig ikke helt modent til, at det er det oplagte valg, man hiver ned af hylden på et nyt web-projekt, men de sprog-features og biblioteker, der er indbygget i SDK'et ser bestemt vel-tænkte ud og peger i retningen af et sprog, der i høj grad kommer til at være brugbart.

Foto: Bogdan Suditu

En af ideerne med, at Dart er offentliggjort i en forholdsvis tidlig version er netop også, at Google kan få samlet feedback fra udvikler-community'et. Ulempen er selvfølgelig, at Dart-projekter på nuværende tidspunkt kan risikere at bygge på sproglige konstruktioner eller biblioteksfunktioner, som ændrer sig, men da jeg talte med Kasper om dette efter keynoten fortalte han, at Google netop gør meget ud af at melde Dart-ændringer ud i god tid.

Pt. er det især server side libraries, der er bygget ind i SDK'et, og Dart-baserede projekter vil på nuværende tidspunkt nok støde ind i, at man savner client side libraries. Google arbejder selv på disse, bl.a. har man allerede indbygget query selectors og adgang til alle DOM collections i W3C, men mon ikke også udvikler-community'et udenfor Google vil bidrage med gode biblioteker, når flere begynder at arbejde med Dart?

Dart compiler til JavaScript for at kunne køre også i browsere, der ikke har en Dart VM (pt. har ikke engang Google Chrome den indbygget). Der er pt. ikke de store interoperabilitetsmuligheder mellem Dart og JS - kun noget message parsing - så det er ikke muligt at kalde sine eksisterende JS-biblioteker fra Dart, hvilket nok vil forsinke adaptionen af Dart i projekter, der allerede har en masse logik bygget i JS.

Det lød som om Dart-teamet regner med, at Dart VM'en vil blive væsentligt hurtigere end V8 (Kasper har i øvrigt også arbejdet på V8'eren, så han må have god baggrund for at sige dette), men pt. kører flere af deres benchmarks hurtigere i det genererede JavaScript end i Dart. Som jeg ser det er Darts bidrag til verden dog også først og fremmest på udviklings-siden; at gøre det sjovere at skrive og vedligeholde web-apps (og server-side apps, i øvrigt også).

Kommentarer (22)
Kræn Hansen Blogger

Jeg glæder mig til at få fingerene i Dart. Det virker som om Kasper og de andre har gjort sig rigtig mange fornuftige overvejelser, også om det komplicerede økosystem som Dart introduceres i. Må dog indrømme at det giver en lille ud-af-kroppen oplevelse når man ser at en string assignment til en integer ikke resulterer i andet end en warning.
Jeg håber ikke at det ender i en krig imellem giganter der hellere vil holde på markedsandele end at understøtte fornuftige teknologiske løsninger. Jeg skal i hvert fald hjem og kode Dart ...

Baldur Norddahl

En alternativ tilgang er projektet ScalaGWT http://scalagwt.github.com/. Også her oversættes til JavaScript så at man kan køre Scala programmer i en webbrowser. Det er muligt at blande Scala, Java og JavaScript i samme projekt.

Scalas tilgang til dynamiske typer er at inkludere et godt typeinferens-system. Programmøren behøver derfor ikke angive typer det meste af tiden. Oversætteren beregner dog typerne så sproget er fuldt statisk typet.

Casper Bang

En alternativ tilgang er projektet ScalaGWT http://scalagwt.github.com/. Også her oversættes til JavaScript så at man kan køre Scala programmer i en webbrowser. Det er muligt at blande Scala, Java og JavaScript i samme projekt.

På sin vis kan forløberen for Dart findes i GWT. De fleste Google ansatte der arbejdede på GWT, arbejder i dag på Dart - og det siger måske lidt om at det er langt mere grundlæggende ting Google ønsker at råde bod på end blot syntaksen. Det er heller ikke nødvendigvis nogen dans på roser at skrive GWT/ScalaGWT, hvor cross-compilation er langsom, kræver specielle udvikler plugins og alligevel ikke tillader en at abstrahere fra grundessensen CSS.

Chrome har ganske vist ikke Dart VM'en indbygget endnu, men den udvikles i en fork af Chromium ved navn Dartium som kan hentes og testes her

...og i dét øjeblik Google vælger at rulle supporten ud i Chrome, har de allerede sørget for indfødt Dart support i 33% af alle browsere i brug.

Torben Mogensen Blogger

Den bedste måde at blande statiske og dynamiske typer er efter min mening at lave typeinferens (som i ML, Scala og Haskell) og tillade eksplicit angivelse af steder, hvor typerne er dynamiske (eksplicit konvertering til dynamisk type og typecase eller lignende for at konvertere fra dynamisk til statisk).

Peter Juhl Christiansen

Det vil vist være det man kalder en journalistisk stramning at sige Dart har rødder i GWT.

Så vidt jeg er orienteret har hjernerne bag Dart ikke været involveret i GWT, men Dart er formodentligt også en konsekvens af at Google har erkendt at GWT vejen (hvor man skriver java der bliver til javascript) ikke holder på den lange bane.

Når det er sagt synes jeg Dart er utrolig interessant og bestemt noget jeg har planer om at eksperimenterer med. Ville bare have ønsket de havde været mere ambitiøs mht syntaksen, deres påstand om at en Java lignede syntaks vil få flere til at bruge det er efter min mening ubegrundet, vil gå så langt som til at sige at udbredelsen af sprog som Scala, Python og Ruby viser det modsatte!

Tænker man så på hvordan et sprog som fx Ruby gør ting der er kluntet og besværlig i traditionelle sprog simple og elegant, synes jeg det er ærgerligt at Google og Dart ikke har forsøgt at lade sig inspirerer mere af den slags sprog.

På plus siden vil jeg dog sige at det er interessant med "optional types", ”første klasses” funktioner og closures, som bestemt ikke bare a fine ord men features der formodentligt gør det sjovere og mere produktivt at kode i.

Torben Mogensen Blogger

For nu at referere et sprog der rent faktisk bruges i praksis og derfor er inden for Tiobe's top50, så bør C# nok også lige nævnes i dette henseende. :)

C# har ikke egentlig typeinferens -- du kan undlade at specificere typer for variable, der initialiseres, men C# kan f.eks. ikke inferere typer for parametre eller metoder. Jeg vil kalde C#s mekanisme "type evaluering", da den kræver, at alle typer på højresiden af en initialisering er kendte, hvor egentlig typeinferens kan udlede typen af en variabel ud fra, hvordan den bruges.

Baldur Norddahl

Så vidt jeg er orienteret har hjernerne bag Dart ikke været involveret i GWT, men Dart er formodentligt også en konsekvens af at Google har erkendt at GWT vejen (hvor man skriver java der bliver til javascript) ikke holder på den lange bane.

Jeg tror nu mere at Google bare spiller på flere heste. Ud over Dart og GWT har Google også et JavaScript baseret system som de vedligeholder. Google kører i mindst tre spor her.

Det er klart at det ikke er optimalt at oversætte til JavaScript. Det er af nød man gør det, uanset om kildesproget er Dart, Java eller Scala. Derfor så jeg helst at man fik skruet lidt op for blusset for at lave en "fælles vm" som kan bruges af diverse sprog, herunder ovennævnte.

Jeg kan godt føle lidt at man forspilder en chance, hvis man udvikler og fremmer en DartVM, hvis denne ikke er lavet så den er velegnet til alle mulige andre sprog.

Casper Bang

C# har ikke egentlig typeinferens -- du kan undlade at specificere typer for variable, der initialiseres, men C# kan f.eks. ikke inferere typer for parametre eller metoder. Jeg vil kalde C#s mekanisme "type evaluering", da den kræver, at alle typer på højresiden af en initialisering er kendte, hvor egentlig typeinferens kan udlede typen af en variabel ud fra, hvordan den bruges.

Jeg refererer til at, udover lokal type-inferens, har C# også dynamic dispatch via "dynamic" keyword:
http://msdn.microsoft.com/en-us/library/dd264736.aspx

Genialt når man skal interface med omverdenen og helt i tråd med moderne polygloth programmering. Eksempel:

dynamic dynlibc = new PInvoke ("libc");  
dynlibc.printf ("I am dynamic call, how cool is this!");
Casper Bang

Det vil vist være det man kalder en journalistisk stramning at sige Dart har rødder i GWT.

Så vidt jeg er orienteret har hjernerne bag Dart ikke været involveret i GWT, men Dart er formodentligt også en konsekvens af at Google har erkendt at GWT vejen (hvor man skriver java der bliver til javascript) ikke holder på den lange bane.

I 2011 skrev "king of GWT" Bruce Johnson, "...many of the same engineers who brought you GWT are working on Dart..." så det er da vist ikke så langt ude.

Og prøv at tage et kig på hvor mange folk der er skredet fra GWT teamet, samt SVN commit loggen for det sidste halve år - der er ikke sket meget! Og med tanke på hvorledes andre relaterede projekter er endt (Wave var tæt forbundet med GWT), er det ret sansynligt at GWT i virkeligheden nu er i maintenance mode og potentielt bliver doneret til open source så snart Dart er blevet moden nok. Derfor har jeg nu hånden på håndbremsen mht. GWT i vores udviklings-afdeling.

Torben Mogensen Blogger

Jeg refererer til at, udover lokal type-inferens, har C# også dynamic dispatch via "dynamic" keyword

Ja, det er jeg klar over. Men hvis man skal have noget, der nærmer sig bekvemmeligheden af et (helt) dynamisk sprog, så skal man ikke være tvunget til at angive typer andet end nogle få steder. Med et overvejende statisk typesystem betyder det "rigtig" typeinferens. Man kan (som i ML og Haskell) angive eksplicitte typer som dokumentation (og for at hjælpe typeinferensen), men udover det kan det være interesant at kunne angive typen "dynamic".

Man kan i et vist omfang simulere dynamiske typer i ML ved at bruge exceptions: Der er en universal exceptiontype, og man kan tilføje nye konstruktorer til denne overalt i programmet. Man kan overføre exceptionværdier som parametre osv, uden at de rejses, så man kan bruge dem på linje med andre værdier.

Casper Bang

Ja, det er jeg klar over. Men hvis man skal have noget, der nærmer sig bekvemmeligheden af et (helt) dynamisk sprog, så skal man ikke være tvunget til at angive typer andet end nogle få steder. Med et overvejende statisk typesystem betyder det "rigtig" typeinferens. Man kan (som i ML og Haskell) angive eksplicitte typer som dokumentation (og for at hjælpe typeinferensen), men udover det kan det være interesant at kunne angive typen "dynamic".

Ja altså, i pragmatiker land, siger man jo gerne "static when you can, dynamic when you must". At man i C# kun har lokal type inferens skyldes jo en balance imellem den i forvejen komplicerede method resolution der foregår i et OO sprog (overloading, nedarvning, covariens, contravariens, vararg etc.). Det giver også god mening at denne "bekvemmelighed" er udeladt når man tænker på contract-driven development som et eksporteret API/SPI repræsenterer.

Man kan i et vist omfang simulere dynamiske typer i ML ved at bruge exceptions: Der er en universal exceptiontype, og man kan tilføje nye konstruktorer til denne overalt i programmet. Man kan overføre exceptionværdier som parametre osv, uden at de rejses, så man kan bruge dem på linje med andre værdier.

Alle sprog har features der kan misbruges. Jeg er nok af dén skole der mener at exceptions brugt som alternative returveje (glorificeret GOTO) er noget skidt når der er langt mere elegante idioms i de fleste sprog. :)

Torben Mogensen Blogger

Jeg er nok af dén skole der mener at exceptions brugt som alternative returveje (glorificeret GOTO) er noget skidt når der er langt mere elegante idioms i de fleste sprog. :)

Min pointe var ikke at bruge exceptions som alternative returveje (selv om der er tilfælde, hvor det giver mening). Min ide var at bruge typen "exception" som en dynamisk type, dog uden nogensinde at rejse nogen exceptions. Modsat mange andre sprog er exceptions i ML "first class citizens", som kan bruges på linje med alle andre værdier.

Casper Bang

Min pointe var ikke at bruge exceptions som alternative returveje (selv om der er tilfælde, hvor det giver mening). Min ide var at bruge typen "exception" som en dynamisk type, dog uden nogensinde at rejse nogen exceptions. Modsat mange andre sprog er exceptions i ML "first class citizens", som kan bruges på linje med alle andre værdier.


Ok, jeg kender ikke ML men jeg kan se det har tupler, som jeg i så fald ville foretrække istedet. Jeg henviser bare til, på baggrund af kommentaren "...tillade eksplicit angivelse af steder, hvor typerne er dynamiske...", at dette netop er filosofien i C# 4.0 (et industrielt general-purpose sprog i Tiobe top5) som mange af Version2's læsere må formodes at arbejde med til daglig.

Type-inference er smart, men jeg er stadig fortaler for at det forbliver internt i et API (som Anders Hejlsberg lægger op til i C#). Et af de problemer jeg ser med type-inferens i større, rigere, længerelevende applikationer; er manglen på abstraktion. Eksempel:

def getSomeList() = {  
  new ArrayList[String]()  
}

Ovenstående Scala (der har type-inference) bliver udledt til at være den konkrete Java type java.util.ArrayList, hvilket er problematisk hvis jeg i virkeligheden ikke ønsker at deklerere og eksponere en dependency på denne type, men istedet en abstrakt java.util.List (der ikke siger noget om big-Oh kompleksitet i forbindelse med inserts, søgning osv.). Ved at lade type-inference være en intern short-hand implementeringsmekaniske, undgår man at gå på kompromis med abstraktionsniveauet.

Torben Mogensen Blogger

Et af de problemer jeg ser med type-inferens i større, rigere, længerelevende applikationer; er manglen på abstraktion. Eksempel:

val someList = new ArrayListString

Ovenstående Scala (der har type-inference) bliver udledt til at være den konkrete Java type java.util.ArrayList, hvilket er problematisk hvis jeg i virkelighed ikke ønsker at deklerere og eksponere en dependency på denne type, men istedet en abstrakt java.util.List (der ikke siger noget om big-Oh kompleksitet i forbindelse med inserts, søgning osv.). Ved at lade type-inference være en intern short-hand implementeringsmekaniske, undgår man at gå på kompromis med abstraktionsniveauet.

I ML kan du bruge modulsystemet til at gøre typer abstrakte, så du kun kan tilgå dem gennem eksporterede operationer. Der er ingen konflikt mellem abstraktion og typeinferens: Når man har brug for abstraktion, laver man eksplicitte erklæringer, som synliggør præcis, det man vil synliggøre.

Baldur Norddahl

ArrayList i en Scala applikation? Tsk tsk. Scala har altså et langt overlegen collection API i forhold til Java.

I forhold til dynamiske typer vil jeg holde på at typeinterferens er den bedre metode. Det kan godt være at den dovne programmør eksponerer lidt for mange implementationsdetaljer i dit eksempel, men oversætteren kan trods alt give fejl hvis en rettelse medfører et problem. Sammenlign med et sprog med dynamiske typer, da vil brugeren af getSomeList stadig kunne kalde ArrayList specifikke metoder. Ændrer vi herefter implementeringen til en anden List-nedarvning, så opdager Scala problemet compile-time men med det dynamiske sprog opdages det først runtime.

Det mindre dovne programmør har i Scala mulighed for at definere metoden med eksplicit returtype "def getSomeList: List = xxx" men den mulighed er der bare ikke med dynamiske typer.

Som jeg forstår Dart så er de midt imellem. Det er muligt at have en eksplicit returtype, men undlader du den, så har du ulemperne fra de dynamiske typer. Det valg forstår jeg ikke - hvorfor ikke lade oversætteren beregne returtypen, som i Scala, og fange de fejl compile-time?

Peter Juhl Christiansen

Er sådan set enig med dig i den forstand at der er visse ting der tyder på at Google er ved at køre GWT ud på et side spor, og køre Dart i stilling til at overtage.

Min kommentar om "journalistisk stramning" referer mere til det faktum at det primært er folk som Gilad Bracha og Lars Bak, der har udtænkt Dart og de har så vidt jeg ved ikke haft noget med GWT at gøre.

Casper Bang

I ML kan du bruge modulsystemet til at gøre typer abstrakte, så du kun kan tilgå dem gennem eksporterede operationer. Der er ingen konflikt mellem abstraktion og typeinferens: Når man har brug for abstraktion, laver man eksplicitte erklæringer, som synliggør præcis, det man vil synliggøre.

Du bliver ved med at komme tilbage til ML, som kun CS Ph.d.'er kender til og bruger. Så vidt jeg kan se skal ML ikke tage hensyn til hverken OO subtyping, method overloading mv. så det er måske ikke helt fair at sammenligne med Dart synes jeg. Dertil kommer Scala og F# noget tættere på.

Min kommentar om "journalistisk stramning" referer mere til det faktum at det primært er folk som Gilad Bracha og Lars Bak, der har udtænkt Dart og de har så vidt jeg ved ikke haft noget med GWT at gøre.

Gilad havde indtil midten af 2011 hvor han blev hyret af Google, travlt med hans eget sprog (Newspeak)... Dart går formodentligt længere tilbage end 8-9 måneder! :) Joshua Bloch, Google's Java chef arkitekt, har åbentbart også været inde over GWT.

Torben Mogensen Blogger

Du bliver ved med at komme tilbage til ML, som kun CS Ph.d.'er kender til og bruger.

Datalogistuderende kan programmere i ML allerede et par måneder efter studiestart, så det er lidt overdrevet.

Så vidt jeg kan se skal ML ikke tage hensyn til hverken OO subtyping, method overloading mv. så det er måske ikke helt fair at sammenligne med Dart synes jeg. Dertil kommer Scala og F# noget tættere på.

Dynamisk subtypning som i Java og C# synes jeg er en unødig komplikation, der ikke giver meget (udover fejlkilder) i forhold til statisk subtypning (som i Haskell typeklasser).

Overloading findes (med få undtagelser) ganske rigtigt ikke direkte i ML (selv om du kan lave noget lignende ved at bruge modulsystemet). Men her er Haskells løsning (typeklasser) bedre end i C# og lignende sprog.

ML er ikke uden fejl, og visse dele af designet vidner om, at det efterhånden er et gammelt sprog. F.eks. er der ikke i sproget en standard for flertrådet eller parallel programmering (selv om der findes implementeringer af begge i nogle compilere/biblioteker), der er ikke standardiseret Unicode support eller generel overloading. Men det ville være en skam at ødelægge sproget med Java-lignende objekter.

Scala og F# er spændende projekter, men de lider begge under, at de skal have tæt integration med de underliggende objektorienterede platforme (JVM og .NET). Det har trukket designet i en, efter min mening, uheldig retning. Læs Bob Harpers blog (http://existentialtype.wordpress.com/) for vebegrundede overvejelser om MLs design.

Casper Bang

Dynamisk subtypning som i Java og C# synes jeg er en unødig komplikation, der ikke giver meget (udover fejlkilder) i forhold til statisk subtypning (som i Haskell typeklasser).


Jeg er ikke helt sikker på hvad du mener med "dynamisk subtyping", eftersom en dynamisk variabel, per definition, kan antage samtlige mulige typer. Og Java har ingen dynamiske typer, kun en bytekode (InvokeDynamic jvf. JSR-292) til at accelerere Ruby, Python osv. på JVM'en (der ellers har skulle benyttet sig af langsomme dynamiske proxier igennem reflection API'et).

Torben Mogensen Blogger

Jeg er ikke helt sikker på hvad du mener med "dynamisk subtyping"

Det kan jeg egentlig godt forstå, for jeg mente "dynamisk nedarvning". Indlægget var skrevet i hast inden et møde, hvilket stavefejlen i sidste linje også bevidner. Jeg beklager.

I dynamisk nedarvning afhænger den kaldte metode af den værdi, en variabel antager på køretid, mens den i statisk nedarvning kun afhænger af typen af variablen, uanset om værdien er af en undertype.

Java, C# og mange andre OO-sprog bruger dynamisk nedarvning, mens Haskell (og til dels C++) bruger statisk nedarvning. Haskell har ikke egentlige subtyper, men der er nedarvning på typeklasser, som svarer lidt til nedarvning for interfaces i Java.

Log ind eller Opret konto for at kommentere