What Are Side Effects?

 

A side effect is a state change in the system that survives a function call.

Essentially, anything that changes the state of the system beyond the current call is a side effect.

Example of side effects:

  • Database write
  • Logging
  • Assigning to a class member or setting property
  • Writing to a file
  • Writing to a service

What is not a side effect?

  • Returning a value
  • Throwing an exception
  • Reading from the database
  • Reading a file
  • Reading from a service
  • Assigning to a local variable

Any time we write to something, we create a side effect. When we read, usually we are no generating side effects. Sometimes reads do produce side effects: Recording or logging a read is a side effect.

An example is in order. Here is an implementation of a ShoppingCart:

  public class ShoppingCart
  {
     public decimal Total => Items.Sum(x => x.Subtotal);
     public IList<ShoppingCartItem> Items { get; } = new List<ShoppingCartItem>();

     public void Add(Product product, int quantity)
     {
        Validate(product, quantity);
        Items.Add(new ShoppingCartItem(product, quantity));
     }

     private void Validate(Product product, int quantity)
     {
        if (product == null)
           throw new MissingProduct();
        if (quantity <= 0)
           throw new InvalidQuantity(quantity);
        if (Items.Any(x => x.Product.Name == product.Name))
           throw new ProductAlreadyInCart();
     }  
  }

Add() is causing a side effect. It is altering the state of the Items collection that will persist beyond the scope of Add(). I.e. this change will still be there when Add() returns.

On the other hand, Validate() does not cause side effects. No state is changed. A number of properties are read and an exception may be thrown but the state of ShoppingCart *or any other objects) remain unaltered. 

Why is changing a local variable not considered a side effect?

Local variables are scoped to the subroutine. When it goes out of scope (i.e. it returns or throws an exception), all local variables are lost. 

  public int CalcScore()
  {
     int score = 0;
     for (var i = 0; i < rolls.Length; i++)
        score += rolls[i];
     return score;
  }

CalcScore has two local variables, score and i. i is scoped to the for loop and any value contained in i will not survive when the for loop completes. Local variable score will survive until CalcScore() returns. CalcScore() is not altering program state that outside of itself, and therefore is not creating side effects.

 

 

 

 

 

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply