[018] 好的函數不會有「副作用」

一個設計良好的函數(Function),不應該產生「副作用(Side Effect)」。

以下函數回傳二個輸入整數相加的結果:

int Add(int a, int b) {
  return a + b;
}

函數 Add 不管呼叫幾次,傳入的參數值相同,得到的結果永遠一致。舉個反例:

int Calc(int a, int b) {
  static bool do_add = true;
  
  int result = 0;
  if (do_add)
    result = a + b;
  else
    result = a - b;
  
  do_add = !do_add;
  return result;
}

第一次呼叫函數 Calc 做加法,第二次則做減法(奇數做加法,偶數做減法)。呼叫此函數產生的副作用導致下一次用相同參數呼叫該函數與前次得到不同的結果,這樣的行為表示該函數有「內部狀態」,該狀態呼叫端不得而知,故該函數的運算結果無法預期。

我認為這是一種設計不良的函數,應儘量避免寫出這類函數。

無副作用函數的好處有:

  • 較容易應用在平行化/多緒處理的情境
  • 容易維護與修改(只要保證「輸入、運算、輸出」的結果不變即可)

有狀態的函數,很有資格設計成類別。「物件有狀態」很自然,函數有狀態則不是好事。