I think this has been brought up a few times and not sure there's a great need for it. It can't (shouldn't) happen _that_ many times, because if you're not going to do something with the result of a function the chances are you should be bothering to do_something() to the function anyway. And even then there are a few other ways this can be done that are arguably cleaner.
1. You have to write "write_y()" function anyway, so create a version that has a no-op version that simply returns the argument:
def write_y(y, arg0, arg1, skip \\ false)
def write_y(y, _, _, false), do: y
def write_y(y, arg0, arg1, _) do
....
2. You can write an anonymous function inline that contains your logic pretty easily, although I don't think this syntax is well-liked, it's at least clear.
some_value
|> do_something()
|> (fn y ->
if y_needed, do: write_y(y, arg0, arg1), else: y
end).()
3. What you don't say whether or not the function called in the "then" function actually returns the original piped value, or if it returns the result of the "write_y" function. There _has_ been discussion about a "tap" function that would let you basically encapsulate the logic in the previous inline function example but be _sure_ to always return the original piped value (so you don't forget the "else: y" bit). I don't remember if that was something that eventually was decided or not, but it's a simple function to write yourself if you really want it:
def tap(value, block) do
block.(value)
value
end
some_value
|> do_something()
|> tap(fn y ->
if y_needed, do: write_y(y, arg0, arg1)
end)
The difference between #2 and #3 is what is ultimately returned if "y_needed". The "tap" function sees a lot more use cases, I think, because "side effects" are a more frequent occurrence -- tossing something into a job queue, writing off a log message that isn't just "IO.inspect", triggering an asynchronous operation, etc. Things where you want to do something with an intermediate value but don't want to change it in the process.
I'm hard pressed to come up with a really great example of where you may want to conditionally do something to a value inline that isn't better handled with functional logic. The idea of "conditionally apply sales tax to a price calculation" comes to mind, but you would encapsulate the logic into the function anyway, because the actual sales tax rate is different per state. I'd expect that to be more like:
item
|> apply_quantity_discount(quantity)
|> apply_sales_tax(state). # apply_sales_tax would know whether or not to do anything based on the state
You say you have to do this "often" -- can you give us some real-world examples of your code logic that you feel necessitates this kind of thing? I really can't think of too many, and wonder if maybe there's just a better way for you to think about the problem in the first place?
...Paul