Questions about Protocols EEx and iolists, trying to make a performant eex engine

  1. Is there a protocol for iolists?
    Could something like String.Chars exist but where the expected return value was some iodata?
    Such a protocol could have an any implementation that fell back to using String.Chars.
  2. I can’t find a way to transform the return value at the end of the EEx process
    The “buffer” I pass to each callback has more information that I want to expose to the final user.
    I think handle_end is only called at the end of case statements etc. It seems that it is not called at all for my simple templates. e.g. <%= x + y %>

pseudo code for a handle end

  def init(_options) do
    quote do
      %{metadata: :foo, buffer: ""}
    end
  end

  def handle_end(quoted) do
    quote do
      %{buffer: buffer} = unquote(quoted)
      buffer
    end
  1. Is working with tuples much faster than maps.
    e.g.
{:safe, buffer_data} = buffer
{:safe, [buffer_data | text]}

# vs.
%{data: buffer_data}  = buffer
%{data: [buffer_data | text}

I assume this is why the Phoenix.HTML template uses the former pattern.
However because it would be very ugly for me to return the tuple form to the caller I am leaning to used the later

1 Like
  1. I’ve never seen one. I think String.Chars already returns iodata (since iodata :: iolist | binary). The first “implementation” of my iodata eex engine had a separate protocol for iolists, but I eventually didn’t find much use for it, since it mostly duplicated String.Chars.
1 Like

In my experience, yes, it is. But does it matter in eex, which to my knowledge only uses these data structures during compilation?

In your example, though, both are much slower than direct list manipulation [buffer_data | text].

My final implementation has just manipulated lists directly.
Unfortunately this means wrapping the data in a struct is a separate step.

I do the wrapping because content from a template needs to be marked as safe so that they can be used as partials in a larger template

1 Like

Or just use my ProtocolEx library. ^.^
Which is actually used in production by at least a couple of people that I know for sure, which was surprising as it started as an experiment! Those people have managed to find every bug so far and no others reported left, just more features now. :slight_smile:

I’m not sure how you are suggesting I use the library? As a replacement for EEx?

Admittedly I have only had a cursory glance so far at the library

I meant as a String.Chars-like efficient protocol that returns iodata that accepts potentially any type of ‘thing’, even Phoenix-like {:safe, ...} tuples. ^.^