اثر جانبی (علوم رایانه)

در علوم رایانه، اگر یک عملیات، تابع یا عبارت بتواند مقدار متغیرهای حالت را خارج از دامنهٔ خود تغییر دهد؛ دارای اثر جانبی  است. به‌عبارت دیگر عملیات شامل یک اثر قابل مشاهده، علاوه‌بر بازگرداندن مقدار (اثر اصلی) به تابع فراخوانی‌کننده است. داده‌های حالت که «بیرون» از عملیات به‌روز می‌شوند، ممکن است «داخل» یک شیء حالت‌دار یا یک سیستم گسترده‌تر مقدار بگیرند. مثال‌هایی از اثر جانبی شامل مقداردهی یک متغیر غیر محلی، مقداردهی یک متغیر محلی استاتیک، تغییر مقدار یک آرگومان ورودی قابل تغییر است که به‌وسیلهٔ ارجاع به تابع پاس داده شده باشد. همچنین انجام عملیات ورودی/خروجی یا فراخوانی سایر توابع دارای اثر جانبی، از مثال‌های این مفهوم به‌شمار می‌روند. در صورت وجود اثر جانبی، ممکن است رفتار یک برنامه به تاریخچه بستگی داشته باشد؛ یعنی ترتیب ارزیابی اهمیت دارد. درک و اشکال زدایی یک تابع با اثر جانبی، مستلزم آگاهی از زمینه و تاریخچه‌های احتمالی آن است.

میزان استفاده از اثر جانبی به زبان برنامه‌نویسی بستگی دارد. در برنامه‌نویسی دستوری استفاده از اثر جانبی جهت به‌روزرسانی حالت سیستم متداول است. در مقابل، در برنامه‌نویسی اعلانی اغلب وضعیت سیستم، بدون به‌وجود آمدن اثرات جانبی، گزارش می‌شود.

در برنامه‌نویسی تابعی اثر جانبی به‌ندرت استفاده می‌شود. عدم وجود اثر جانبی، انجام درستی‌یابی صوری یک برنامه را آسان‌تر می‌کند. زبانهای کاربردی مانند Standard ML، Scheme و اسکالا عوارض جانبی را ممنوع نمی‌کنند، اما برای برنامه‌نویسان این زبان‌ها، خودداری از ایجاد اثر جانبی مرسوم است. ربان تابعی هسکل اثرات جانبی مانند عملیات ورودی/خروجی و دیگر محاسبات حالت‌دار را با استفاده از مونادها مشخص می‌کند.

برنامه نویسان زبان اسمبلی باید از اثرات جانبی پنهان آگاه باشند - دستورالعمل‌هایی که بخش‌هایی از حالت پردازنده را تغییر می‌دهد و در دستورالعمل ذکر نشده‌اند. یک مثال کلاسیک از یک اثر جانبی پنهان یک دستورالعمل حسابی است که به‌طور ضمنی کدهای وضعیت را تغییر می‌دهد (یک اثر جانبی پنهان) در حالی که صریحاً یک ثبات را تغییر می‌دهد (اثر آشکار). یکی از اشکالات بالقوه یک مجموعه دستورالعمل با عوارض جانبی پنهان این است که اگر تعداد زیادی از دستورالعمل‌ها اثر جانبی روی یک حالت مشترک داشته باشند، ممکن است منطق موردنیاز برای به‌روزرسانی آن حالت (مانند کد وضعیت) به یک تنگنا در کارایی تبدیل شود. این مشکل به‌خصوص در برخی از پردازنده‌های طراحی شده با بهینه‌سازی خط لوله (از سال ۱۹۹۰) یا با اجرای خارج ترتیب رایج است. چنین پردازنده‌ای ممکن است برای تشخیص اثرات جانبی پنهان نیاز به مدارات بیشتری داشته باشد؛ یا در صورتی که نتیجهٔ عملیات به اثرات جانبی متکی باشد، حتی ممکن است خط لوله را متوقف کند.

شفافیت مرجع 
عدم وجود اثر جانبی شرط لازم برای شفافیت مرجع است، اما کافی نیست. شفافیت مرجع به این معنی است که می‌توان یک عبارت (مانند فراخوانی تابع) را با مقدار آن جایگزین کرد. این امر مستلزم این است که این عبارت سره باشد، به این معنی که این عبارت باید قطعی بوده (همیشه برای همان ورودی مقدار یکسانی داشته باشد) و اثر جانبی نداشته باشد.

اثر جانبی موقتی 
معمولاً هنگام بحث دربارهٔ اثر جانبی و شفافیت مرجع، اثرات جانبی ناشی از مدت زمان لازم برای اجرای عملیات فعلی نادیده گرفته می‌شود. همچنین در مواردی مانند «زمانبندی سخت‌افزار» یا «تست»، عملیات دارای اثر جانبی، به‌طور ویژه به دلیل اثر جانبی موقتی آن‌ها به برنامه اضافه می‌شوند. مانند  sleep(5000)یاfor (int i = 0; i <10000; ++i) {}‪ ‬این دستورها وضعیت را تغییر نمی‌دهند با این حال صرفاً برای اتلاف زمانی که جهت اجرای آن‌ها نیاز است، استفاده می‌شود.

تکرارشوندگی 
تابع f با اثر جانبی، تحت ترکیب متوالی f; f «تکرار شونده» است اگر بعد از دو بار فراخوانی با مقادیر یکسان، اثر جانبی نداشته، و فراخوانی دوم مقداری برابر با فراخوانی اول داشته باشد. (با فرض این که میان دو فراخوانی، هیچ تابع دیگری صدا زده نشده‌است)

به عنوان نمونه کد پایتون زیر را در نظر بگیرید: x = 0

def setx(n):
    global x
    x = n

setx(5)
setx(5) در اینجا، تابع setx تکرارشونده است زیرا فراخوانی دوم به setx (با همان مقادیر) حالت مشهود برنامه را تغییر نمی‌دهد: x در اولین فراخوانی مقدار ۵ داشت، و در فراخوانی دوم باز هم مقدار ۵ می‌گیرد. توجه داشته باشید که این مفهوم، با تکرارشوندگی تحت ترکیب ترکیب توابعf ∘ f متفاوت است. به عنوان تابع، قدر مطلق تحت ترکیب تکرار شونده است: def abs(n):
    if n <0:
        return -n
    else:
        return n

abs(-5) == abs(abs(-5)) == abs(5) == 5

مثال 
یکی از مثال‌های متداول اثر جانبی، عملکرد اپراتور واگذاری در C++ است. به عنوان مثال، تابع انتساب، عملوند راست را برمی‌گرداند در حالی که تأثیر جانبی روی مقداردهی به یک متغیر دارد. این ویژگی به مقداردهی‌های چندگانه کمک می‌کند: int i, j;
i = j = 3; به دلیل این که وابستگی عملگر انتساب، راست به چپ است، این عبارت هم‌ارز عبارت زیر است: int i, j;
i = (j = 3); // ‫عبارت j = 3 مقدار 3 را برمی‌گرداند که در ادامه به i انتساب می‌شود‬ در حالی که نتیجهٔ انتساب عدد ۳ به متغیر j، بعداً به متغیر i اختصاص می‌یابد. این برای برنامه‌نویسان مبتدی سردرگم‌کننده است. while (b == 10) {} // ‫بررسی می‌کند که آیا b به مقدار 10 ارزیابی می‌شود یا خیر‬باwhile (b = 10) {} // ‫عملگر = مقدار 10 را برمی‌گرداند. که به‌صورت خودکار به true ارزیابی می‌شود، بنابراین شرط همیشه صادق است‬

جستارهای وابسته 
 نقطه دنباله
 عملیات از راه دور (علم کامپیوتر)
 عبارت بی‌اهمیت
 حملهٔ کانال جانبی

منابع 

برنامه‌نویسی تابعی
برنامه‌نویسی
نظریه زبان‌های برنامه‌نویسی