প্রোটোকল হলো:
defprotocol দিয়ে ডিফাইন করা হয়।defimpl দিয়ে নির্দিষ্ট কোনো ডেটা টাইপের জন্য ইমপ্লিমেন্ট করা হয়।প্রোটোকলের একটা বড় সুবিধা হলো, নির্দিষ্ট একটি ডেটা টাইপের জন্য প্রোটোকলের ইমপ্লিমেন্টেশনকে সেই ডেটা টাইপের সংজ্ঞা বা প্রোটোকলের সংজ্ঞার সাথে একসাথে বান্ডল করে রাখতে হয় না। এই কারণে এমন লাইব্রেরি লেখা যায়, যেগুলো লাইব্রেরিতে কোনো পরিবর্তন না করেই ব্যবহারকারীরা সহজে বাড়িয়ে নিজেদের কাস্টম ডেটা টাইপের সাথে কাজ করাতে পারেন।
Elixir-এর সব টাইপের জন্যই প্রোটোকল ইমপ্লিমেন্ট করা সম্ভব: Tuple, Atom, List, BitString, Integer, Float, Function, PID, Map, Port, Reference, Any, আর স্ট্রাক্ট।
একসাথে একাধিক টাইপের জন্য প্রোটোকল ইমপ্লিমেন্ট করা যায়:
defimpl Reversible, for: [Map, List] do
def reverse(term) do
Enum.reverse(term)
end
end
যে মডিউল স্ট্রাক্টটি ডিফাইন করে, তার ভিতরেই সরাসরি কোনো স্ট্রাক্টের জন্য প্রোটোকল ইমপ্লিমেন্ট করলে :for আর্গুমেন্ট বাদ দেওয়া যায়:
defmodule ShoppingCart do
defstruct [:items]
defimpl Reversible do
def reverse(shopping_cart) do
Enum.reverse(shopping_cart)
end
end
end
Any-তে ফলব্যাকডিফল্টভাবে, যে ডেটা টাইপের জন্য প্রোটোকলটি ইমপ্লিমেন্ট করা হয়নি, তার জন্য প্রোটোকল কল করলে Protocol.UndefinedError এরর দেখায়:
to_string({})
# => ** (Protocol.UndefinedError) protocol String.Chars not implemented for {} of type Tuple
# (elixir 1.10.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
# (elixir 1.10.3) lib/string/chars.ex:22: String.Chars.to_string/1
এমন পরিস্থিতিতে ব্যবহারের জন্য একটি ফলব্যাক ইমপ্লিমেন্টেশন দিয়ে এটা এড়ানো সম্ভব। এর জন্য প্রোটোকলটি ডিফাইন করার সময় @fallback_to_any মডিউল অ্যাট্রিবিউট true সেট করুন এবং Any টাইপের জন্য একটি ইমপ্লিমেন্টেশন লিখুন:
defprotocol Reversible do
@fallback_to_any true
def reverse(term)
end
defimpl Reversible, for: Any do
def reverse(term) do
term
end
end
মনে রাখবেন, বেশিরভাগ ক্ষেত্রেই এরর দেখানোই ভালো পদ্ধতি, কারণ সব ডেটা টাইপের জন্য একটি প্রোটোকল নিয়েreasonable ধারণা করা কঠিন।
Enumerable - এই প্রোটোকলটি ইমপ্লিমেন্ট করে এমন ডেটা টাইপের সাথে Enum আর Stream মডিউলের ফাংশনগুলো কাজ করে।Collectable - Enum.into/2 ফাংশনটি একটি এনিউমারেবলকে একটি কালেকশনে ঢোকাতে এই প্রোটোকলটি ব্যবহার করে।Inspect - কোনো নির্দিষ্ট ডেটা টাইপকে Kernel.inspect/2 কীভাবে স্ট্রিং হিসেবে উপস্থাপন করে, তা বদলাতে এই প্রোটোকলটি ইমপ্লিমেন্ট করতে পারেন।String.Chars - কোনো নির্দিষ্ট ডেটা টাইপকে Kernel.to_string/1 কীভাবে স্ট্রিং হিসেবে উপস্থাপন করে, তা বদলাতে এই প্রোটোকলটি ইমপ্লিমেন্ট করতে পারেন।