In this post, I'm going to cover a few miscellaneous topics that did't fit very well into what I've covered so far.
IEx has its own set of commands, and I'm going to cover some of the useful ones I've learned so far. IEx commands are actually Elixir functions contained in the
IEx.Helpers module, but from within the IEx shell, they just look like regular shell commands.
h command an abbreviation of "help", and you can use it to pull up information on almost anything in Elixir (or at least that how it appears to me). I suspect that compiled Elixir modules and functions contain some sort of documentation metadata, which the
h command retrieves and displays. That's purely speculation on my part, but it would not surprise me that once we learn how to attach documentation to code, the
h command would display documentation for our own code as well.
h command is a function, you can call it like so:
h([something]). However, since this IEx is a shell, I prefer to use the space syntax instead of the parentheses syntax:
h [something]. Let's look at an example.
We can get the documentation associated with a module, in this case the String module.
iex> h String String A String in Elixir is a UTF-8 encoded binary. ## Codepoints and grapheme cluster The functions in this module act according to the Unicode Standard, version 11.0.0. As per the standard, a codepoint is a single Unicode Character, which may be represented by one or more bytes. For example, the codepoint "├⌐" is two bytes: iex> byte_size("├⌐") 2 However, this module returns the proper length: iex> String.length("├⌐") 1 Furthermore, this module also presents the concept of grapheme cluster (from now on referenced as graphemes). Graphemes can consist of multiple codepoints that may be perceived as a single character by readers. For example, "├⌐" can be ...
I'm only including part of the results in the above example. The text continues for quite a while.
We can also retrieve documentation for a particular function. The following retrieves the documentation for
iex> h String.upcase/1 def upcase(string, mode \\ :default) Converts all characters in the given string to uppercase according to mode. mode may be :default, :ascii or :greek. The :default mode considers all non-conditional transformations outlined in the Unicode standard. :ascii uppercases only the letters a to z. :greek includes the context sensitive mappings found in Greek. ## Examples iex> String.upcase("abcd") "ABCD" iex> String.upcase("ab 123 xpto") "AB 123 XPTO" iex> String.upcase("ol├í") "OL├ü" The :ascii mode ignores Unicode characters and provides a more performant implementation when you know the string contains only ASCII characters: iex> String.upcase("ol├í", :ascii) "OL├í"
You can even use
h to get the documentation for itself by typing
All the documentation that you can retrieve for anything in the official Elixir environment appears to be also available on the Elixir website. However, the
h command is useful if you don't want to have to go search for that documentaton. I imagine that it is also useful for summoning documentation for other Elixir frameworks and libaries.
c command loads and compiles one or more modules from source code files, making the loaded modules available for use in the IEx shell.
I already showed how to use this command in the second post covering functions and modules. I'll give a brief example here.
iex> c "math_operations.exs" [MathOperations]
The above code example loads the
MathOperations module from
math_operations.exs. After that, we can call the functions in that module from within IEx.
i command prints data type information. You can use this command to look up information about a variable, function, module, or pretty much anything that represents some kind of data. Since Elixir is a dynamically-typed language, this is most useful when you see some kind of identifier and you want to find out more about it. The
i command will tell you if it's a function, string, atom, list, or whatever else.
This example prints out information regarding the String module. There's quite a lot of information available. It's interesting to see that the data type of a module identifier is actually an atom. It even tells me where the source code was located on José's hard drive before it was compiled. :)
iex> i String Term String Data type Atom Module bytecode c:/Program Files (x86)/Elixir/lib/elixir/ebin/Elixir.String.beam Source /Users/jose/OSS/elixir/lib/elixir/lib/string.ex Version  Compile options [:debug_info] Description Use h(String) to access its documentation. Call String.module_info() to access metadata. Raw representation :"Elixir.String" Reference modules Module, Atom Implemented protocols IEx.Info, Inspect, List.Chars, String.Chars
The next examples print out information regarding a string, integer, and a list.
iex> name = "Bob" "Bob" iex> i name Term "Bob" Data type BitString Byte size 3 Description This is a string: a UTF-8 encoded binary. It's printed surrounded by "double quotes" because all UTF-8 encoded codepoints in it are printable. Raw representation <<66, 111, 98>> Reference modules String, :binary Implemented protocols IEx.Info, Collectable, Inspect, List.Chars, String.Chars
iex> age = 32 32 iex> i age Term 32 Data type Integer Reference modules Integer Implemented protocols IEx.Info, Inspect, List.Chars, String.Chars
iex> i [1, 2, 3] Term [1, 2, 3] Data type List Reference modules List Implemented protocols IEx.Info, Collectable, Enumerable, Inspect, List.Chars, String.Chars
That's interesting. I don't know what protocols are yet, but based on the information I see here, they sure appear to resemble interfaces in C#. I'll bet that they are at least something similar to interfaces.
I don't yet understand the meaning of all this information yet, but I'll bet this will be really useful once I become a proficient Elixir developer.
Other IEx commands
There are many more commands in IEx, most of which I've never used. You can look at a summary of them by typing
iex> h IEx.Helpers IEx.Helpers Welcome to Interactive Elixir. You are currently seeing the documentation for the module IEx.Helpers which provides many helpers to make Elixir's shell more joyful to work with. This message was triggered by invoking the helper h(), usually referred to as h/0 (since it expects 0 arguments). You can use the h/1 function to invoke the documentation for any Elixir module or function: iex> h(Enum) iex> h(Enum.map) iex> h(Enum.reverse/1) You can also use the i/1 function to introspect any value you have in the shell: iex> i("hello") There are many other helpers available, here are some examples: ΓÇó b/1 - prints callbacks info and docs for a given module ΓÇó c/1 - compiles a file ΓÇó c/2 - compiles a file and writes bytecode to the given path ΓÇó cd/1 - changes the current directory ΓÇó clear/0 - clears the screen ΓÇó exports/1 - shows all exports (functions + macros) in a module ΓÇó flush/0 - flushes all messages sent to the shell ΓÇó h/0 - prints this help message ΓÇó h/1 - prints help for the given module, function or macro ΓÇó i/0 - prints information about the last value ΓÇó i/1 - prints information about the given term ΓÇó ls/0 - lists the contents of the current directory ΓÇó ls/1 - lists the contents of the specified directory ΓÇó open/1 - opens the source for the given module or function in your editor ΓÇó pid/1 - creates a PID from a string ΓÇó pid/3 - creates a PID with the 3 integer arguments passed ΓÇó ref/1 - creates a Reference from a string ΓÇó ref/4 - creates a Reference with the 4 integer arguments passed ΓÇó pwd/0 - prints the current working directory ΓÇó r/1 - recompiles the given module's source file ΓÇó recompile/0 - recompiles the current project ΓÇó runtime_info/0 - prints runtime info (versions, memory usage, stats) ΓÇó v/0 - retrieves the last value from the history ΓÇó v/1 - retrieves the nth value from the history Help for all of those functions can be consulted directly from the command line using the h/1 helper itself. Try: iex> h(v/0) To list all IEx helpers available, which is effectively all exports (functions and macros) in the IEx.Helpers module: iex> exports(IEx.Helpers) This module also includes helpers for debugging purposes, see IEx.break!/4 for more information. To learn more about IEx as a whole, type h(IEx).
h IEx will give you a lot of documentation about IEx and how it works. I have not yet read all of it, but it's quite informative. The same IEx documentation is available on the Elixir website. It includes the module documentation and the documentation for the functions within the module. No doubt it all comes from the same source.
Here's a tip that that has helped me out when in IEx. Sometime you mess up the syntax and IEx wants you to type in the magic characters to complete the statement. There are times when you just want to abort the statement completely, but the only way to do that is to figure out the characters that Elixir wants or exist IEx entirely by pressing Ctrl+C twice.
However, it is possible to just abort the statement by typing in
#iex:break. I have no idea what the significance of that is, but it allows you to abort the statement and get back to the IEx prompt.
iex> list = [1, 2 ...> ...> ...> ...> #iex:break ** (TokenMissingError) iex:5: incomplete expression iex>
Another tip is to use the
v function in Elixir. That will repeat the last thing you entered so you don't have to type it all over again. This is particularly helpful if the last statement was really long and you don't want to have to type it all over again.
iex> [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] iex> v [1, 2, 3, 4, 5] iex> list = v() [1, 2, 3, 4, 5] iex> list [1, 2, 3, 4, 5] iex>
Running Code Directly
From what I understand, we don't have to go into IEx to run a code file. We can run code directly from the command line.
So I created the following code in the ElixirOperations project that I had created as part of writing the last post. You can find the ElixirOperator project in its own folder in the Learn With Me: Elixir repository on Github.
Operator.apply(&MathOperations.add/2, 4, 9) Operator.apply(&MathOperations.subtract/2, 4, 9) Operator.apply(&MathOperations.multiply/2, 4, 9) Operator.apply(&MathOperations.divide/2, 4, 9) Operator.apply(&MathOperations.mod/2, 9, 4) Operator.apply(&MathOperations.negate/1, 9) Operator.apply(&MathOperations.square/1, 9) Operator.apply(&MathOperations.square/1, MathOperations.pi)
Then I tried running it using
elixir perform_operations.exs. That resulted in the following error:
** (UndefinedFunctionError) function Operator.apply/3 is undefined (module Operator is not available) Operator.apply(&MathOperations.add/2, 4, 9) perform_operations.exs:1: (file) (elixir) lib/code.ex:767: Code.require_file/2
So it clearly couldn't locate and load other modules that way. I then tried passing all the required files in as parameters.
elixir operator.exs math_operations.exs perform_operations.exs
There was absolutely no output. OK, it's not IEx, so I probably need to output those values to the screen. So then I tried adding a calls to do so.
IO.puts("Hello") IO.puts Operator.apply(&MathOperations.add/2, 4, 9) IO.puts Operator.apply(&MathOperations.subtract/2, 4, 9) IO.puts Operator.apply(&MathOperations.multiply/2, 4, 9) IO.puts Operator.apply(&MathOperations.divide/2, 4, 9) IO.puts Operator.apply(&MathOperations.mod/2, 9, 4) IO.puts Operator.apply(&MathOperations.negate/1, 9) IO.puts Operator.apply(&MathOperations.square/1, 9) IO.puts Operator.apply(&MathOperations.square/1, MathOperations.pi)
There was still no output. By reading the
elixir tool help documentation (just type
elixir --help), I found that it was only running the first file and the rest were being regarded as data. Perhaps they are being used as parameters for the script?
Anyway, I then discovered that the other files could be loaded using the
-r switch, like so:
elixir -r operator.exs -r math_operations.exs perform_operations.exs Hello 13 -5 36 0.4444444444444444 1 -9 81 9.869604401089358
Very nice. I can now run .exs files as scripts from outside IEx.
Single-line comments in Elixir are preceded by the
# character. This is equivalent to the
#This is a code comment name = "Bob" #Convert the name to upper-case name = String.upcase(name)
There is no generic multi-line comment syntax similar to
Seeing how documentation metadata can be retrieved in IEx, I think it's quite likely that there is some special documentation format that needs to be followed. I have no idea what that looks like yet. So until then, I'll just document my functions with standard comments.
Comments can be used in IEx, and they evaluate to
nil. I know because I tried. However, comments are more useful in source code files than they are in IEx.
iex> #This is a comment nil iex> #This is another comment nil iex> name = "Bob" "Bob"
By the way, I haven't actually covered
nil yet, and that's because I know nothing about it. I think it's safe to assume that it's similar to