बिहेवियर की मदद से हम एक बिहेवियर मॉड्यूल में इंटरफेस (फंक्शन और मैक्रो के समूह) तय कर सकते हैं, जिन्हें बाद में अलग-अलग कॉलबैक मॉड्यूल लागू कर सकते हैं। एक ही इंटरफेस होने की वजह से इन कॉलबैक मॉड्यूल को एक-दूसरे की जगह इस्तेमाल किया जा सकता है।
ध्यान दीजिए कि ब्रिटिश अंग्रेज़ी में इसकी स्पेलिंग "behaviours" होती है।
बिहेवियर बनाने के लिए हमें एक नया मॉड्यूल बनाना होता है और उन फंक्शन की सूची बतानी होती है जो इस इंटरफेस का हिस्सा हैं। हर फंक्शन को @callback मॉड्यूल एट्रिब्यूट से परिभाषित करना होता है। इसका सिंटैक्स फंक्शन टाइपस्पेक (@spec) जैसा ही होता है। हमें फंक्शन का नाम, आर्गुमेंट के टाइप की सूची, और सारे संभावित रिटर्न टाइप बताने होते हैं।
defmodule Countable do
@callback count(collection :: any) :: pos_integer
end
किसी मौजूदा बिहेवियर को अपने मॉड्यूल में जोड़ने के लिए (यानी कॉलबैक मॉड्यूल बनाने के लिए) हम @behaviour मॉड्यूल एट्रिब्यूट का इस्तेमाल करते हैं। इसकी वैल्यू उस बिहेवियर मॉड्यूल का नाम होनी चाहिए जिसे हम जोड़ रहे हैं।
इसके बाद हमें उन सारे फंक्शन (कॉलबैक) को परिभाषित करना होता है जिनकी उस बिहेवियर मॉड्यूल को ज़रूरत होती है। अगर हम किसी और का बिहेवियर लागू कर रहे हैं, जैसे Elixir का बना हुआ Access या GenServer बिहेवियर, तो उस बिहेवियर के सारे कॉलबैक की सूची हमें hexdocs.pm पर डॉक्युमेंटेशन में मिल जाएगी।
एक कॉलबैक मॉड्यूल सिर्फ अपने बिहेवियर के फंक्शन ही लागू करने तक सीमित नहीं है। एक ही मॉड्यूल कई बिहेवियर भी लागू कर सकता है।
यह बताने के लिए कि कौन-सा फंक्शन किस बिहेवियर से आया है, हमें हर फंक्शन से पहले @impl मॉड्यूल एट्रिब्यूट लगाना चाहिए। इसकी वैल्यू उस बिहेवियर मॉड्यूल का नाम होनी चाहिए जो यह कॉलबैक परिभाषित करता है।
defmodule BookCollection do
@behaviour Countable
defstruct [:list, :owner]
@impl Countable
def count(collection) do
Enum.count(collection.list)
end
def mark_as_read(collection, book) do
# other function unrelated to the Countable behaviour
end
end
बिहेवियर परिभाषित करते समय किसी कॉलबैक का डिफॉल्ट इम्प्लीमेंटेशन भी दिया जा सकता है। यह इम्प्लीमेंटेशन __using__/1 मैक्रो के कोटेड एक्सप्रेशन में लिखा जाना चाहिए। ताकि बिहेवियर मॉड्यूल का इस्तेमाल करने वाले लोग इस डिफॉल्ट इम्प्लीमेंटेशन को ओवरराइड कर सकें, फंक्शन का इम्प्लीमेंटेशन लिखने के बाद defoverridable/1 मैक्रो को कॉल कीजिए। यह एक कीवर्ड लिस्ट लेता है, जिसमें कीज़ फंक्शन के नाम और वैल्यू फंक्शन की आरिटी होती हैं।
defmodule Countable do
@callback count(collection :: any) :: pos_integer
defmacro __using__(_) do
quote do
@behaviour Countable
def count(collection), do: Enum.count(collection)
defoverridable count: 1
end
end
end
ध्यान रखिए कि __using__/1 के अंदर फंक्शन बनाना, डिफॉल्ट कॉलबैक इम्प्लीमेंटेशन के अलावा किसी और उद्देश्य के लिए ठीक नहीं माना जाता। लेकिन आप हमेशा किसी दूसरे मॉड्यूल में फंक्शन बना सकते हैं और उन्हें __using__/1 मैक्रो में इम्पोर्ट कर सकते हैं।