ในการเขียนโปรแกรมที่เกี่ยวข้องกับนิพจน์ ในบางครั้งก็อาจเกิดปัญหา Side effect (ผลกระทบซึ่งเราไม่ทราบ) ปัญหานี้จะทำให้โปรแกรมเมอร์ debug โปรแกรมไม่ได้ หากไม่เข้าใจถึงผลกระทบที่เกิดขึ้น ปัญหานี้มักเกี่ยวข้องกับเรียกใช้งานฟังก์ชั่นในโปรแกรมซึ่งเราเรียกว่าเกิด Functional side effect
นิพจน์ (expression)
result = A * B + myfunction( ) + 20;
1. เมื่อนิพจน์ (expression) มีการเรียกใช้ฟังก์ชั่น โปรแกรมเมอร์ทราบหรือไม่ว่าภาษาการโปรแกรมนั้นการประเมินผลนิพจน์จะยังคงพิจารณาตาม Precedence rule และ Associativity หรือจะต้องพิจารณาการเรียกฟังก์ชั่นร่วมด้วย เช่น ต้องเรียกก่อนค่อยประเมินนิพจน์ตาม Precedence rule และ Associativity
คำตอบ ถ้าไม่ทราบต้องไปดู Specification ของภาษา แต่ละภาษาอาจไม่เหมือนกัน ส่วนใหญ่ภาษามักกำหนดให้เรียกฟังก์ชั่นให้เสร็จก่อน แล้วค่อยประเมินนิพจน์
2. ถ้าการเรียกฟังก์ชั่นมีการแก้ไขค่าของตัวแปรที่ปรากฎในนิพจน์ เช่น ตัวแปร A หรือ B (สมมติ A หรือ B เป็น Nonlocal variable ที่ฟังก์ชั่นสามารถเข้าถึงได้ ดังนั้นลำดับการเรียกฟังก์ชั่นก่อนและหลังจะมีผลต่อผลลัพธ์หรือไม่ ?
คำตอบ มีแน่นอน สมมติว่าเรียกฟังก์ชั่นก่อน ดังนั้นค่า A และ B ที่อาจเกิดการแก้ไขจะเป็นค่าหลังจากเรียกฟังก์ชั่น ถ้าเรียกฟังก์ชั่นภายหลัง (ทำตาม Precedence rule และ Associativity ตามปกติ) ค่า A และ B ในนิพจน์จะเป็นค่าก่อนเรียกฟังก์ชั่น และต้องจำไว้ว่าในบรรทัดถัดไปจะใช้ค่า A และ B จะเป็นค่าใหม่ที่ถูกแก้ไขแล้ว
สาเหตุจาก Functional Side Effect จึงมาจาก 2 กรณี
1. การเรียกฟังก์ชั่นในนิพจน์ที่มีการแก้ไขค่าของตัวแปร Nonlocal variable ในนิพจน์
#include <stdio.h>
int A = 20, B=5;
void main( ){
result = A * B + myfunction( ) + 20;
...
}
int myfunction( ){
A = A +10 ;
....
return A;
}
เมื่อโปรแกรมเมอร์ทั่วไปที่ไม่ทราบปัญหา Functional side effect จะเข้าใจว่าตัวแปร result จะมีค่าเป็น 150
result (150) = 20 * 5 + 30 + 20
แต่ความจริงแล้วเป็น 200
result (200) = 30 * 5 + 30 + 20
void main( ){
int A = 20, B = 5;
result = A * B + myfunction (&A) + 20;
}
void myfunction(int *p){
*p = *p + 10;
}
ความเข้าใจจะเหมือนกรณีแรก
วิธีแก้ไข
พยายามหลีกเลี่ยงการเขียนโค้ดในลักษณะนี้ หากไม่แน่ใจว่าภาษาการโปรแกรมจะมีลำดับการประเมินผลอย่างไร เมื่อมีการเรียกฟังก์ชั่นในนิพจน์ ?
อาจจัดเรียงนิพจน์ใหม่ เช่น
result = A * B + 20;
result = result + myfunction( );
หรือ
result = result =+ myfunction(&A);
ซึ่งเมื่อเรียงใหม่ค่า A ที่นำไปคูณกับ B จะมีค่าเท่ากับ 20 ตามความเข้าใจแรกเริ่ม
Referential transparency
สมมติ
result1 = (myfunction (A) + B) / (myfunction (A) - C);
temp = myfunction(A);
result2 = (temp + B) / (temp - C);
ถ้าการเรียกฟังก์ชั่นไม่มีการแก้ไขค่าตัวแปรใดๆ (A , B, C) ที่เกี่ยวข้องกับนิพจน์ คำสั่งบรรทัดแรกและบรรทัดที่สาม น่าจะได้ผลลัพธ์เดียวกัน เนื่องจากไม่เกิด Functional side effect
เราจะเรียกว่าโปรแกรมมีคุณสมบัติ Referential transparency
แต่ถ้าเกิดเรียกฟังก์ชั่นในบรรทัดแรกมีการแก้ไขค่า A, B หรือ C จากการเรียกฟังก์ชั่นแล้ว ผลลัพธ์จากคำสั่งในบรรทัดแรก และบรรทัดสุดท้ายจะไม่เท่ากันทันที
No comments:
Post a Comment