This is my first blog post and it turned out to be a long one. I wrote about how lists and improper lists work.
Nice blog, very clean layout. Did you roll it yourself? I suggest to add a RSS feed and a <link rel="alternate" ...>
pointing to your feed in the homepage.
I used this eleventy template: GitHub - kohrongying/11ty-blog-starter: 11ty, Tailwind. Works when JS is disabled
I liked because itās clean and supports light/dark mode, I just had to add OpenGraph metatags to the base template.
Iām still figuring out how to configure eleventy, once I have that sorted out I will try to add an RSS feed as you suggest.
The RSS Atom feed is up.
I also added an additional section on the IO Lists definition, since the typespec as shown in the documentation is not quite clear. It turns out iolists are made of iohead
s and iotail
s, and tails cannot be bytes, but heads can. In the type maybe_improper_list(a, b)
, a
is the contents and b
the termination, as mentioned in Erlang -- Types and Function Specifications.
So if iolist is defined as maybe_improper_list(byte() | binary() | iolist(), binary() | [])
Then this works:
iex> :erlang.iolist_to_binary([1 | "2"])
<<1, 50>>
But this breaks with a not very useful error message:
iex> :erlang.iolist_to_binary([1 | 2])
** (ArgumentError) argument error
:erlang.iolist_to_binary([1 | 2])
better not to try your luck everywhere with improper list. The only core erlang lib that I know that returns an improper list is:
iex(1)> :string.next_codepoint("abc")
[97 | "bc"]
It sorta makes sense because it is a no-op for charlist strings:
iex(3)> :string.next_codepoint('abc')
'abc'
If someone is going to redesign erlang from the ground up it is probably better to make improper list or cons cell a synonym of 2-tuple, so everything can make a lot more sense. but whatever.
I completely agree with you, this was mostly an exploration of the language rather than a recommendation or trying to find places where to use them. I found places where the docs were a little ambiguous or descriptions of the same thing were scattered around, so I also tried to somewhat document that.
There are places where improper lists are super handy and having them identical to 2-ary tuples would be irritating. For example I used cons cell instead of tuples in BARE implementation due to fact, that 2-ary tuples can be used for other things there, and I didnāt wanted to have some heuristic there to deduce whether it is proper type or field ID specifier.
That could cause a lot of confusion if sometime a chain tuples appears as a list and sometimes as tuples. I definitely like being very explicit and not try and be too kind and helpful. It is bad enough now as it is with strings.
t would also make the display function a bit more complex.
This is not exactly about Elixir, but about how to apply an Elixir design pattern to Javascript. Many people here write a bit of client side Javascript so I think it is relevant.
I often find myself having to ātagā my with clauses, often because checking {:ok, _}|{:error, _}
isnāt descriptive enough for error handling,
with {:post, {:ok, post}} <- {:post, fetch_post(id)},
{:meta, {:ok, meta}} <- {:other_data, fetch_post_meta(post)},
{:auth, :ok} <- {:auth, authorize(...)},
do: ...
else
{:post, {:error, reason}} -> show_404_or_whatever()
{:meta, {:error, reason}} -> show_post_but_flag_error_or_something()
{:auth, :unauthorized} -> redirect_to_login()
end
vs
with {:ok, post}} <- fetch_post(id),
{:ok, meta}} <- fetch_post_meta(post),
:ok <- authorize(...),
do: ...
else
# cant tell here if {:error, reason} is for fetch_post or fetch_post_meta
{:error, reason} -> generic_error(reason) #?
:unauthorized -> redirect_to_login()
end
Is this pattern implied in your posts or do you have another solution? Always match on specific reason
values? Maybe you simply structure the rest of the app so it isnāt needed (ie: the call should pass in meta
before we even get to the with or ?).
I donāt find tagging to be that bad, but it does add some noise and it can feel like if you have to tag any, you should tag them all, so even stuff like :ok|:unauthorized
end up getting tagged.
Great posts.
Great question!
I mostly try to avoid tagging in with
, because I feel it makes the code harder to understand. At VBT projects we use a credo check to prevent this pattern. Before I started working with them, the team was using this pattern extensively, and no one really misses it now
In this particular example, Iād make the core function return something like {:ok, post_with_meta} | {:error, :not_found | {:no_meta, post} | :unauthorized}
, which I think clearly communicates what can go wrong with a business operation.
The client such as controller or absinthe resolver can now do something like:
case Core.fetch_post(...) do
{:ok, post_with_meta} -> ...
{:error, :not_found} -> ...
...
end
We mostly work with graphql, and we use some company-wide absinthe middleware that automatically handle common errors, such as unauthorized or Ecto.Changeset.t
, which keeps the resolver code small and focused.
Iām doing live coding using Elixir programming language, explaining basic functional programming abstractions like parametric and ad-hoc generics (polymorphism), functors, functional composition, currying and lazy evaluation.
Thank you got this series. Not sure if itās a lot of work, but I would have found it helpful if the article series had an index of the articles (or was a doubly linked list, lol). When I finished the first, I wanted to immediately go to the second and so on.
Even medium has RSS, and the RSS contains full text.
just subscribe https://medium.com/feed/very-big-things in your favorite feed reader.
If you donāt have a favorate feed reader, you can use this link:
https://airss.roastidio.us/?url=https://medium.com/very-big-things
The above link use GitHub - derek-zhou/airss: A light weight feed reader that runs in your browser, with no backend that come with some caveats though. You may want to read it first.
Iāve just published a piece on PostgreSQL EXPLAIN ANALYZE. Itās not strictly about Elixir but since PG is popular with Phoenix apps I though Iād share it here: