Omutbara datatyper med NET

I veckan kom en stor nyhet från NET Framework utvecklarna , Immutable Collections släpptes i skarp version på Nuget.

Så vad är en omutbar typ och när är det bra? Om du är NET eller javautvecklare har du förhoppningsvis koll på att bland andra String och DateTime typerna är omutbara vilket innebär att de aldrig kan ändra värde efter att de har initierats. Omutbara typer kan ha  metoder för manipulering men returnerar alltid nya objekt, exempelvis ToUpper(), Substring(),  AddDays() osv. De flesta av oss har någon gång gjort det här enkla misstaget:
myString.Replace("MySql", "MariaDB")
 när vi egentligen menade
myString = myString.Replace("MySql", "MariaDB");
 Några fördelar med omutbara typer är att:

* De är trådsäkra
* De kan återanvändas helt eller delvist

Ett objekt som inte kan ändras kan bara läsas. Alltså kan objektet läsas av många trådar samtidigt utan
konflikt och därmed utan behov av synkronisering. Återanvänding sparar minne (och cpu) genom att variabler med samma värde *kan* referera till samma objekt på heapen. Om du skall skicka ett objekt av typen EventArgs i NET är det resurssnålare att använda EventArgs.Empty än att skapa ett nytt objekt med new EventArgs(). Skillnaden är marginell men handlar det om tillräckligt många events blir det snabbt mätbart. Både java och C# stöder internering av strängar med effekten att två strängreferenser till likadana strängar pekar på samma strängobjekt.

Det är enkelt att skapa egna trådsäkra, omutbara typer. Se bara till att de inte kan muteras! Grundidén är att all data skickas in i konstruktorn som tilldelar readonly fält eller properties. Metoder som manipulerar måste returnera nya objekt. Här är ett exempel:


Det finns inget sätt att ändra ett objekt av typen SquashPlayer, men det går att skapa nya från scratch eller som en kopia av existerande med nytt värde för ranking-fältet.

Omutbara samlingsklasser

Principen här är att varje metod som manipulerar, exempelvis Add() eller Remove(), returnerar en ny samling. Här är ett försök till en omutbar lista:

Listan är omutbar men det finns ett stort prestandaproblem: hela listan kopieras vid Add(). Mycket kopiering blir det! Men den är trådsäker som följande kod demonstrerar:


Observera raden som lägger till en ny spelare. Tilldelningen är atomär. Lästråden kommer att få antingen versionen före eller efter tilldelningen.

Om vi istället hade använt en vanlig lista och synkroniserat med lock(){} runt raden som lägger till en player samt loopen som läser hade vi fått en hel del blockering mellan läs och skrivtrådarna men sluppit en hel del kopierng. Återigen försumbart med så lite data. Om du vill överväga omutbara samlingar i något projekt är det klokast att göra prestandatester med och utan. Generellt kan man säga att skrivoperationer går lite långsammare men blockerar inte läsoperationer.

OrigoDb, ett open-source projekt som jag är engagerad i, stöder datamodellering med omutbara typer. Samlingsklasserna från MS är därför mycket välkomna och ger våra användare mycket nya möjligheter vad det gäller modellering samt ACID stöd helt utan synkronisering mellan läs och skrivtransaktioner.

De nya omutbara samlingsklasserna från MS kräver NET 4.5 och laddas ner via nuget:
Install-Package Microsoft.Bcl.Immutable
  

Skicka en kommentar

Trevligt att du vill dela med dig av dina åsikter! Tänk på att hålla på "Netiketten" och använda vårdat språk.