۱۲ آبان ۱۴۰۵ aha.io ۳ دقیقه مطالعه

ترفند ریوبی: تشخیص آرگومان مفقود از مقدار nil

ترفند ریوبی: تشخیص آرگومان مفقود از مقدار nil — Moment of Ruby: An Argument for Nothing

خلاصه

در زبان Ruby گاهی متدها هم به عنوان مقداردهنده و هم خواننده استفاده می‌شوند. مقاله پیش رو تکنیک ظریفی را بررسی می‌کند که چگونه با استفاده از ارزیابی تنبل آرگومان‌های پیش‌فرض، می‌توان تفاوت میان ارسال مقدار nil یا عدم ارسال آرگومان را تشخیص داد.

مقدمه و زمینه

در توسعه نرم‌افزار با زبان Ruby، الگوی طراحی متدهایی که همزمان به عنوان Getter و Setter عمل می‌کنند بسیار رایج است. در این الگو، اگر به متد مقداری پاس دهید، آن را تنظیم می‌کند و اگر هیچ مقداری پاس ندهید، مقدار فعلی را برمی‌گرداند. این الگو تا زمانی که بخواهیم مقادیری مانند false یا nil را به عنوان مقدار معتبر ذخیره کنیم با چالش مواجه می‌شود.

چالش تشخیص عدم ارسال آرگومان

فرض کنید متدی به شکل زیر داریم:

module Cloakable
  def cloaking(value = nil)
    if value
      @setting = value
    else
      @setting
    end
  end
end

این پیاده‌سازی ساده در نگاه اول کار می‌کند، اما مشکل اینجاست که اگر بخواهیم مقدار false یا nil را تنظیم کنیم، تفاوتی با حالت عدم ارسال آرگومان (cloaking()) نخواهد داشت. بررسی ساده با value.nil? نیز مشکل را حل نمی‌کند، زیرا ارسال صریح nil با عدم ارسال آن یکسان دیده می‌شود.

برای حل این مشکل، معمولاً توسعه‌دهندگان از شیءهای نگهبان (Sentinel Objects) استفاده می‌کنند:

NOT_PROVIDED = Object.new.freeze

def cloaking(value = NOT_PROVIDED)
  unless value.equal?(NOT_PROVIDED)
    @setting = value
  end
  @setting
end

ترفند ظریف Ruby

زبان Ruby ویژگی قدرتمندی دارد: عبارت آرگومان پیش‌فرض فقط زمانی ارزیابی می‌شود که آن آرگومان هنگام فراخوانی متد حذف شده باشد. علاوه بر این، این عبارت می‌تواند شامل یک انتساب (Assignment) باشد.

با استفاده از این ویژگی، می‌توان کدی بسیار تمیزتر نوشت بدون اینکه نیاز به تعریف شیءهای اضافی باشد:

module Cloakable
  def cloaking(value = (nothing_provided = true))
    return @cloaking if nothing_provided
    @cloaking = value
  end
end

مکانیسم عملکرد این ترفند

  • اگر متد را بدون آرگومان صدا بزنید، عبارت داخل پرانتز (nothing_provided = true) اجرا می‌شود و مقدار true به عنوان مقدار پیش‌فرض value در نظر گرفته می‌شود.
  • در این حالت متغیر محلی nothing_provided مقدار true می‌گیرد و بلافاصله مقدار قبلی بازگردانده می‌شود.
  • اگر هر مقداری (حتی false یا nil) به متد ارسال شود، Ruby از ارزیابی عبارت پیش‌فرض صرف‌نظر می‌کند. در نتیجه متغیر nothing_provided به عنوان یک متغیر محلی شناخته می‌شود اما مقدار آن nil خواهد بود چون انتساب هرگز اجرا نشده است.

این الگو در کدهای منبع بزرگ نیز دیده می‌شود؛ برای مثال، متد index_with در Ruby on Rails از روش مشابهی برای تشخیص اینکه آیا بلاک یا مقدار پیش‌فرض داده شده است یا خیر استفاده می‌کند.

چرا این موضوع برای مهندسان اهمیت دارد؟

برای توسعه‌دهندگان بک‌اند و مهندسان نرم‌افزار، نوشتن APIهای تمیز و قابل اعتماد اهمیت بالایی دارد. این تکنیک به ما اجازه می‌دهد قراردادهای متد (Method Contracts) را دقیق‌تر تعریف کنیم، از باگ‌های ظریف جلوگیری نماییم و کدی خواناتر و بدون نیاز به متغیرهای کمکی اضافی یا شیءهای نگهبان بنویسیم.

این مطلب به‌صورت کاملاً خودکار و با هوش مصنوعی از مقالهٔ اصلی و بحث هکرنیوز تهیه شده و ممکن است خطا داشته باشد. حقوق مطلب اصلی متعلق به نویسندهٔ آن است. قوانین و گزارش مشکل

این خبر را با دیگران به اشتراک بگذارید

خبرهای فناوری در قالب پست و ویدیوی کوتاه، در اینستاگرام هکرنیوز بلاگ. به‌زودی
هر خبر به محض انتشار، به‌همراه پادکست روزانه در کانال تلگرام هکرنیوز بلاگ.