How to create a string template?

There’s no ability to create a string template variable? For instance:

defmodule M1 do
  @my_str_var "aaaaa{key1}bbbbb{key2}cccc" # this

  def get_string(var1, var2) do

    # but then how to use it?

    # String.interpolate(@my_str, var1,  var2)

    # or
    # String.interpolate(@my_str, %{key1: var1, key2: var2})


you can use EEx.

template = "aaaaa<%= key1 %>bbbbb<%= key2 %>cccc"
EEx.eval_string(template, key1: "foo", key2: "bar")
#=> "aaaaafoobbbbbbarcccc"
1 Like

It’s worth noting that EEx.eval_string isn’t very fast. The EEx module documentation has more information on its use, I would suggest that you want the function_from_string macro.


What’s that?

A macro that expands to a function that can render your template quickly, as it basically has been transformed into a single big string concatenation.

If though you only have a small string as in the example above, just using string interpolation might work better.


Details can be found in the page that I linked :slight_smile:

So to make this more clear, it would turn "aaa<%= key1 %>bbb<%= key 2%>ccc" into

fn key1, key2 -> 
  key1_string = to_string(key1)
  key2_string = to_string(key2)
  "aaa" <> key1_string <> "bbb" <> key2_string <> "ccc" 
1 Like

I already have a function that does that. The question is how to store a string as a template string to re-use it in the function “get_string()”.

Without using EEx which is slow.

I think the core point is that you don’t store “template strings” but you can store strings and then combine them yourself, with bespoke code or a library.

1 Like

Only when you want to evaluate the template during runtime for each time you want to apply it.

If though, you use the macros provided by eex to compile the templates at compile time of your program and inject a runtime optimized version in your code, then eex is fast enough.

phoenix uses eex by default, but is rendering templates slow? No, not really, we still manage to get sub millisecond responses, despite having to use “slow” eex.


Maybe my post was not clear enough: What I showed you was what a function like the function_from_string macro would do.

While the parsing part is ‘slow’ (but no slower than any way you might be able to do this manually), you only have to do it once, and then can re-use it every time you fill it in. You can even (and this is what e.g. Phoenix does) run the parsing step at compile-time.

This is the only way to store a ‘template string’ directly without using e.g. EEx would be to store it as quote do "aaa#{x}bbb#{y}ccc" end and later on ‘embed’ it from within another macro that you write. That is probably very messy.

@Nicd’s approach below is much better :slightly_smiling_face:

The simplest way:

defmodule Foo do
  def get_string(var1, var2) do
    # do stuff ...
    bar = my_tpl_str(var1, var2)
    # etc

  defp my_tpl_str(k1, k2), do: "aaaaa#{k1}bbbbb#{k2}ccccc"

I will ask question than no one else did: what you do with value returned from get_string/2? If you are sending it over the wire or save it to the file, then maybe you should check iodata() instead, so your “template” would look like:

def get_string(var1, var2) when is_string(var1) and is_string(var2) do
  ["aaaaa", var1, "bbbbb", var2, "cccc"]

IO.puts get_string("foo", "bar") # => aaaaafoobbbbbbarcccc

Yeah, I’m super late to this all, but I’d most definitely wrap this in a function. I’m going to give you the answer that I personally needed, going into the detail that I lacked when I came here with this same question, for posterity.

I think that this is using @variables beyond their scope. The @ symbol denotes a Module Attribute, which is constant. While module attributes serve many purposes (like annotations with @doc), when used functionally, just think that the values replace their references at compile time, and in this case, a string template variable is, by nature and name, variable.

So in action, if you have @my_token "1234", wherever you put @my_token, at compile time, the language will just “swap” (loosely) every instance of @my_token with the string value “1234”.