Ruby, Elm, Kotlin - se flaskesangen generert med 6 språk

Faggruppa løste samme problem med JavaScript, Kotlin, Ruby, Elm, F# og C#. - Gøy!

Peter Hemmen i Bekk viser deg hvordan faggruppa hans løste 99 flasker på veggen-sangen på forskjellige måter i forskjellige språk. 📸: Privat
Peter Hemmen i Bekk viser deg hvordan faggruppa hans løste 99 flasker på veggen-sangen på forskjellige måter i forskjellige språk. 📸: Privat Vis mer

I faggruppen Røddig kode hadde vi i forrige uke et møte (på video, seff) der vi alle sammen programmerte samme, lille oppgave i et valgfritt språk og sammenlignet resultatet.

Selv med en liten oppgave, var det stor bredde blant løsningene våre.

Tungt inspirert at boken 99 Bottles of OOP skulle vi nemlig lage et program som skrev ut teksten til sangen “99 Bottles of Beer”.

Hele teksten kan finnes på 99-bottles-of-beer.net, men jeg tror man får et godt nok inntrykk av problematikken her ved å se på de siste fire versene:

«De 97 første versene er temmelig like hverandre.»

"3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottles of beer on the wall.

2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.

1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, no more bottles of beer on the wall.

No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall."

De 97 første versene er temmelig like hverandre, men så er det altså i de tre siste versene kompleksiteten er gjemt.

På forhånd var jeg enig om at vi alle forsøkte å følge samme API. Det inneholder tre public-metoder: song() skriver ut hele sangen, verses(start, stop) skriver ut vers nummer start til vers nummer stop. verse(verse) skriver ut vers nummer verse.

La oss se på noen løsninger!

Utvikleren har her skilt på vers-nummer og antall flasker (det var det ikke alle som gjorde), og hen har også lagt til støtte for et vilkårlig antall flasker med noe snedig modulo-bruk.

Verses er laget fort og gæli med en while som endrer på start-verdien, og selve de fire variantene av vers er skrevet ut helt ekspslisitt. Linjeskift legges til både inni strengene og med Console.WriteLine siden C# ikke har multi-line strings. Alt i alt oversiktlig og greit, dette.

Her er en tilsvarende løsning i Kotlin. Legg merke til forskjellene:

Denne er som nevnt temmelig lik som den første løsningen vi så på, men her er det i mine øyne enda litt tydeligere hva som faktisk blir skrevet ut fordi det er er brukt multi-line strings og when-statementet i Kotlin er også hakket mer eksplisitt enn “tradisjonelle” if-setninger. for-løkka med downTo er fiffig, men litt trekk for å blande vers og flasker i koden er vi nesten nødt til å gi.

Løsningen der hver av de fire variantene med vers er skrevet ut var den vanligste, og vi har et par til vi skal se på. Her er en Ruby-variant:

Ruby sløser ikke akkurat med linjene, men jeg skulle gjerne ha sett en litt mer elegant måte å lage strengene på for å unngå eksplisitte linjeskift inni strengene og skråstrek mellom linjene.

Dessuten har forfatteren (som tilfeldigvis er meg sjæl) blandet konseptene vers og flasker. Tsk tsk.

Den siste av disse mest eksplisitte variantene er skrevet i Elm:

Det er greit å følge med på hva som skjer her (hvis man har sett litt Elm tidligere i hvert fall), men personlig ville jeg satt pris på å slippe de litt klønete kallene til String.fromInt.

Det er vel imidlertid (litt av) prisen man må betale for kruttsterk typing og maks eksplisitthet (heter det det?) over hele linja.

Personlig ville jeg nok foretrukket en case/of istedenfor en else/if, men nå er vi over i (Jørn Ola) Pirkeland. Også verdt å merke seg her er at utvikleren har skrevet seg bort fra vers/flasker-problematikken ved å kalle “telleren” for i inni verse og så bruke List.reverse på lista etterpå. Snedig!

Apropos snedig, la oss se på den løsningen med færrest kodelinjer (selv om jeg ikke tror det nødvendigvis var et mål). Denne er skrevet i Javascript:

Her er det innført noen hjelpe-konsepter som labelize og pluralize, og selve iterasjonen er fint løst med rekursjon og en falsy-sjekk. Jeg ser bort fra at første linja har en liten feil (1 bottles of beer…).

Jeg ser derimot ikke bort fra beslutningen om å avslutte hvert funksjonsnavn med “lize” og å ikke følge API-et som jeg ble enig om før møtet.

La oss ta en titt på en annen JS-variant:

Selve verse-funksjonen er oversiktlig, med en del hjelpefunksjoner for å ta unna småforskjellene i de forskjellige variantene av verset.

Verdt å merke seg er bruken av et resultat-objekt fra doBeer for å samle handlingen med flaskene og hvor mange som gjenstår. Utvikleren har til og med brukt et par biblioteker fra npm. De har heldigvis svært beskrivende navn.

Én liten luring til i JS tar vi oss tid til:

Lik, men ikke helt lik, noen andre løsninger vi har sett. Jeg liker tydeligheten til switch/case for å vise hvilke typer vers som håndteres, bra skille på vers-nummer/antall ølflasker og det er jo riktig så røddig™ med input-validering.

Så får det heller være at det har sneket seg inn en liten feil i verset med to ølflasker igjen (1 bottles of beer).

Vi sjofer én til i Kotlin før vi runder av med et par .NET-løsninger helt til slutt:

Denne utvikleren har innført konseptet bottleText for å angi antallet flasker, og ellers er det ganske rett frem og fint. Det er holdt god styr på vers og antall flasker og den siste linja er såpass spesiell at den har fått sin egen if-sjekk.

Personlig ville jeg nok ha foretrukket det vanligste tilfellet først i if-sjekken, men det blir muligens litt i overkant Pirkelunden Mannskor av meg å melde på en ellers finfin løsning.

Et språk jeg ikke ser så mye til (lenger) er F#, og denne neste løsningen var et gledelig gjensyn, for etter at jeg har jobbet en del med Elm var det nå ganske mye lettere forstå enn forrige gang jeg prøvde meg på F#:

Syntaksen i F# kan være litt heftig når man ikke er vant til det, men det som slår meg mest av alt med denne løsningen er hvor lik den er den forrige Kotlin-løsningen vi så på.

Her er det brukt rekursjon for å oppnå iterasjon (som man vel nesten i F#?), men bortsett fra det er den nesten identisk. Én ekstra funksjon for å få en beskrivelse av antallet flasker, og ellers skriver den ut den første linja først, og har en egen sjekk for hvilken versjon av siste linja det er.

Jeg vil tippe at det er stor spredning i hvilken av disse to siste man liker best basert på hva man har jobbet med tidligere og hva man altså er vant til. Det er imidlertid gøy å merke seg at det så og si er identiske løsninger, bare i to ganske så forskjellige språk.

Som en bonus helt på slutten skal vi se på den oppgaven som skilte seg klart mest fra de andre. Det var nemlig “Sangomaten!” Her har utvikleren slått seg løs og lagt en liten console-app i C# med input-validering og en temmelig lettbeint stil:

Denne skapte riktig så god stemning i faggruppemøtet. Selve koden for å skrive ut sangen likner litt på de første Javascript-løsningene vi så på, men det er jo ikke det mest spennende her.

Jeg satte pris på å se en Console-app igjen, og fniser fortsatt litt av HeiHalloHelpers.cs. Det ble kommentert at litt velplassert regex hadde gjort selve input-valideringen en god del enklere, men noe sier meg at akkurat røddighet kanskje ikke var aller høyest på agendaen her uansett.

Gøy var det, i hvert fall. Akkurat som resten av faggruppemøtet. Takk for meg.