giddie

giddie

Ok_then - The Swiss Army Knife for tagged tuple pipelines

GitHub: GitHub - flexibility-org/ok_then: The Swiss Army Knife for tagged tuple pipelines · GitHub
HexDocs: OK then... — ok_then v1.1.0

I just couldn’t quite find what I was looking for when it came to handling tagged tuples. In particular, I really wanted to find an elegant solution to the problem of missing return values that are not errors. Because sometimes, a missing return value is an error, and other times it’s not. Rust handles this very elegantly, using separate Result (Ok / Error) and Option (Some / None) types, often in tandem.

So I decided I had to write my own solution for handling tagged tuples. And I’m quite pleased with the result. Of course I have to give credit to those who have gone before, such as the authors of the “OK” and “Croma” packages.

The most controversial feature will be the addition of :none alongside :ok and :error, though this becomes mostly transparent in pipelines.

There are a few more functions I’d like to add, in particular to the Result.Enum module. And I’d also like a monadic “with”-like macro, similar to that offered by the “OK” package.

First Post!

wmnnd

wmnnd

Seems like a neat idea! You’ve already mentioned that you think adding :none might be controversial - why do you think it’s still useful?
After all, nil is also simply an atom (is_atom(nil) == true and nil == :nil) :slight_smile:

Most Liked

dimitarvp

dimitarvp

What does a new convention of :ok / :none achieve that hasn’t been achieved by the :ok / :error convention?

If a function does not return data then it can just return :ok (not a tuple).

When you say semantics and consistency, I am not seeing it. It’s OK to have a personal preference but I don’t see the value.

As for nil, well, I think we all know that’s a huge and very expensive mistake in computer science in general. But as others pointed out, nil is also an atom so replacing it with another one doesn’t help much. Not sure I am seeing the argument for the stack traces as well.

Maybe I just don’t get it though.

dorgan

dorgan

There are some functions that return none, like erlang:dist_ctrl_get_data, erlang:system_info, but it seems in those cases it means “set to none” or “not available” rather than “not found”

giddie

giddie

Yes, absolutely. The ok_then library will also accept any bare atom (:some, :success, :ok, …). It interprets these internally as {:ok, {}}, {:some, {}}, ..., so mapping functions will receive {} as the wrapped value, and that’s what unwrap!() would return too. It’s just that :none is returned by Result.from/1 and Result.map/2 if they receive nil as a value to wrap, and there are shorthand functions to handle :none, such as default/2 and none_then/2.

So if you want, you could fall back to a bare :ok quite easily like this:

Result.from(nil)      # :none
|> Result.default({}) # :ok

# or

Result.from(nil)         # :none
|> Result.none_then(:ok) # :ok

I’d be interested in some testcases, actually. Could I tempt you to come up with some examples of vanilla Elixir that we could compare to an equivalent using the ok_then library?

Last Post!

giddie

giddie

Version 1.1.0 has been released, with the following notable additions:

Result.tap(result, func_or_value) and related functions
This function behaves like Kernel.tap/2, but calls the function only if the result was tagged as expected:

iex> {:ok, "hello"} |> Result.tap(&IO.puts/1)
hello
{:ok, "hello"}

A 0-arity function is accepted, if you only really care about :ok/:error, rather than the value:

iex> {:ok, "hello"} |> Result.tap(fn -> do_something() end)
{:ok, "hello"}

The function is not called if the tag doesn’t match.
Naturally, error_tap/2 and tagged_tap/3 are available too.

Result.default!(result, value) and family
If you know a default value should never be nil, a bang-variant of the “default” functions is now available that will raise if the value is nil, instead of returning :none:

iex> :none |> Result.default!("hello")
{:ok, "hello"}

iex> :none |> Result.default!(nil)
** (ArgumentError) Value is nil.

Result.filter/2 now accepts 0-arity functions and truthy values
Previously this function accepted only a 1-arity function, but there are situations where the value is irrelevant, or relies on an external value, and this is now possible:

iex> {:ok, "hello"} |> Result.filter(fn -> true end)
{:ok, "hello"}

iex> {:ok, "hello"} |> Result.filter(false)
:none

Where Next?

Popular in Announcing Top

Qqwy
Hello everyone, I wrote a small library today called MapDiff. It returns a map listing the (smallest amount of) changes to get from map...
New
Crowdhailer
Experimenting with this code. OK.try do user <- fetch_user(1) cart <- fetch_cart(1) order = checkout(cart, user) save_orde...
New
michalmuskala
Hello everybody. I have just released Jason - a new JSON library. You might be wondering, why do we need a new library? The primary foc...
New
versilov
Could not wait for the missing Elixir ML libraries to appear, so, I wrote one myself, taking https://github.com/sdwolfz/exlearn as a foun...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
Qqwy
TypeCheck: Fast and flexible runtime type-checking for your Elixir projects. Core ideas Type- and function specifications are const...
336 14713 100
New
restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 10739 134
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49134 226
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

We're in Beta

About us Mission Statement