{"id":10996,"date":"2024-07-21T10:37:24","date_gmt":"2024-07-21T10:37:24","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=10996"},"modified":"2024-07-21T10:37:24","modified_gmt":"2024-07-21T10:37:24","slug":"more-modules-in-elixer","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/more-modules-in-elixer\/","title":{"rendered":"More modules in Elixer"},"content":{"rendered":"<p>In the post <a href=\"https:\/\/putridparrot.com\/blog\/a-little-more-elixir-were-talking-modules-and-functions\/\" rel=\"noopener\" target=\"_blank\">A little more Elixir, we\u2019re talking modules and functions<\/a> we looked at a basic use of modules to allows us to declare functions (and macros, although we&#8217;ve not really touched these yet). <\/p>\n<p>Modules can be nested, for example<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndefmodule Math do\r\n  defmodule Fractions do\r\n  # Nested module and functions \r\n  end\r\n\r\n  # Top level module an functions\r\nend\r\n<\/pre>\n<p>These don&#8217;t actually have a relationship with one another, instead Elixir essentially has them as separate modules, like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndefmodule Math do\r\n  # functions\r\nend\r\n\r\ndefmodule Math.Fractions do\r\n  # functions\r\nend\r\n<\/pre>\n<p><strong>Importing modules<\/strong><\/p>\n<p>The <em>import<\/em> keyword (as the name suggests) imports a module&#8217;s functions and\/or macros into the scope of the module or function they&#8217;re imported into. The scope is limited to that defined by the start and end of the module or function. Importing allows us to call functions from the module without having to use it&#8217;s module name. For example, we have a <em>Math<\/em> module with functions <em>add<\/em> and <em>sub<\/em> but we import it into our function like this<\/p>\n<pre class=\"brush: plain; highlight: [3]; title: ; notranslate\" title=\"\">\r\ndef f do \r\n  import Math\r\n  add(1, 7)\r\nend\r\n<\/pre>\n<p>Notice how the highlighted line does not need to prefix the module name to the function.<\/p>\n<p>We can limit what&#8217;s imported using additional syntax where where we have <em>only:<\/em> or <em>except:<\/em> to reduce the scope of imports to the minimal, for example we do not need <em>sub<\/em> in our import so we could write<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndef f do \r\n  import Math, only &#x5B;add: 2]\r\n  add(1, 7)\r\nend\r\n<\/pre>\n<p>In the above we import <em>only<\/em> the <em>add<\/em> function with arity of 2 (i.e. the 2 parameter function named <em>add<\/em>).<\/p>\n<p><strong>Aliasing modules<\/strong><\/p>\n<p>As the name suggests, <am>alias<\/em> allows us to create an alias to a module name, for example let&#8217;s say we have <em>Math.Fractions<\/em> whilst not a big deal to type if we&#8217;re typing it for every function it create a lot of &#8220;clutter&#8221; in our code, so instead we can alias the name like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndefmodule TestMod do\r\n  alias Math.Fraction, as: F\r\n  def f do\r\n    F.some_function()\r\n  end \r\nend\r\n<\/pre>\n<p><strong>Require a module<\/strong><\/p>\n<p>The <em>require<\/em> keyword ensure the macro definitions of a module are compiled into the scope using the <em>require<\/em>. Or to put this another way <em>require<\/em> ensures that a required module is loaded before the module that&#8217;s calling into it. This will ensure any macros within it are available to the calling module and they&#8217;re scoped to that calling module. <\/p>\n<p><em>Note: require is not like an alias, so you still need to prefix any macro\/function calls with the module name (unless you also alias it ofcourse)<\/em><\/p>\n<p>An example might be something like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndefmodule A do\r\n  defmacro hello(arg) do\r\n    quote do\r\n      IO.puts &quot;Hello #{unquote(arg)}&quot;\r\n    end\r\n  end\r\nend\r\n\r\ndefmodule B do\r\n  def hello_world() do\r\n    A.hello &quot;World&quot;\r\n  end\r\nend\r\n<\/pre>\n<p>In the above, if you compile this into iex using <em>c(&#8220;require_sample.rx&#8221;)<\/em> you&#8217;ll get warnings such as <em>warning: you must require A before invoking the macro A.hello\/1<\/em> if you try to execute the command <em>B.hello_world(&#8220;Scooby&#8221;)<\/em> you&#8217;ll get an error like this <em>** (UndefinedFunctionError) function A.hello\/1 is undefined or private. However, there is a macro with the same name and arity. Be sure to require A if you intend to invoke this macro<\/em>.<\/p>\n<p>So as you can see, we need to use <em>require<\/em>, simply add the <em>require A<\/em> as below<\/p>\n<pre class=\"brush: plain; highlight: [10]; title: ; notranslate\" title=\"\">\r\ndefmodule A do\r\n  defmacro hello(arg) do\r\n    quote do\r\n      IO.puts &quot;Hello #{unquote(arg)}&quot;\r\n    end\r\n  end\r\nend\r\n\r\ndefmodule B do\r\n  require A\r\n  def hello_world() do\r\n    A.hello &quot;World&quot;\r\n  end\r\nend\r\n<\/pre>\n<p><strong>The use macro<\/strong><\/p>\n<p>The <em>use<\/em> macros allows us to &#8220;inject&#8221; any code into the current module. It&#8217;s used as an extension point.<\/p>\n<p>I&#8217;ll dedicate a post of it&#8217;s own to the <em>use<\/em> keyword as it&#8217;s interesting what you can do with it.<\/p>\n<p><strong>Module Attributes<\/strong><\/p>\n<p>Attributes in Elixir are prefixed with the @ symbol. These add metadata to our module. An attribute is declared as a <em>@name value<\/em> pair. Whilst the name can be pretty much anything (within the allowable syntax), for example I might have a <em>@my_ver 1<\/em>, there are some reserved names<\/p>\n<ul>\n<li>@moduledoc is use for module documentation<\/li>\n<li>@doc is use for function or macro documentation<\/li>\n<li>@spec is use to supply a typespec for the function which follows<\/li>\n<li>@behaviour is used for OTP or under-defined behaviour (and yes it&#8217;s the UK spelling)<\/li>\n<\/ul>\n<p>Here&#8217;s an example of creating our own attribute and we&#8217;re able to use it within our functions<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndefmodule Attributes do\r\n  @some_name PutridParrot\r\n\r\n  def attrib() do\r\n    @some_name\r\n  end\r\nend\r\n<\/pre>\n<p>This will return the @some_name value.<\/p>\n<p>You can set the attribute multiple times within the module scope. Elixir evaluates from top to bottom so functions after a change to the @some_name (above) will get the new value.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the post A little more Elixir, we\u2019re talking modules and functions we looked at a basic use of modules to allows us to declare functions (and macros, although we&#8217;ve not really touched these yet). Modules can be nested, for example defmodule Math do defmodule Fractions do # Nested module and functions end # Top [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[730],"tags":[],"class_list":["post-10996","post","type-post","status-publish","format-standard","hentry","category-elixir"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10996","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=10996"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10996\/revisions"}],"predecessor-version":[{"id":11013,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10996\/revisions\/11013"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=10996"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=10996"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=10996"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}