Your first Mix program - Discover Elixir & Phoenix | Ludu

Your first Mix program

by Tristan Edwards Tristan Edwards

11 thanks

  • In this chapter, we'll leave IEx behind and start writing our first real Elixir application!

    +
  • Using Mix

    +
  • When you installed Elixir in the first chapter, you also got a little command line program called "Mix". The mix bash command lets you do many things, like installing third party libraries, generating files, testing your program, and much more. If you've ever used Ruby, you could see mix as a combination of bundler, rake and gem – all combined into a single powerful command!

    +
  • Pro tip: when in doubt, you can type `⁣mix help`⁣ to see a list of available commands:
    +
  • Alright! Let's use Mix to create an Elixir application called elixirapp:

    +
  • Loading code...
    +
  • You should now have a new folder called elixirapp that you can cd into:

    +
  • Loading code...
    +
  • What's in a project?

    +
  • Inside your application's folder, you should see the following files and folders:

    +
  • +
  • Let's go through them one by one:

    +
    • 1

      config: sets configuration details for your app. Right now it only contains a single file (config.exs), which sets configurations that are common across all environments. In the future you'll probably want separate files for each environments (e.g. prod.exs and test.exs).

    • 2

      lib: this is where your app lives and where you'll write the vast majority of your Elixir code. Right now it only contains a single file – `elixirapp.ex` with an empty module.

    • 3

      test: the home of your automated tests, which exist to make sure that your app is bug-free. The file test_helper.exs is executed before any other test file. Note that all your test files must end in _test.exs, just like the default file: elixirapp_test.exs.

    • 4

      mix.exs: if you've ever used Node.js, you'll notice that this file is roughly equivalent to package.json. It's used to define version numbers, both for the app itself and for its dependencies.

    • 5

      README.md: a simple Markdown file where you describe how your apps work.

    +
  • Now that you know the basic file structure of a Mix project, let's write some code!

    +
  • Writing and running your code

    +
  • Let's start with a good ol' "Hello World"-application! Open the file lib/elixirapp.ex and create a function called say_hello using def:

    +
  • Loading code...
    +
  • Save your file and open the command line. Make sure that you're in your program's folder and run this command:

    +
  • Loading code...
    +
  • This will compile your entire Mix application and open it in IEx. Now you can call your application's functions by referencing the Elixirapp-module:

    +
  • Loading code...
    +
  • Reading the user's input

    +
  • Let's make our program a little more interesting. We want to ask the user what their name is, read their input, and then print out "Hello (whatever their name is)". If the user doesn't fill in their name and tries to continue, the application should show an error message and ask again.

    +
  • We'll start by building a main-function where we read the user's input through IO.gets and inspect it with IO.inspect. We'll leave our previous say_hello-function as it is for now.

    +
  • Loading code...
    +
  • Let's run this again with iex -S mix. This time, we call Elixirapp.main, type "test" and press enter:

    +
  • Loading code...
    +
  • As you can see, IO.gets appends a newline character at the end of our input. We want to trim this away before inspecting the value. To do this, we can use Elixir's built-in String.strip-function, and change our program a bit:

    1
    Ted Klein Bergman
  • Loading code...
    +
  • Now, if we exit IEx and re-run the program, the newline character will be gone:

    +
  • Loading code...
    +
  • The Pipe Operator

    +
  • The pipe operator |> is a great feature in Elixir that makes your code shorter and more readable. It allows us to rewrite the following code...

    +
  • Loading code...
    +
  • ...into a single line like this:

    +
  • Loading code...
    +
  • The pipe operator takes the returned value of the function on the left hand side (IO.gets) and sends it as the first parameter to the function on the right hand side (String.strip). It's essentially a more readable version of this:

    +
  • Loading code...
    +
  • The pipe operator is especially helpful when you have many nested functions. Compare the readability of these two lines performing the same thing:

    +
  • Loading code...
    +
  • Pattern matching functions

    +
  • Let's go back to our app! The last thing we want to do is print out the user's name or show an error message depending on the input we receive.

    +
  • We'll start by modifying our current say_hello-function so that it can take a name parameter, and use some string interpolation to display it in a sentence:

    +
  • Loading code...
    +
  • Now, how do we handle the use case where the user types in nothing, and sends us an empty string? We could use a case inside say_hello, but I want to show something cooler: pattern matching functions!

    +
  • Above our current say_hello-function, we can declare another, seemingly identical, say_hello-function, but where the difference is that its first parameter is always an empty string. Inside it, we log an error message and return to main():

    +
  • Loading code...
    +
  • Now, when we call say_hello from main, our program will run through the say_hello function declarations in our file from top to bottom and latch on to the first one that it matches with. This means that if our name variable is an empty string, it will go to the first say_hello, but in all other cases, it will go to the second one. Cool!

    +
  • Our final program should now look like this:

    +
  • Loading code...
    3
    Tristan Edwards Peter Marreck
  • Let's restart IEx, run the program one last time and make sure that it works as expected!

    +
  • Loading code...
    +
  • One more thing...

    +
  • Another quirky thing about Elixir is that when a function is called (and the program has to decide which function definition to latch on to) it not only pattern-matches against the values of the parameters, but also against the number of parameters itself!

    +
  • In our program, we could add a third definition of the say_hello-function that takes two parameters instead of just one:

    +
  • Loading code...
    +
  • That way, if you call say_hello("Tristan") (with one parameter), it will print the usual "Hello Tristan!", but if you call say_hello("Good morning", "Tristan") (with two parameters), it will latch on to this newly defined function instead, and print "Good morning Tristan!".

    +
  • Because of this feature, Elixir programmers always specify the number of parameters a function takes whenever they reference it, like this: {function_name}/{number_of_params}.
    For instance, in our example above, we have both say_hello/1 (which takes one argument) and say_hello/2 (which takes two arguments).

    +
  • You'll notice that if you try to call say_hello/0 or say_hello/3, Elixir will give you an UndefinedFunctionError:

    +
  • +
  • Sweet! Now you should have a basic overview of how Elixir works, including some knowledge on pattern matching and the pipe operator. In the next chapter, we're going to start diving into the Phoenix framework!

    +

Did it help you? Click to say "thanks" to the author!

Next lesson: Phoenix

Want to create your own course on Ludu?

Back to lesson