Boo


søndag 4. desember 2011 Julekalender Polyglot Boo

Er du interessert i å lære et .NET-språk som er mer elegant og enklere å skrive enn C# og VB.NET, og som i tillegg gir deg samme mulighet for å utvide selve språket som det Lisp gjør? Da kan Boo være et bra valg!

Boo er et objektorientert, statisk typet språk med en syntaks inspirert av Python. Det så dagens lys i 2003, og har vært under aktiv utvikling siden det. Gjeldene release ble sluppet i januar 2011.

Boo kjører altså på .NET-plattformen (og Mono), og man har tilgang til det meste av hva man er vandt til i rammeverket, som generics, linq osv, og man kan benytte alt man har av eksisterende .NET-biblotek. Ofte bruker man Boo til deler av prosjekt – der hvor Boo's styrker kommer til sin rett.

Disse styrkene er blant annet en behagelig syntaks (selv om ikke alle vil være enige i det), og kraftig type inference og automatisk type casting som gjør at den sterke typingen ikke går i veien for deg, og er mer behagelig å jobbe med. Dessuten får du literals (enklere syntaks) for lister, arrays og dictionaries, du trenger bare bruke klasser når du trenger det (funksjoner lever fint for seg selv), og du kan bruke duck-typing (en form for dynamisk typing) når du måtte ha behov for det.

boo

Alt dette er vel og bra, men Boo har mer! Fokuset under utviklingen av Boo har vært på å lage en fleksibel og utvidebar kompilator. Dette gjør at man kan utvide selve språket gjennom å lage ting som meta-metoder og makroer som kjører under selve kompileringsprosessen. Disse teknikkene gjør blant annet at man kan unngå det vi ofte kaller for boilderplate code. Det gjør også Boo til et glimrende verktøy for å lage domenespesifike språk, noe Ayende Rahien beskrev i boken DSLs in Boo: Domain-Specific Languages in .NET.

Jeg har selv fått benyttet Boo på denne måten i et par prosjekter, og synes det fungerer ganske bra.

På tide med litt kode

Som vanlig har jeg implementert en løsning (eller rettere sagt flere løsninger) på Project Euler problem nummer 1hvordan man summerer opp alle tall opp til 1000 som er delelige på 3 eller 5. Dette vil ikke demonstrere noen makro eller meta-features, men gi et første inntrykk av hvordan Boo-kode ser ut, og hva man kan gjøre.

 1 """A simple, imperative Boo solution to Euler problem #1"""
 2 
 3 class Euler1:
 4   static def Solve():
 5     sum = 0
 6     for i in range(1, 1000):
 7       if i % 3 == 0 or i % 5 == 0:
 8         sum += i
 9     return sum

I koden over deklarerer jeg en klasse jeg kaller Euler1. Den har en statisk metode som heter Solve. Her kjører jeg en for-løkke over en range og legger til et tall i sum-variabelen hvis det er delelig på 3 eller 5.

Du bør ha lagt merke til et par ting: For det første bruker Boo indentering til å definere strukturen i koden, akkurat slik Python gjør det. Dessuten har jeg ikke deklarert noen typer her (bortsett fra selve Euler1 da), Boo-kompilatoren skjønner fint at sum er en int, at i er en int, og at Solve dermed også returnerer en int. Ingen grunn til at jeg skal måtte påpeke det.

For å kjøre koden min skriver jeg følgende:

11 print Euler1.Solve()

Siden Solve er en statisk metode trenger jeg ikke opprette en instans av Euler1, men kaller bare metoden direkte på klassen. Print er faktisk en makro som ekspanderer til System.Console.WriteLine(..) under kompilering.

Her følger en alternativ implementasjon som benytter seg av Sum-funksjonen i System.Linq:

1 import System.Linq.Enumerable
2 
3 def Euler1Filter(it as int):
4   if it % 3 == 0 or it % 5 == 0:
5     return it
6 
7 print range(1, 1000).Sum(Euler1Filter)

En range er nemlig en IEnumerable<Int32>, og jeg kan dermed kalle Sum på denne, slik .NET-utviklere er vandt til, og sende inn en funksjon som parameter. Denne funksjonen blir kalt for hvert element i sekvensen. Legg merke til at jeg har gjort noe litt rart i Euler1Filter-funksjonen.., jeg returnerer kun hvis elementet skal være med. Jeg antar Boo er smart nok til å returnere en default-verdi (dvs. 0) når elementet ikke matcher.

Til slutt har jeg gjort en løsning som benytter det Boo kaller for en Generator Expression (jeg ville kalt det en list comprehension):

10 import System.Linq.Enumerable
11 
12 def include(i as int):
13   return i % 3 == 0 or i % 5 == 0
14 
15 def euler1Range():
16 """ Function returns a Generator Expression """
17   return x for x in range(1, 1000) if include(x)
18 
19 print euler1Range().Sum()

Hvorfor bruke tid på Boo

Bakgrunnen for Boo er først og fremst en frustrasjon over syntaksen til C#. Hvis du deler denne, og synes språk som Python er mere elegante, så er Boo noe du bør se på.

Men styrken til Boo ligger i makroene. Du kan utvide språket med nye kodeord og strukturer som gjør at du kan forme det til å passe dine behov, og gjøre din kode enklere. Dette er kanskje ikke for hvem som helst, men seriøse utviklere bør være klar over hva de eventuelt går glipp av om de ikke bruker makroer.

Hvordan komme i gang

Boo finner du på boo.codehaus.org. Det du kan begynne med er å lese Boo-manifestet (pdf), skrevet av språkets skaper i 2004-2005.

Jeg har slitt litt med at noe av dokumentasjonen på Boo er utdatert, og det kan være litt vanskelig å navigere på siden for å finne det man er ute etter. Men det finnes et relativt stort community rundt Boo, og det skal være mulig å finne den hjelpen man trenger om man forsøker.


comments powered by Disqus