Biverkning (datavetenskap)

Inom datavetenskap sägs en operation, funktion eller uttryck ha en bieffekt om den modifierar något/något tillståndsvariabelvärde utanför sin lokala miljö, det vill säga om det har någon annan observerbar effekt än dess primära effekt av att returnera en värde för den som anropar åtgärden. Exempel på bieffekter inkluderar modifiering av en icke-lokal variabel , modifiering av en statisk lokal variabel , modifiering av ett föränderligt argument som skickas med referens , utför I/O eller anrop av andra funktioner med biverkningar. I närvaro av biverkningar kan ett programs beteende bero på historien; det vill säga ordningen på utvärderingen har betydelse. Att förstå och felsöka en funktion med biverkningar kräver kunskap om sammanhanget och dess möjliga historia.

Biverkningar spelar en viktig roll vid design och analys av programmeringsspråk . I vilken grad biverkningar används beror på programmeringsparadigmet. Till exempel, imperativ programmering används ofta för att skapa biverkningar, för att uppdatera ett systems tillstånd. Däremot deklarativ programmering vanligtvis för att rapportera om systemets tillstånd, utan biverkningar.

Funktionell programmering syftar till att minimera eller eliminera biverkningar. Bristen på biverkningar gör det lättare att göra formell verifiering av ett program. Det funktionella språket Haskell eliminerar biverkningar som I/O och andra statistiska beräkningar genom att ersätta dem med monadiska handlingar. Funktionella språk som Standard ML , Scheme och Scala begränsar inte biverkningar, men det är vanligt att programmerare undviker dem.

Assembly språkprogrammerare måste vara medvetna om dolda bieffekter – instruktioner som ändrar delar av processorns tillstånd som inte nämns i instruktionens minnesminne. Ett klassiskt exempel på en dold bieffekt är en aritmetisk instruktion som implicit modifierar villkorskoder (en dold bieffekt) medan den explicit modifierar ett register (den avsedda effekten). En potentiell nackdel med en instruktionsuppsättning med dolda biverkningar är att om många instruktioner har biverkningar på ett enda tillstånd, som tillståndskoder, så kan logiken som krävs för att uppdatera det tillståndet sekventiellt bli en prestandaflaskhals. Problemet är särskilt akut på vissa processorer designade med pipelining (sedan 1990) eller med out-of-order exekvering . En sådan processor kan kräva ytterligare styrkretsar för att upptäcka dolda biverkningar och stoppa pipelinen om nästa instruktion beror på resultaten av dessa effekter.

Referenstransparens

Frånvaro av biverkningar är ett nödvändigt, men inte tillräckligt, villkor för referenstransparens. Referenstransparens innebär att ett uttryck (som ett funktionsanrop) kan ersättas med dess värde. Detta kräver att uttrycket är rent , det vill säga uttrycket måste vara deterministiskt (alltid ge samma värde för samma input) och biverkningsfritt.

Tidsmässiga biverkningar

Biverkningar som orsakas av den tid det tar för en operation att utföra ignoreras vanligtvis när man diskuterar biverkningar och referenstransparens. Det finns vissa fall, som med hårdvarutid eller testning, där operationer infogas specifikt för deras tidsmässiga biverkningar, t.ex. sleep(5000) eller för (int i = 0; i < 10000; ++i) {} . Dessa instruktioner ändrar inte tillstånd annat än att det tar en tid att slutföra.

Idempotens

En subrutin med biverkningar är idempotent om flera applikationer av subrutinen har samma effekt på systemtillståndet som en enda applikation, med andra ord om funktionen från systemtillståndsutrymmet till sig själv som är associerat med subrutinen är idempotent i matematisk mening . Tänk till exempel på följande Python- program:

  0

 
     
      


   

    x  =  def  setx  (  n  ):  global  x  x  =  n  setx  (  3  )  hävda  x  ==  3  setx  (  3  )  hävda  x  ==  3 

setx är idempotent eftersom den andra applikationen av setx till 3 har samma effekt på systemtillståndet som den första applikationen: x var redan inställd på 3 efter den första applikationen och den är fortfarande inställd på 3 efter den andra applikationen.

En ren funktion är idempotent om den är idempotent i matematisk mening . Tänk till exempel på följande Python-program:

 
         0  

    def  abs  (  n  ):  returnera  -  n  om  n  <  else  n  assert  abs  (  abs  (  -  3  ))  ==  abs  (  -  3  ) 

abs är idempotent eftersom den andra appliceringen av abs på returvärdet för den första applikationen till -3 returnerar samma värde som den första applikationen till -3.

Exempel

En vanlig demonstration av biverkningsbeteende är den hos uppdragsoperatören i C . Tilldelningen a = b är ett uttryck som värderas till samma värde som uttrycket b , med bieffekten att R-värdet för b lagras i L-värdet för a . Detta tillåter flera tilldelningar:

       a  =  (  b  =  3  );  // b = 3 utvärderas till 3, som sedan tilldelas till a 

Eftersom operatörsrätten associerar motsvarar detta

     a  =  b  =  3  ; 

Detta utgör ett potentiellt stopp för nybörjare som kan förvirra

       medan  (  b  ==  3  )  {}  // testar om b utvärderas till 3 

med

       medan  (  b  =  3  )  {}  // b = 3 utvärderas till 3, som sedan kastar till sant så att slingan är oändlig 

Se även