কম্পিউটার

রুবিতে গ্রাম্য নিল হ্যান্ডলিং

গত ছয় মাস ধরে আমি মরিচায় একটি 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 প্রতিরোধ করতে পারে যে সবসময় উৎপাদনে স্খলিত হয়। এটি দেখতে কিছুটা কষ্টকর, এবং খুব রুবিশ নয় তবে আমি কল্পনা করি যে কিছু পরিমার্জন করলে একটি আরও মনোরম বাক্য গঠন হবে৷


  1. সিএসএস ব্যবহার করে উপচে পড়া বিষয়বস্তু পরিচালনা করা

  2. রুবিতে বিটওয়াইজ হ্যাক

  3. রুবিতে ল্যাম্বডাস ব্যবহার করা

  4. রুবি 2.6-এ 9টি নতুন বৈশিষ্ট্য