গত ছয় মাস ধরে আমি মরিচায় একটি NES এমুলেটর কাজ করছি। আপনি যেমন আশা করতে পারেন, আমি মরিচা সম্পর্কে অনেক কিছু শিখেছি এবং NES অভ্যন্তরীণ সম্পর্কে আরও অনেক কিছু শিখেছি। কিন্তু অভিজ্ঞতাও রুবিকে দেখার দৃষ্টিভঙ্গি বদলে দিয়েছে।
বিশেষত, এটি আমাকে nil
ফেরত দেওয়া পদ্ধতি সম্পর্কে একটু বেশিই পাগল করে তুলেছে .
আপনি যদি কিছুর জন্য না দাঁড়ান তবে আপনি যেকোনো কিছুর জন্য পড়ে যাবেন
nil
কি করে রুবি মানে? প্রায় কিছু. যখন একটি পদ্ধতি শূন্য প্রদান করে, তখন এর অর্থ হতে পারে:
- পদ্ধতিটির কোনো রিটার্ন মান নেই
- সাধারণত একটি রিটার্ন মান থাকে কিন্তু এইবার নয়
- এটি ডাটাবেস থেকে একটি মান প্রদান করে, যা NULL
- অপ্রত্যাশিত কিছু ঘটেছে
এটি কোড পড়া কঠিন করে তোলে এবং এটি সবচেয়ে সাধারণ এর প্রধান কারণ রুবিতে রুবি ব্যতিক্রম:NoMethodError
. একটি ব্যতিক্রম পর্যবেক্ষণ পরিষেবার অংশ-মালিক হিসাবে, NoMethodError
আমার বাচ্চাকে স্কুলে ভর্তি করাচ্ছে।
নিচের কোডটি দেখুন। এটি nil
প্রদান করে বেশিরভাগ সময় কারণ if
বিবৃতি nil
এ মূল্যায়ন করা হয় যখন কন্ডিশনাল মেলে না এবং কোন else
নেই .
def color_name(rgb)
if rgb == 0x000000
"black"
end
end
color_name("#FFFFFF").titleize
=> NoMethodError: undefined method `titleize' for nil:NilClass
আপনি যদি একজন অভিজ্ঞ রুবি বিকাশকারী হন তবে আপনি জানেন যে এই খরগোশের গর্তটি আরও গভীরে যায়। কখনও কখনও শূন্যের এই ভিন্ন অর্থগুলি অদ্ভুত উপায়ে ওভারল্যাপ করে, এটি জানা অসম্ভব করে তোলে — উদাহরণস্বরূপ — একটি ডাটাবেসের একটি মান NULL
কিনা। , অথবা ডাটাবেসের কোন মূল্য নেই।
একটি ভালো উপায়
মরিচা-এ nil
বলে কিছু নেই . পরিবর্তে, যখন আমরা বোঝাতে চাই যে একটি ফাংশন কখনও কখনও একটি মান প্রদান করে এবং কখনও কখনও "কিছুই না" প্রদান করে তখন আমরা একটি Option
ব্যবহার করি .
Option
এমন একটি প্রকার যা হয় কিছু নির্দিষ্ট মান ধারণ করে, বা কোনো মান নেই। কোডে তারা দেখতে কেমন তা এখানে:
Option::Some(42); // Wraps the number 42 in an option
Option::None; // Indicates "no result"
এটি ইতিমধ্যেই আমাদের অ্যাড-হক nil
এর চেয়ে ভাল দেখাচ্ছে ব্যবহার, কিন্তু এটি আরও ভাল পায়। মরিচা কম্পাইলার আপনাকে None
বিবেচনা করতে বাধ্য করে মামলা আপনি ঘটনাক্রমে এটি উপেক্ষা করতে পারবেন না।
match my_option {
Some(x) => do_something_with_x(x),
// If you remove the `None` match below, this code
// won't compile.
None => do_the_default_thing()
}
তাই আমরা আমাদের রঙের নামকরণের উদাহরণটি এভাবে মরিচায় লিখতে পারি:
fn color_name(rgb: u32) -> Option<String> {
if rgb == 0x000000 {
Some("black".to_owned())
} else {
None
}
}
এখন আমরা Some
উভয়ই পরিচালনা করতে বাধ্য হচ্ছি এবং None
শর্তাবলী:
let name = color_name(0xFFFFFF);
let name = match color_name(0xFFFFFF) {
Some(value) => value,
None => "unknown".to_owned(),
}
নিশ্চিতভাবেই এটি দেখতে কিছুটা ভার্বস এবং অদ্ভুত, কিন্তু যখন একটি ফাংশন একটি দরকারী মান প্রদান করে না তখন এটি কেসটিকে উপেক্ষা করা অসম্ভব করে তোলে৷ এর মানে কোড যা বোঝা এবং বজায় রাখা সহজ৷
রুবিতে প্রয়োগ করার বিকল্প
রুবির কি কঠোরতার অভাব রয়েছে তা নমনীয়তার জন্য তৈরি করে। আমি ভেবেছিলাম Option
এর মত কিছু বাস্তবায়ন করার চেষ্টা করা আকর্ষণীয় হবে রুবিতে।
আমরা রুবিতে কম্পাইল-টাইম ত্রুটি তৈরি করতে পারি না, যেহেতু এটি একটি ব্যাখ্যা করা ভাষা। কিন্তু আমরা ভুল কোড সর্বদা করতে পারি আপনি একটি প্রান্তের ক্ষেত্রে আঘাত করলে শুধুমাত্র একটি ব্যতিক্রম উত্থাপন করার পরিবর্তে একটি ব্যতিক্রম উত্থাপন করুন৷
প্রথমে দুটি ক্লাস তৈরি করা যাক। Some
একটি পঠনযোগ্য মান ধারণ করে। None
খালি. এগুলি যতটা সহজ মনে হয় ততটাই সহজ৷
class Some
attr_reader :value
def initialize(value)
@value = value
end
end
class None
end
এরপর, আমরা আমাদের Option
তৈরি করব ক্লাস যা হয় Some
ধারণ করে অথবা None
এবং যখন আমরা উভয়ের জন্য হ্যান্ডলার সরবরাহ করি তখনই আমাদের সেগুলি অ্যাক্সেস করতে দেয়৷
class Option
def initialize(value)
@value = value
end
def self.some(value)
self.new(Some.new(value))
end
def self.none()
self.new(None.new)
end
def match(some_lambda, none_lambda)
if @value.is_a?(Some)
some_lambda.call(@value.value)
elsif @value.is_a?(None)
none_lambda.call()
else
raise "Option value must be either Some or None"
end
end
end
অবশেষে, আমরা নতুন Option
ব্যবহার করার জন্য আমাদের রঙের উদাহরণ পুনরায় লিখতে পারি ক্লাস:
def color_name(rgb)
if rgb == 0x000000
Option.some("black")
else
Option.none()
end
end
puts color_name(0x000000).match(
-> value { value },
-> { "no match" })
# Prints "black"
উপসংহার
আমি এখনও একটি বাস্তব প্রকল্পে এই কৌশলটি চেষ্টা করেছি। আমি মনে করি এটি অবশ্যই অনেকগুলি NoMethodErrors
প্রতিরোধ করতে পারে যে সবসময় উৎপাদনে স্খলিত হয়। এটি দেখতে কিছুটা কষ্টকর, এবং খুব রুবিশ নয় তবে আমি কল্পনা করি যে কিছু পরিমার্জন করলে একটি আরও মনোরম বাক্য গঠন হবে৷