ترفند ریوبی: تشخیص آرگومان مفقود از مقدار 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) را دقیقتر تعریف کنیم، از باگهای ظریف جلوگیری نماییم و کدی خواناتر و بدون نیاز به متغیرهای کمکی اضافی یا شیءهای نگهبان بنویسیم.
این مطلب بهصورت کاملاً خودکار و با هوش مصنوعی از مقالهٔ اصلی و بحث هکرنیوز تهیه شده و ممکن است خطا داشته باشد. حقوق مطلب اصلی متعلق به نویسندهٔ آن است. قوانین و گزارش مشکل