কম্পিউটার টিউটোরিয়াল

RBS: রুবির নতুন টাইপ অ্যানোটেশন সিস্টেম ব্যাখ্যা

RBS হল রুবির জন্য একটি নতুন টাইপ সিনট্যাক্স ফরম্যাট ভাষা। RBS আপনাকে .rbs এক্সটেনশন والی ফাইলগুলোতে রুবি কোডে টাইপ অ্যানোটেশন যোগ করতে দেয়। সেগুলো এইরকম দেখায়:

class MyClass
  def my_method : (my_param: String) -> String
end

RBS দিয়ে টাইপ অ্যানোটেশন প্রদান করলে আপনি নিম্নলিখিত সুবিধাগুলো পাবেন:

  • কোডবেসের কাঠামো সংজ্ঞায়িত করার একটি সাফ ও সংক্ষিপ্ত উপায়।
  • লিগ্যাসি কোডে টাইপ যোগ করার একটি নিরাপদ উপায়, ক্লাসগুলো সরাসরি পরিবর্তন না করে ফাইলগুলোর মাধ্যমে।
  • স্ট্যাটিক ও ডাইনামিক টাইপ চেকারগুলো সাথে সার্বজনীনভাবে ইন্টিগ্রেট করার সম্ভাবনা।
  • মেথড ওভারলোডিং, ডাক টাইপিং, ডাইনামিক ইন্টারফেস ইত্যাদি মোকাবিলার জন্য নতুন ফিচার।

কিন্তু 잠깐! কি ইতিমধ্যেই Sorbet এবং Steep মতো স্ট্যাটিক টাইপ চেকার আছে না?

হ্যাঁ, সেগুলো দুর্দান্ত! তবে, চার বছরের আলোচনা এবং কমিউনিটি-বিল্ট টাইপ চেকারগুলির একাধিক সংস্করণের পর, রুবি কমিটার টিম মনে করল যে টাইপ চেকার টুল তৈরি করার জন্য কিছু стандарт নির্ধারণ করার সময় এসে গেছে।

RBS офиসিয়ালি একটি ভাষা, এবং রুবি ৩ এর সাথে এসে যাচ্ছে।

এছাড়াও, রুবির ডাইনামিক্যালি টাইপড প্রকৃতি এবং ডাক টাইপিং ও মেথড ওভারলোডিংয়ের মতো সাধারণ প্যাটার্নের কারণে, সেরা পদ্ধতি নিশ্চিত করার জন্য কিছু সতর্কতা গ্রহণ করা হচ্ছে, যা আমরা শীঘ্রই বিস্তারিত দেখব।

রুবি ৩ ইনস্টল

এখানে দেখানো উদাহরণগুলো অনুসরণ করতে হলে রুবি ৩ ইনস্টল করতে হবে।

আপনি অফিসিয়াল নির্দেশনা অনুসরণ করে বা রুবি-বিল্ড ব্যবহার করে (যদি একাধিক রুবি ভার্সন ম্যানেজ করতে হয়) এটি করতে পারেন।

বিকল্পভাবে, আপনি বর্তমান প্রজেক্টে সরাসরি rbs জেম ইনস্টল করতে পারেন:

gem install rbs

স্ট্যাটিক বনাম ডাইনামিক টাইপিং

আগে এগোয়ার আগে, এই ধারণাটি স্পষ্ট করি। ডাইনামিক্যালি টাইপড ভাষাগুলো স্ট্যাটিক ভাষাগুলোর সাথে কীভাবে তুলনা করা যায়?

ডাইনামিক্যালি টাইপড ভাষাগুলোতে (রুবি, জাভাস্ক্রিপ্ট), ইন্টারপ্রেটারের জন্য কোনো পূর্বনির্ধারিত ডেটা টাইপ থাকে না যাতে সে রানটাইমে নিষিদ্ধ অপারেশন হলে কী করবে বুঝতে পারে।

এটি স্ট্যাটিক টাইপিংয়ের ঠিক বিপরীত। স্ট্যাটিক্যালি টাইপড ভাষাগুলোতে (জাভা, সি), কম্পাইল টাইমে টাইপ যাচাই করা হয়।

নিচের জাভা কোড স্নিপেটটি রেফারেন্স হিসেবে নিন:

int number = 0;
number = "Hi, number!";

স্ট্যাটিক টাইপিংয়ে এটি সম্ভব নয়, কারণ দ্বিতীয় লাইনটি এরর ফেলবে:

error: incompatible types: String cannot be converted to int

এখন একই উদাহরণটি রুবিতে দেখুন:

number = 0
number = "Hi, number!"
puts number # সফলভাবে "Hi, number!" প্রিন্ট করে

রুবিতে, একটি ভেরিয়েবলের টাইপ রানটাইমে পরিবর্তন হয়, অর্থাৎ ইন্টারপ্রেটার জানে কিভাবে একটি টাইপ থেকে অন্যটিতে ডাইনামিক্যালি স্যুইচ করতে হয়।

এই ধারণাটি সাধারণত শক্তিশালী টাইপড বনাম দুর্বল টাইপড ভাষার সাথে বিভ্রান্ত করতে হয়।

রুবি শুধু ডাইনামিক্যালি টাইপড নয়, বরং শক্তিশালী টাইপড ভাষাও, অর্থাৎ এটি রানটাইমে ভেরিয়েবলের টাইপ পরিবর্তন করার অনুমতি দেয়। কিন্তু এটি আপনাকে ক্রেজি টাইপ মিক্সিং অপারেশন করার অনুমতি দেয় না।

পরবর্তী উদাহরণটি দেখুন (রুবিতে), পূর্বের থেকে অ্যাডapted:

number = 2
sum = "2" + 2
puts sum

এখানে আমরা দুটি ভিন্ন টাইপের সংখ্যা (Integer এবং String) যোগ করার চেষ্টা করছি। রুবি নিচের এরর ফেলবে:

main.rb:2:in `+': no implicit conversion of Integer into String (TypeError)
from main.rb:2:in `
'

অর্থাৎ, রুবি বলছে যে ভিন্ন টাইপ জড়িত জটিল ক্যালকুলেশন করার দায়িত্ব আপনার।

অন্যদিকে, জাভাস্ক্রিপ্ট যা দুর্বল এবং ডাইনামিক্যালি টাইপড, একই কোডটি ভিন্ন ফলাফল দিতে পারে:

> number = 2
> sum = "2" + 2
> console.log(sum)
> 22 // এটি উভয় মান কনক্যাট করে

RBS সোরবেট থেকে কীভাবে ভিন্ন?

প্রথমে, কোড অ্যানোটেট করার পদ্ধতিতে প্রত্যেকের পদ্ধতি ভিন্ন। সোরবেট আপনার কোডে সরাসরি অ্যানোটেশন যোগ করে কাজ করে, অন্যদিকে RBS শুধু .rbs এক্সটেনশন वाली একটি নতুন ফাইল তৈরি করতে হয়।

এটির প্রধান সুবিধা লিগ্যাসি কোডবেস মাইগ্রেশন করার সময় দেখা যায়। যেহেতু আপনার মূল ফাইলগুলো প্রভাবিত হয় না, তাই RBS ফাইলগুলো প্রজেক্টে অ্যাডপ্ট করা অনেক নিরাপদ।

এর সৃষ্টিকর্তাদের মতে, RBS-এর প্রধান লক্ষ্য আপনার রুবি প্রোগ্রামের কাঠামো বর্ণনা করা। এটি শুধু ক্লাস/মেথড সিগনেচার সংজ্ঞায়িত করার ওপর ফোকাস করে।

RBS নিজে টাইপ চেক করতে পারে না। এর লক্ষ্য সীমাবদ্ধ: টাইপ চেকাররা (সোরবেট, স্টিপ ইত্যাদি) তাদের কাজ করতে পারেন সেজন্য কাঠামো সংজ্ঞায়িত করা।

একটি সাধারণ রুবি ইনহেরিটেন্স উদাহরণ দেখুন:

class Badger
  def initialize(brand)
    @brand = brand
  end
  def brand?
    @brand
  end
end

class Honey < Badger
  def initialize(brand: "Honeybadger", sweet: true)
    super(brand)
    @sweet = sweet
  end
  def sweet?
    @sweet
  end
end

বাড়ি! শুধু দুটি ক্লাস কিছু অ্যাট্রিবিউট এবং অনুমান করা টাইপসহ।

নিচে একটি সম্ভাব্য RBS রিপ্রেজেন্টেশন দেখানো হলো:

class Brand
  attr_reader brand : String
  def initialize : (brand: String) -> void
end

class Honey < Brand
  @sweet : bool
  def initialize : (brand: String, ?sweet: bool) -> void
  def sweet? : () -> bool
end

খুব একইরকম, ঠিক না? এখানে প্রধান পার্থক্য হল টাইপগুলো। উদাহরণস্বরূপ, Honey ক্লাসের initialize মেথড একটি String এবং একটি boolean প্যারামিটার গ্রহণ করে এবং কিছুই রিটার্ন করে না (void)।

এদিকে, সোরবেট টিম RBI (সোরবেটের ডিফল্ট টাইপ ডেফিনিশন এক্সটেনশন) এবং RBS-এর মধ্যে ইন্টারঅপারেবিলিটির জন্য টুল তৈরি করতে ঘনিষ্ঠভাবে কাজ করছে।

লক্ষ্য হল সোরবেট এবং যেকোনো টাইপ চেকার RBS-এর টাইপ ডেফিনিশন ফাইলগুলো কীভাবে ব্যবহার করবে সে বোঝার ভিত্তি তৈরি করা।

স্ক্যাফোল্ডিং টুল

আপনি যদি ভাষা শিখতে শুরু করেন এবং ইতিমধ্যে কিছু প্রজেক্ট থাকে, তবে কোথায় এবং কীভাবে টাইপিং শুরু করবেন তা অনুমান করা কঠিন হতে পারে।

এটি বিবেচনা করে রুবি টিম আমাদের একটি খুব উপকারী CLI টুল rbs দিয়েছে যা বিদ্যমান ক্লাসের জন্য টাইপ স্ক্যাফোল্ড করে।

কনসোলে rbs help টাইপ করে উপলব্ধ কমান্ডগুলো দেখুন:

RBS: রুবির নতুন টাইপ অ্যানোটেশন সিস্টেম ব্যাখ্যা CLI টুলে উপলব্ধ কমান্ড।

তালিকায় সবচেয়ে গুরুত্বপূর্ণ কমান্ড হচ্ছে prototype কারণ এটি সোর্স কোড ফাইলের AST বিশ্লেষণ করে "আনুমানিক" RBS কোড জেনারেট করে।

"আনুমানিক" কারণ এটি ১০০% কার্যকর নয়। যেহেতু আপনার লিগ্যাসি কোড मुख্যভাগে আনটাইপড, তাই এর স্ক্যাফোল্ড করা কন্টেন্টও অধিকাংশই অনটাইপড থাকবে। যদি কোনো স্পষ্ট অ্যাসাইনমেন্ট না থাকে, RBS কিছু টাইপ অনুমান করতে পারে না।

আরেকটি উদাহরণ নিন, এবার ক্যাসকেডেড ইনহেরিটেন্সসহ তিনটি ভিন্ন ক্লাস নিয়ে:

class Animal
  def initialize(weight)
    @weight = weight
  end
  def breathe
    puts "Inhale/Exhale"
  end
end

class Mammal < Animal
  def initialize(weight, is_terrestrial)
    super(weight)
    @is_terrestrial = is_terrestrial
  end
  def nurse
    puts "I'm breastfeeding"
  end
end

class Cat < Mammal
  def initialize(weight, n_of_lives, is_terrestrial: true)
    super(weight, is_terrestrial)
    @n_of_lives = n_of_lives
  end
  def speak
    puts "Meow"
  end
end

সhibang অ্যাট্রিবিউট এবং মেথডসহ সাধারণ ক্লাস। মনে রাখবেন, একটি ডিফল্ট বুলিয়ান মান দেওয়া আছে, যা RBS-এর স্বয়ংক্রিয় অনুমান ক্ষমতা প্রদর্শনে গুরুত্বপূর্ণ।

এখন এই টাইপগুলো স্ক্যাফোল্ড করতে নিচের কমান্ড চালান:

rbs prototype rb animal.rb mammal.rb cat.rb

আপনি যত ইচ্ছে রুবি ফাইল পাস করতে পারেন। এক্সিকিউশনের ফলাফল নিচে:

class Animal
  def initialize: (untyped weight) -> untyped
  def breathe: () -> untyped
end

class Mammal < Animal
  def initialize: (untyped weight, untyped is_terrestrial) -> untyped
  def nurse: () -> untyped
end

class Cat < Mammal
  def initialize: (untyped weight, untyped n_of_lives, ?is_terrestrial: bool is_terrestrial) -> untyped
  def speak: () -> untyped
end

আমরা যা অনুমান করেছিলাম, RBS আমাদের ক্লাস তৈরি করার সময় লক্ষ্য করা অধিকাংশ টাইপ বুঝতে পারলো না।

আপনার অধিকাংশ কাজ হবে untyped রেফারেন্সগুলো ম্যানুয়ালি আসল টাইপে পরিবর্তন করা। কমিউনিটিতে এখনও এটাকে আরও ভালোভাবে করার জন্য আলোচনা চলছে।

মেটাপ্রোগ্রামিং

মেটাপ্রোগ্রামিং-এর ক্ষেত্রে, rbs টুল খুব সাহায্য করবে না এর ডাইনামিক প্রকৃতির কারণে।

নিচের ক্লাসটি উদাহরণ হিসেবে নিন:

class Meta
  define_method :greeting, -> { puts 'Hi there!' }
end
Meta.new.greeting

এটিকে স্ক্যাফোল্ড করলে ফলাফল হবে:

class Meta
end

ডাক টাইপিং

রুবি অবজেক্টের প্রকৃতি (তাদের টাইপ) সম্পর্কে বেশি চিন্তা করে না, বরং তারা কী করতে পারে (তাদের কী করে) সেটা চিন্তা করে।

ডাক টাইপিং হল একটি বিখ্যাত প্রোগ্রামিং শৈলী যা এই মতামত অনুসরণ করে:

"যদি একটি অবজেক্ট হাঁসের মত আচরণ করে (বোলে, চলে, উড়ে ইত্যাদি), তবে সেটি হাঁস।"

অর্থাৎ, রুবি সেটিকে সবসময় হাঁস হিসেবে বিবেচনা করবে যদিও এর মূল সংজ্ঞা এবং টাইপ হাঁস প্রতিনিধিত্ব করার জন্য নয়।

তবে, ডাক টাইপিং কোড ইমপ্লিমেন্টেশনের ডিটেইল লুকিয়ে রাখতে পারে যা সহজেই ট্রিকি এবং খুঁজে বের করা/পড়া কঠিন হতে পারে।

RBS ইন্টারফেস টাইপ ধারণা চালু করেছে, যা মেথডের একটি সেট যা কোনো কনক্রিট ক্লাস বা মডিউল এর ওপর নির্ভরশীল নয়।

পূর্বের অ্যানিমেল ইনহেরিটেন্স উদাহরণ নিন এবং অনুমান করুন যে আমরা থলচর প্রাণীদের জন্য একটি নতুন হায়ারার্কিক্যাল লেভেল যোগ করছি যেখান থেকে আমাদের Cat ইনহেরিট করবে:

class Terrestrial < Animal
  def initialize(weight)
    super(weight)
  end
  def run
    puts "Running..."
  end
end

নন-থলচর চাইল্ড অবজেক্টগুলো দৌড়াতে না দেয়ার জন্য, আমরা একটি ইন্টারফেস তৈরি করতে পারি যা সপেক্ষিক টাইপ চেক করে:

interface _CanRun
  # `<<` অপারেটর প্রয়োজন যা `Terrestrial` অবজেক্ট এক্সেপ্ট করে।
  def <<: (Terrestrial) -> void
end

RBS কোডকে স্পেসিফিক run মেথডে ম্যাপ করলে সিগনেচার হবে:

def run: (_CanRun) -> void

যেকোনো Zeitpunkt কেউ Terrestrial অবজেক্ট ছাড়া অন্য কিছু মেথডে পাস করতে চাইলে, টাইপ চেকার সেটি লগ করবে।

ইউনিয়ন টাইপস

রুবিস্টদের মধ্যে বিভিন্ন টাইপের মান ধারণ করা এক্সপ্রেশন খুব সাধারণ।

def fly: () -> (Mammal | Bird | Insect)

RBS পাইপ অপারেটর দিয়ে সেগুলো যোগ করে ইউনিয়ন টাইপ সাপোর্ট করে।

মেথড ওভারলোডিং

অনেক প্রোগ্রামিং ভাষার মতো রুবিতে মেথড ওভারলোডিং সাধারণ প্র্যাকটিস, যেখানে একটি ক্লাসে একই নামের একাধিক মেথড থাকতে পারে কিন্তু সিগনেচার ভিন্ন (টাইপ বা প্যারামিটারের সংখ্যা, অর্ডার ইত্যাদি)।

একটি উদাহরণ নিন যেখানে একটি প্রাণী তার निकটতম বিবর্তন শাখা রিটার্ন করতে পারে:

def evolutionary_cousins: () -> Enumerator[Animal, void] | { (Animal) -> void } -> void

এভাবে, RBS আমাদের স্পষ্টভাবে নির্ধারণ করতে দেয় যে একটি প্রাণীর একক বিবর্তন শাখা থাকবে নাকি অনেক গুলো।

TypeProf

সামান্তরালভাবে, রুবি টিম typeprof নামে একটি নতুন প্রজেক্ট শুরু করেছে, একটি এক্সপেরিমেন্টাল টাইপ-লেভেল রুবি ইন্টারপ্রেটার যা RBS কন্টেন্ট বিশ্লেষণ ও জেনারেট করার চেষ্টা করে।

এটি অ্যাবস্ট্রাক্ট ইন্টারপ্রিটেশন দিয়ে কাজ করে এবং এখনও শুরুর ধাপে আছে, তাই প্রোডাকশন উদ্দেশ্যে ব্যবহার করার সময় সতর্ক থাকুন।

ইনস্টল করতে আপনার প্রজেক্টে জেম যোগ করুন:

gem install typeprof

মনে রাখবেন, এর জন্য রুবি ভার্সন ২.৭+ প্রয়োজন।

Animal ক্লাসের নিচের ভার্সন নিন:

class Animal
  def initialize(weight)
    @weight = weight
  end
  def die(age)
    if age > 50
      true
    elsif age <= 50
      false
    elsif age < 0
      nil
    end
  end
end
Animal.new(100).die(65)

age মেথডের ভেতরের লজিক এবং তার পরবর্তী কলের ভিত্তিতে TypeProf কোডে ম্যানিপুলেট হওয়া টাইপগুলো বুদ্ধিমানভাবেই অনুমান করতে পারে।

typeprof animal.rb কমান্ড চালালে আউটপুট হবে:

## Classes
class Animal
  @weight: Integer
  def initialize: (Integer weight) -> Integer
  def die: (Integer age) -> bool?
end

বেশ কোডবেস वाले প্রজেক্টের জন্য এটি একটি শক্তিশালী টুল।

VS Code ইন্টিগ্রেশন

এখনো RBS-এর জন্য ফরম্যাটিং, স্ট্রাকচার চেকিং ইত্যাদির জন্য অনেক VS Code প্লাগইন নেই, বিশেষ করে এখনো এটি আপেক্ষিক নতুন।

তবে, স্টোরে "RBS" খুঁজলে ruby-signature নামে একটি প্লাগইন পাবেন যা সিনট্যাক্স হাইলাইটিংয়ে সাহায্য করবে:

RBS: রুবির নতুন টাইপ অ্যানোটেশন সিস্টেম ব্যাখ্যা VS Code-এ RBS সিনট্যাক্স হাইলাইটিং।

উপসংহার

RBS খুব নতুন হলেও সুরক্ষিত রুবি কোডবেসের দিকে একটি গুরুত্বপূর্ণ পদক্ষেপ।

সময়ের সাথে নতুন টুল এবং ওপেন-সোর্স প্রজেক্ট উদিত হবে যা এটিকে ব্যাকআপ করবে, যেমন রুবি অন রেইলস অ্যাপ্লিকেশনের জন্য RBS ফাইল জেনারেট করার জন্য RBS Rails।

ভবিষ্যতে রুবি কমিউনিটির জন্য অদ্ভুত জিনিসগুলো আছে - আরও নিরাপদ এবং বাগ-মুক্ত অ্যাপ্লিকেশন। দেখতে পাওয়ার জন্য অপেক্ষা করছি! кредит

  1. রুবিতে সিলেকশন সর্ট মাস্টার করুন: স্টেপ-বাই-স্টেপ ইমপ্লিমেন্টেশন

  2. RBS: রুবির নতুন টাইপ অ্যানোটেশন সিস্টেম ব্যাখ্যা

  3. রুবি দিয়ে ইন্সারশন সর্টিং দক্ষতা অর্জন: ধাপে ধাপে গাইড

  4. রুবি ২.৬-এ ৯টি গুরুত্বপূর্ণ উন্নতির অন্বেষণ