Proposal Tuple.ok/1 and Tuple.error/1

34 views
Skip to first unread message

t...@scalpel.com

unread,
Apr 16, 2019, 5:04:13 PM4/16/19
to elixir-lang-core
It is often the case that you want to wrap the result of an operation in an ":ok" or ":error" Tuple. We should add convenience wrapper functions since this is so common and it cleans up otherwise ugly code.

def ok(value), do: {:ok, value}
def error(value), do: {:error, value}

OvermindDL1

unread,
Apr 16, 2019, 5:12:35 PM4/16/19
to elixir-lang-core
This could be quite useful!  On the other side it would be useful to add functions like these as well:

def ok!({:ok, value}), do: value

def ok?({:ok, _value}), do: true
def ok?(_), do: false

And so forth for error as well.  They are not really useful on their own because matching is better, but for use in pipes that would be quite useful (right now I use the exceptional library, which does similar things and more).

José Valim

unread,
Apr 16, 2019, 5:22:38 PM4/16/19
to elixir-l...@googlegroups.com
Hi Tom, thanks for the proposal.

As OvermindDL1 already hinted, this can lead to a slippery slope where we need to add bang variants, question mark variants, ok/1/2/3/4 to deal with arities and so on. I would suggest building this vocabulary as necessary in your applications or, if you want to share it with the world, it could be a nice library. Hint: the package ok_error seems to be available. :)

José Valim
Skype: jv.ptec
Founder and Director of R&D


--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/30614530-7e33-4cb8-bffb-63c18248d340%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

t...@scalpel.com

unread,
Apr 16, 2019, 5:46:20 PM4/16/19
to elixir-lang-core
I disagree that this should be a library. (I've already done this in my app and would be fine extracting it into one though) I don't buy the slippery slope argument.  The functions are very simple to create and maintain, and it's not like the Tuple module is overflowing with complexity. We have things like 'is_even' and 'is_odd' because they are common to work with. :ok and :error are insanely common in elixir codebases. Why not add convenience methods?


On Tuesday, April 16, 2019 at 5:22:38 PM UTC-4, José Valim wrote:
Hi Tom, thanks for the proposal.

As OvermindDL1 already hinted, this can lead to a slippery slope where we need to add bang variants, question mark variants, ok/1/2/3/4 to deal with arities and so on. I would suggest building this vocabulary as necessary in your applications or, if you want to share it with the world, it could be a nice library. Hint: the package ok_error seems to be available. :)

José Valim
Skype: jv.ptec
Founder and Director of R&D


On Tue, Apr 16, 2019 at 11:12 PM OvermindDL1 <overm...@gmail.com> wrote:
On Tuesday, April 16, 2019 at 3:04:13 PM UTC-6, t...@scalpel.com wrote:
It is often the case that you want to wrap the result of an operation in an ":ok" or ":error" Tuple. We should add convenience wrapper functions since this is so common and it cleans up otherwise ugly code.

def ok(value), do: {:ok, value}
def error(value), do: {:error, value}

This could be quite useful!  On the other side it would be useful to add functions like these as well:

def ok!({:ok, value}), do: value

def ok?({:ok, _value}), do: true
def ok?(_), do: false

And so forth for error as well.  They are not really useful on their own because matching is better, but for use in pipes that would be quite useful (right now I use the exceptional library, which does similar things and more).

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

José Valim

unread,
Apr 16, 2019, 6:04:55 PM4/16/19
to elixir-l...@googlegroups.com
Hi Tom,

You don't have to buy the arguments, we can agree to disagree, but they are still the reason for not adding such functions to Elixir. :)

I also agree with is_even and is_odd being similar convenience functions but they do have a rationale. They were added before defguard existed. At the time, writing guards was a bit more bureaucratic. But if is_odd/is_even were proposed today, they would most likely have been rejected as well.

Elixir already has a perfectly fine syntax via curly brackets for creating ok and error tuples, that also works on matching, so my recommendation is still to build an extra vocabulary in your app or as a separate library.

José Valim
Skype: jv.ptec
Founder and Director of R&D
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/0314757d-eff2-4b23-8130-a19ee921b254%40googlegroups.com.

OvermindDL1

unread,
Apr 16, 2019, 6:39:10 PM4/16/19
to elixir-lang-core
On Tuesday, April 16, 2019 at 4:04:55 PM UTC-6, José Valim wrote:
Elixir already has a perfectly fine syntax via curly brackets for creating ok and error tuples, that also works on matching, so my recommendation is still to build an extra vocabulary in your app or as a separate library.

Quite agree.  Though one thing that I'd find immensely useful is a way to match something out of a pipeline or error otherwise.  Like currently there is a `match?/2` function, it would be nice to have a generic `match/2` function as well, which would take a matchspec (either erlang's, with of course a nice elixir builder, or whatever...) and the value and it returns back in the form as specified.  Perhaps as a thought it could work like:

```elixir
# Via a matchspec that builds based on an `fn` similar to erlang's parse transform:
iex(1)> match({:ok, 6.28}, fn {:ok, v} -> [v] end)
[6.28]

iex(2)> match({:error, "blah"}, fn {:ok, v} -> [v] end)
** (MatchError) no match of right hand side value: {:error, "blah"}

# Or maybe have a match/3 instead with a kind an anon-fun syntax with a match/2 fallback to return all values, either by itself if 1 or as a tuple containing all?
iex(3)> match({:ok, 6.28}, {:ok, _})
6.28

# &# syntax requires the output argument
iex(4)> match({:ok, 6.28}, {:ok, &1}, &1)
6.28

iex(4)> match({:ok, 6.28}, {:ok, &1}, [&1])
[6.28]
```
Of which a pipeline usage could look like:
```elixir
things
|> might_fail()
|> match({:ok, _})
|> assert(6.28)
```
Compared to the usual (or even larger and more wordy forms):
```elixir
things
|> might_fail()
|> case do {:ok, v} -> v end
|> assert(6.28)
```
Consequently the `match/2,3` macro can be implement fairly easily by just falling down to a `case` expression with some rewriting of variable names for ease of use (or don't, force the user to 'name' out the matcher parts they want to use, though I like just `_` as a single-out nice bit, consequently this is how I implemented it in the shell for this quick test).

Potential other alternative name might be something like `match_out`, but I personally like `match` as the corresponding part of `match?`.

t...@scalpel.com

unread,
Apr 16, 2019, 6:47:56 PM4/16/19
to elixir-lang-core
Fair enough, I know when to give up on a losing battle. 

Would you consider an alternative like Tuple.wrap/1. It would work exactly like List.wrap/1 but doesn't carry the baggage that "error" and "ok" would have. This way I could still accomplish the goal of keeping pipe chains clean with something like.

value |> Tuple.wrap() |> Tuple.insert_at(0, :ok)

Which is a bit wordier but functionally equivalent to the original proposal.

Ryan Winchester

unread,
Apr 16, 2019, 6:51:31 PM4/16/19
to elixir-l...@googlegroups.com
value |> (&{&1}).() |> Tuple.insert_at(0, :ok)

For more options, visit https://groups.google.com/d/ optout .
--

You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com .
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/2e7204c7-6d06-49f9-8edc-7c631f75063a%40googlegroups.com .

Andrea Leopardi

unread,
Apr 16, 2019, 6:52:56 PM4/16/19
to elixir-l...@googlegroups.com
Just a reminder that if you're dead set on the pipeability, you can always go with an inline anonymous function:

val
|> (fn x -> {:ok, x} end).()

Not that I am a big fan of this, I'd rather go with a named helper function that you add to your application, but nonetheless this is a possibility.

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/2e7204c7-6d06-49f9-8edc-7c631f75063a%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--

Andrea Leopardi

Ryan Winchester

unread,
Apr 16, 2019, 6:54:16 PM4/16/19
to elixir-l...@googlegroups.com
Yeah, sorry

value |> (&{:ok, &1}).()

t...@scalpel.com

unread,
Apr 16, 2019, 6:58:57 PM4/16/19
to elixir-lang-core
I understand that this is possible, and thank you for the suggestion but I'm not the biggest fan of anonymous functions.

When I go back and read programs written this way I can't tell if I wrote the code or a cat walked on my keyboard.

José Valim

unread,
Apr 16, 2019, 7:07:33 PM4/16/19
to elixir-l...@googlegroups.com
If the choice is between:

value |> Tuple.wrap() |> Tuple.insert_at(0, :ok)

and

{:ok, value}

I believe we should choose the second every time.

If the choice is between:

value
|> very()
|> long()
|> pipeline()
|> Tuple.wrap()
|> Tuple.insert_at(0, :ok)

and:

value
|> very()
|> long()
|> pipeline()
|> OkError.ok()

and:

var = 
  value
  |> very()
  |> long()
  |> pipeline()

{:ok, var}

I don't see any reason why we should ever do the first one.

So I really don't see which problem Tuple.wrap is supposed to solve.


José Valim
Skype: jv.ptec
Founder and Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/721abcf1-0cfd-4824-b54a-ff2aa22487f3%40googlegroups.com.

t...@scalpel.com

unread,
Apr 16, 2019, 7:20:25 PM4/16/19
to elixir-lang-core
I see your point.

I was thinking more along the lines of consistency in the API design. If you can wrap an item in a list why can't you wrap it in a tuple? If you could wrap things in tuples then you could insert a value at the front of said tuple.This is more of an exercise in "you could" rather than "you should".
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

José Valim

unread,
Apr 16, 2019, 7:24:15 PM4/16/19
to elixir-l...@googlegroups.com
Well, the difference is really in their usage. Tuples are rarely used dynamically, you usually want to see tuples as literals in your code. The Tuple docs also mention it:

> The functions in this module that add and remove elements from tuples are
> rarely used in practice, as they typically imply tuples are being used as
> collections. To append to a tuple, it is preferable to use pattern matching


José Valim
Skype: jv.ptec
Founder and Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/5607dc54-2c5d-452c-a5a5-fa6ec03864c3%40googlegroups.com.

t...@scalpel.com

unread,
Apr 16, 2019, 7:32:33 PM4/16/19
to elixir-lang-core
I agree that they are rarely used dynamically, but when they are they can be quite the pain to work with. 

For example, if you are doing any work with ASN.1 dynamic tuples are everywhere. Any advanced work in cryptography or telecom becomes harder to work with than I would like it to be.

José Valim

unread,
Apr 16, 2019, 7:36:51 PM4/16/19
to elixir-l...@googlegroups.com
They probably shouldn't been lists in the first place but that ship sailed a long time ago.

If you need to work with them dynamically, the API is there. It just shouldn't be encouraged and adding functions such as Tuple.wrap could end-up having the opposite effect: encouraging more dynamic work making everyone's life harder, rather than easier.


José Valim
Skype: jv.ptec
Founder and Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/50776062-e75d-4f31-8266-2b633e78bf89%40googlegroups.com.

t...@scalpel.com

unread,
Apr 16, 2019, 8:02:56 PM4/16/19
to elixir-lang-core
Ok we'll paint the bikeshed green.

José Valim

unread,
Apr 16, 2019, 8:19:07 PM4/16/19
to elixir-l...@googlegroups.com
Hi Tom,

You probably meant it as a joke but just keep in mind jokes do not translate well to text.

Evaluating the language proposals is often tiresome and it is work that is not always appreciated, so it is probably best for everyone to stay in topic.

Thanks,

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/f1c5a753-6964-466b-aabb-5f8cdb7c7ec0%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--

Greg Vaughn

unread,
Apr 16, 2019, 8:26:48 PM4/16/19
to elixir-l...@googlegroups.com
José, you are so gracious in dealing with the Elixir community. I appreciate that very much. It has inspired me to work to be more gracious in my own life.

-Greg Vaughn
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2Bmvy5%3DC3cgwMPquPsrM32JjNdn0mxdsvOthLt0eXU4yg%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages