Proposal: Allow IO.inspect to accept a function as argument

131 views
Skip to first unread message

mar...@lob.com

unread,
Jan 12, 2018, 4:59:04 PM1/12/18
to elixir-lang-core
I often find myself wanting to inspect things in the middle of a chain of pipes, but I don’t always want to inspect the return values as-is. Sometimes I want to inspect sub-attributes or call functions on the return values to inspect them.

For example, imagine the contrived pipeline below.

["thing1", "thing2"]
|> generate_more_things()
|> do_something_with_things()

If I want to know the length of the list returned by generate_more_things/1, I would do this:

["thing1", "thing2"]
|> generate_more_things()
|> (fn things ->
  things |> length() |> IO.inspect()
  things
end).()
|> do_something_with_things()

If IO.inspect can take a function as an argument, print the inspection of the result of calling that function, but still return the un-altered input, I could do this:

["thing1", "thing2"]
|>
generate_more_things()
|> IO.inspect(fn things -> length(things) end)
|> do_something_with_things()

Or even:

["thing1", "thing2"]
|>
generate_more_things()
|> IO.inspect(&length/1)
|> do_something_with_things()

I think this would aid during debugging and be a useful feature in the standard library. I'd love to implement and contribute on this, but I wanted to see if such a thing would be accepted before beginning work.

Open to feedback!

José Valim

unread,
Jan 12, 2018, 6:18:49 PM1/12/18
to elixir-l...@googlegroups.com
Thanks for the proposal!

Unfortunately that would make us unable to inspect functions themselves, which is a valid argument to IO.inspect after all.

Imagine the confusion of trying to inspect a pipeline that may emit an anonymous function only to find it is being executed instead.



José Valim
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-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/4e2bfad0-b745-4059-8736-996e641c7bb2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Greg Vaughn

unread,
Jan 12, 2018, 6:31:17 PM1/12/18
to elixir-l...@googlegroups.com
I like the original idea and would like to suggest another approach. What if there were an additional Inspect.Opts of :transform? It then would enable this sort of thing:

["thing1", "thing2"]
|> generate_more_things()
|> IO.inspect(transform: &length/1)
|> do_something_with_things()

-Greg Vaughn
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
> --
> 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/CAGnRm4KAvw%2BwWnh7d60%3DvKEkuLvWfyoh4XuM9rbuxz_CaLg9%3DA%40mail.gmail.com.

OvermindDL1

unread,
Jan 13, 2018, 10:38:22 PM1/13/18
to elixir-l...@googlegroups.com
Or call it `map` as it's shorter and perfectly descriptive.  I've made a few variants of this myself and I'd love it built into IO.inspect.

> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.

> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/4e2bfad0-b745-4059-8736-996e641c7bb2%40googlegroups.com.
> 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-core+unsubscribe@googlegroups.com.
--
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-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/6CF01F3F-5848-4E19-BCA1-9D256824D6E0%40gmail.com.

Marcus Gartner

unread,
Jan 15, 2018, 11:31:09 AM1/15/18
to elixir-l...@googlegroups.com
Doh! I should have realized the issue with executing the function passed. 

I like the idea of a transform option that can be passed.

IO.map makes sense in my example, but wouldn't make sense to me if the pipeline wasn't dealing with an enumerable, and it would be nice if this feature was general enough to work idiomatically with any possible values. 

> 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/4e2bfad0-b745-4059-8736-996e641c7bb2%40googlegroups.com.
> 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/CAGnRm4KAvw%2BwWnh7d60%3DvKEkuLvWfyoh4XuM9rbuxz_CaLg9%3DA%40mail.gmail.com.
> 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.
--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/TUkmNHI4IbI/unsubscribe.
To unsubscribe from this group and all its topics, 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/CAJhqboH_tYYRPFWf8HuVJru5phmOmU7tK_PDWVca36mUfWhJ8Q%40mail.gmail.com.

Martin Svalin

unread,
Jan 15, 2018, 4:14:54 PM1/15/18
to elixir-l...@googlegroups.com
`map` would have the connotation of applying a function to all elements of a collection. `apply` would more directly have the connotation of running a function with some arguments.

`IO.inspect(value, apply: &length/1)`

I like the idea of being able to narrow down what I'm inspecting during the print-debugging workflow I inevitably regress to. `nested_structure |> IO.inspect(apply: & get_in(&1, [:foo, :bar, :baz]))`. Thumbs up for the idea.

José Valim

unread,
Jan 15, 2018, 4:28:10 PM1/15/18
to elixir-l...@googlegroups.com
The more general construct here would be a tee:

["thing1", "thing2"]
|> generate_more_things()
|> IO.inspect(transform: &length/1)
|> do_something_with_things()

could be written as:

["thing1", "thing2"]
|> generate_more_things()
|> tee(&IO.inspect(length(&1))
|> do_something_with_things()

Note IO.inspect is already a tee.

José Valim
Founder and 
Director of R&D
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.

> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/4e2bfad0-b745-4059-8736-996e641c7bb2%40googlegroups.com.
> 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-core+unsubscribe@googlegroups.com.

> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4KAvw%2BwWnh7d60%3DvKEkuLvWfyoh4XuM9rbuxz_CaLg9%3DA%40mail.gmail.com.
> 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-core+unsubscribe@googlegroups.com.
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/TUkmNHI4IbI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-lang-core+unsubscribe@googlegroups.com.

--
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-core+unsubscribe@googlegroups.com.

--
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-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAAHw6CLuxuNsnk-JWCTPtCr4_fsQG13eUQC3ajW5Ca2LkWwdLQ%40mail.gmail.com.

Kelvin Raffael Stinghen

unread,
Jan 15, 2018, 8:26:02 PM1/15/18
to elixir-l...@googlegroups.com
The `tee/2` idea is wonderful!! This way we can use it for any function, not just `IO.inspect`. One word: PERFECT!!!

I am opening a PR for it...

Best,
Kelvin Stinghen
kelvin....@me.com

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/CAGnRm4Ji7kAjv5i4_04AVp-hae4ghj1DgZx1zr%2B4LyGBYpj5_A%40mail.gmail.com.

Kelvin Raffael Stinghen

unread,
Jan 19, 2018, 11:10:11 AM1/19/18
to elixir-lang-core
It happens that the `tee/2` function was not merged to elixir core because not too much people could bring real-life examples for using it except for debugging.

But for those who liked the idea and want to use the `tee/2` function, I've created the [`plumbing`](https://github.com/kelvinst/plumbing) package.

Best,
Kelvin Stinghen
kelvin....@me.com

mar...@lob.com

unread,
Jan 19, 2018, 11:43:17 AM1/19/18
to elixir-lang-core
`apply` is succinct and clear. I created a PR here: https://github.com/elixir-lang/elixir/pull/7229

It's been closed for now, until something (if anything) is agreed upon.

Are there downsides of adding `apply` to IO.inspect/3 that outweigh the benefits?

Federico Bergero

unread,
Jan 19, 2018, 11:57:41 AM1/19/18
to elixir-lang-core
I have a real-life example (not for debugging). I'm actually tee function (my own trivial implementation).

Suppose you have to change some records on a Repo (using Ecto) and the send some notifications about those changes.
We are doing something like this:

changeset =
   E
   |> Repo.get(id)
   |> E.some_change()
   |> E.some_other_change()

Repo.update!(changset)

Notification.send(changeset)

with the tee function we could write it like 
E    
|> Repo.get(id)
|> E.some_change()
|> E.some_other()
|> tee(&Repo.update!/1)
|> Notification.send()

I think the tee function is very useful for general cases.


 


Best,
Kelvin Stinghen
kelvin....@me.com

> 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/4e2bfad0-b745-4059-8736-996e641c7bb2%40googlegroups.com.
> 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/CAGnRm4KAvw%2BwWnh7d60%3DvKEkuLvWfyoh4XuM9rbuxz_CaLg9%3DA%40mail.gmail.com.
> 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.
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/TUkmNHI4IbI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-lang-co...@googlegroups.com.

--
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.

--
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.

--
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.

mar...@lob.com

unread,
Jan 30, 2018, 5:38:55 PM1/30/18
to elixir-lang-core
Any other thoughts on this? I'd like to continue the discussion or move forward with a decision to include or not include something like IO.inspect with an :apply option. I'm very open to changes in the name of the option, but the general functionality of a function that can transform the item to be inspected, but still returning the original input. This is something that I feel would be very helpful in debugging use-cases.

José Valim

unread,
Jan 30, 2018, 7:02:27 PM1/30/18
to elixir-l...@googlegroups.com
We don't plan to include such functionality for now. I am not convinced the generic function is generally useful and I am not sure an option to IO.inspect will be used that frequently other than a handful of developers that read the fine print.

I understand the latter is not a strong argument though and that can be a bit frustrating.

In any case, we do appreciate your proposal and contributions.



José Valim
Founder and 
Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/29087b37-89f9-4bf8-a77c-f471a1a11613%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages