مقایسه Expression و Statement در برنامه نویسی

در این مقاله به این موضوع اشاره شده که چرا عبارت‌ها (Expression) در برنامه نویسی نسبت به «گزاره‌ها» (Statement) ایمن‌تر هستند و از این طریق، مقایسه Expression و Statement یا همان تفاوت Expression با Statement در برنامه نویسی انجام شده است. برای درک بهتر مفاهیم مطرح شده در این نوشتار، مثال‌هایی به زبان‌های سی‌شارپ و F#‎ ارائه می‌شود.

مقایسه Expression و Statement یا همان تفاوت Expression با Statement در برنامه نویسی

تفاوت Expression با Statement در برنامه نویسی

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

در سی‌شارپ (C#‎) و اکثر زبان‌های دستوری بین عبارت‌ها و گزاره‌ها تمایز وجود دارد و قوانینی در خصوص این مسئله وضع شده است که کدام‌یک در چه موقعیتی قابل استفاده خواهند بود. اما در یک زبان برنامه نویسی تماماً تابعی به هیچ وجه امکان پشتیبانی از گزاره‌ها وجود ندارد؛ زیرا در یک زبان برنامه نویسی واقعاً خالص، هیچ اثر جانبی وجود نخواهد داشت.

مقایسه Expression و Statement در برنامه نویسی F#‎

با وجود اینکه زبان F#‎‎ (اف‌شارپ) خالص نیست، اما از قواعد یکسانی تبعیت می‌کند. در F#‎ همه چیز به عنوان یک عبارت در نظر گرفته می‌شود. نه فقط مقدارها و تابع‌ها، بلکه کنترل جریان (مثل if-then-else و حلقه‌ها) تطبیق الگو و سایر موارد نیز به عنوان یک Expression یا همان عبارت در نظر گرفته می‌شوند.

اصطلاحات برنامه نویسی

مزایای استفاده از Expression به جای Statement چه هستند؟

در استفاده از عبارت‌ها به جای گزاره‌ها، برخی مزایای پنهان و جزئی وجود دارند و اول اینکه بر خلاف گزاره‌ها، عبارت‌های کوچک‌تر را می‌توان به عبارت‌های بزرگ‌تر ترکیب (Combine | Compose) کرد. بنابراین، اگر همه چیز به صورت عبارت یا همان Expression باشد، آنگاه همه چیز قابل ترکیب هم خواهد بود.

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

بنابراین، مثلاً در عبارت a+b در صورتی که هم بخش a و هم بخش b خالص باشند، آنگاه بخش a را می‌توان جداسازی و درک کرد و آن را مورد آزمایش قرار داد و به خودی خود قابل ارزیابی خواهد بود. همین حقیقت در مورد عبارت b هم صادق است. این قابلیت ایزوله بودن عبارت‌ها، یکی دیگر از جنبه‌های مثبت برنامه نویسی تابعی به حساب می‌آید.

ایمنی بیشتر و فشرده تر بودن Expression نسبت به Statement

استفاده از عبارت‌ها (Expressions) به‌طور دائم باعث می‌شود که کدهای تولید شده هم ایمن‌تر باشند و هم فشردگی آن‌ها بیش‌تر باشد. در ادامه توضیحات بیش‌تری همراه با مثال برای درک بهتر این مسئله ارائه شده است.

ابتدا بهتر است رویکرد مبتنی بر گزاره‌ها (Statement) را بررسی کرد. گزاره‌ها هیچ مقداری را برنمی‌گردانند، بنابراین برنامه نویس ناچار به استفاده از متغیرهای موقتی خواهد بود که از داخل بدنه گزاره‌ها تخصیص داده می‌شوند. در ادامه مثال‌هایی با استفاده از زبان برنامه نویس C#‎ ارائه شده است:

public void IfThenElseStatement(bool aBool)
{
   int result;     //what is the value of result before it is used?
   if (aBool)
   {
      result = 42; //what is the result in the 'else' case?
   }
   Console.WriteLine("result={0}", result);
}

مشکلات استفاده از Statement کدامند؟

به دلیل اینکه «if-then» یک گزاره است، متغیر result باید خارج از گزاره تعریف ولی تخصیص آن در داخل گزاره انجام شود. این مسئله منجر به بروز برخی مشکلات خواهد شد:

  • متغیر result باید در خارج از گزاره راه‌اندازی شود. در این صورت، مقدار اولیه ان چه باید باشد؟
  • ممکن است برنامه نویس فراموش کند تخصیص متغیر result را در گزاره if انجام دهد. در اینصورت چه اتفاقی رخ خواهد داد؟ هدف گزاره if فقط این است که آثار جانبی داشته باشد (که این اثر جانبی همین تخصیص به متغیر است). این یعنی گزاره‌ها پتانسیل اشکال داشتن یا به اصطلاح Buggy بودن را دارند، زیرا احتمال فراموش کردن تخصیص دادن در یک شاخه معمولاً بالا است. به این دلیل که تخصیص دادن تنها یک اثر جانبی بوده است، کامپایلر نمی‌تواند هیچ اخطاری صادر کند. با توجه به اینکه متغیر result پیش از این در محدوده مربوطه تعریف شده است، ممکن است کامپایلر از این متغیر استفاده کند، بدون اینکه از نامعتبر بودن آن اطلاع داشته باشد.

Statement در برنامه نویسی

  • در مورد حالت else مقدار متغیر result چه خواهد بود؟ در شرایطی که مقداردهی برای متغیر result انجام نشده است، آیا فراموش شده است که این کار انجام شود؟ آیا این یک ایراد بالقوه است؟
  • در نهایت، تکیه بر اثرهای جانبی برای انجام دادن وظایف مورد نظر به این معنی است که گزاره‌ها به راحتی در قالبی دیگر قابل استفاده نخواهند بود. برای مثال نمی‌توان آن‌ها را برای سازماندهی مجدد کدها (Refactoring) یا موازی‌سازی مورد استفاده قرار داد. دلیلش این است که آن‌ها وابستگی به متغیری دارند که جزئی از خود گزاره نیست و خارج از آن تعریف شده است.

باید توجه داشت که کدهای فوق در C#‎ کامپایل نخواهند شد، زیرا اگر برنامه نویس از یک متغیر محلی تخصیص داده نشده مثل result استفاده کند، کامپایلر خطا صادر خواهد کرد. اما تعریف تعدای مقدار پیش‌فرض برای result پیش از آنکه حتی استفاده شده باشد، همچنان یک معضل به حساب می‌آید. برای مقایسه Expression و Statement در برنامه نویسی ، در ادامه همان کدها این بار با استفاده از روش مبتنی بر عبارت یا همان Expession بازنویسی شده‌اند:

public void IfThenElseExpression(bool aBool)
{
    int result = aBool ? 42 : 0;
    Console.WriteLine("result={0}", result);
}

برتری Expression نسبت به Statement در برنامه نویسی

در نسخه مبتنی بر عبارت، هیچ یک از مشکلات و مسائلی که پیش‌تر مطرح شدند اتفاق نخواهند افتاد:

  • متغیر result در همان زمانی که تعریف می‌شود، تخصیص هم داده می‌شود. هیچ متغیری نباید در خارج عبارت مربوطه تعریف و راه‌اندازی شود و هیچ نگرانی بابت مقداردهی اولیه آن‌ها وجود نخواهد داشت.
  • عبارت else هم به‌طور صریح و واضح مدیریت می‌شود. در این روش، هیچ شانسی وجود ندارد که فرد اختصاص دادن مقدار به متغیر را در یکی از شاخه‌ها فراموش کند.
  • به هیچ عنوان امکان فراموش کردن تخصیص result وجود نخواهد داشت زیرا این متغیر وجود خارجی ندارد.

در F#‎ این دو مثال به صورت زیر نوشته خواهند شد:

let IfThenElseStatement aBool =
   let mutable result = 0       // mutable keyword required
   if (aBool) then result <- 42
   printfn "result=%i" result

کلمه کلیدی «mutable» به عنوان یک «Code Smell» در F#‎ در نظر گرفته می‌شود و استفاده از آن به غیر از برخی موارد خاص توصیه نمی‌شود. در حین یادگیری باید تا حد امکان از آن‌ اجتناب کرد.

در نسخه مبتنی بر عبارت این مثال به زبان F#‎، متغیر mutable حذف شده است و در هیچ‌کجا تخصیص مجددی وجود ندارد:

let IfThenElseExpression aBool =
   let result = if aBool then 42 else 0
                // note that the else case must be specified
   printfn "result=%i" result

پس از آنکه گزاره if به یک عبارت تبدیل شد، آنگاه به راحتی می‌توان سازماندهی مجدد کدها یا همان Refactor کردن آن‌ها را به راحتی انجام داد و بدون بروز هیچ نوع خطایی، تمام زیرعبارت را به زمینه و بافت دیگری انتقال داد. در ادامه نسخه سازماندهی مجدد شده (Refactor شده) کدها به زبان C#‎ آمده است:

public int StandaloneSubexpression(bool aBool)
{
    return aBool ? 42 : 0;
}

public void IfThenElseExpressionRefactored(bool aBool)
{
    int result = StandaloneSubexpression(aBool);
    Console.WriteLine("result={0}", result);
}

اکنون همین کدهای بالا به زبان F#‎ در ادامه ارائه شده‌اند:

let StandaloneSubexpression aBool =
   if aBool then 42 else 0

let IfThenElseExpressionRefactored aBool =
   let result = StandaloneSubexpression aBool
   printfn "result=%i" result

جمع‌بندی

به این ترتیب، مقایسه Expression و Statement در برنامه نویسی و به نوعی تفاوت Expression با Statement در این مقاله شرح داده شد و برای مقایسه بهتر و درک بیش‌تر تفاوت‌های این دو موجودیت، مثال‌هایی به زبان‌های سی‌شارپ و اف‌شارپ (F#‎) ارائه شدند. امید است این مقاله مفید واقع شود.

اگر این مطلب مفید بوده است، استفاده از دوره‌های آموزشی و مقالات زیر نیز پیشنهاد می‌شوند:

 

منبع [+]

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *