Literally a 1 char change: <https://github.com/arr...
# arrow-contributors
p
Literally a 1 char change: https://github.com/arrow-kt/arrow-fx/pull/286/files If anyone is feeling lucky 😎
c
mmm... why are you throw exceptions?
p
I'm not 😅 that was there before. It's an terminal operation that propagates the fact that there is no items upward
There is another method called
firstOrNull()
c
I see, it is only a "helper" function that could be useful in some cases
r
All terminal ops run effects and can be considered unsafe in streams. That’s why they are
suspend
so the effects including exceptions are handled by the continuation that runs the suspended program.
💯 2
by being suspend they are pure because they can only be composed in other suspend function, so while throwing the exception isn’t great it does not break referential transparency
c
👌
k
sorry for hanging up on this, but I don’t understand is, why don’t we explicitly return an Either<Error, O>, the caller could explicitly trigger the throw with
getOrThrow
? Should I understand more about where to use Either and where not to?
p
I've been thinking about that @kioba if we mirror the API from
Option
to nullables it could be possible to do:
Copy code
stream.first().orElse { error("Oops!") }
If first() returns nullable
r
@pablisco
firstOrElse
?
p
Well, I’m thinking about composition of these functions:
Copy code
fun <O> Stream<O>.first() : O?
fun <O> O?.orElse(block: () -> O) : O
As I mention here: https://github.com/arrow-kt/arrow-fx/pull/291#discussion_r497532005 This means that other operations that result in a nullable can benefit of that api, even the ones that are not part of Arrow. It would mean that we don’t have to maintain
firstOrElse
or similar for other types like ListK, etc. That said, I see the benefit of having shortcuts. For instance if we do:
Copy code
stream.effectTap { .. }.drain()
We could have:
effectDrain {}
which does something similar… However, maybe there is a way we can automate/generate these composite shortcuts (are these comprehensions?) using Meta 🤔
👍 1
IMHO: smaller API = ❤️
👍 1
r
smaller api is better, agreed
And in that sense how is
orElse
different than
?:
p
They are functionally the same. The only difference is that
orElse
is easier to chain with other operations. Obviously, in this case we are talking about a terminal operation but I can see cases where it would facilitate working with the result from
?:
Which involves wrapping the statement in parentheses. The other thing is that it can be used to make the code more readable to some people:
Copy code
fetchMemory()
  .orElse { fetchLocal() }
  .orElse { fetchRemote().andSave() }
Vs
Copy code
fetchMemory() ?: fetchLocal() ?: fetchRemote().andSave()
Which, if a well intended developer comes after and adds some parentheses:
Copy code
fetchMemory() ?: (fetchLocal() ?: fetchRemote()).andSave()
Boom! Behaviour is now changed 😅
Also,
orElse
can be considered a
flatMapLeft
, kind of, right?
r
yeah not opposed, I think those are valid cases.
specially if it’s all inlined
p
Damn it! I just tried to see if it was possible, but it’s not possible to do:
Copy code
inline class Option<out A>(val value: A?)
nor:
Copy code
typealias Option<A> = A?
😞 That would have been so nice for migration 😅