Ambiguity in `first`
Closed this issue · 5 comments
first([None])
equals to first([])
.
Related thread on SO.
Turns out like this is not trivial issue.
This is by design.
Other two possibilities - return some strange value or raise error are both less handy. First one doesn't even resolve ambiguity, only lessens the chance. And raising exception is far less composable than returning None
.
What are use cases:
- You know that there is no
None
s in a sequence. - You don't care.
- You don't know and you care.
In my experience 1 and 2 are far more often than 3, and first
will do the job for them. And even when you hit 3 you can use:
seq[0] # for non-lazy sequence
next(seq) # for iterator
next(iter(seq)) # if you don't know
Not as pretty and self-telling sure, but that's for a rare case.
Check paragraph in Real World Haskell.
Scroll to text
Several of the functions above...
Exceptions are actually composable, you just need to handle them in your composition =)
Another option that I see - make default
argument for first
, like everywhere in Python.
As I see - crashy first
is actually right thing, because from my experience - if you need this function, than its likely that you processing non-empty list, and if it becomes empty - some special handling kicks in.
And I cant agree with "use cases" part - how could you don't care if there is the ambiguity? Ambiguity is BAD, so you should care.
2 is rare as is 3. 1 is most common, so 1 + 2 far more often than 3.
Exceptions are composable in principle and return values are composable in Python with plain functions, including builtings like map
or sort
. first
used to raise exception, but then I noticed that I use silent(first)
too often. I then found all first
usages and found not a single example of scenario 3. So from my experience, returning None
is the best solution here.
Another interesting point that you didn't came here because you have a practical problem, you are arguing on basis of purity. And there is nothing wrong with that, besides practicality beats its )
So, yes first
is not pure, I know this and I think that's ok. Only real practical examples of code where this is inconvenient can change my mind.
I actually just wanted to discuss function design =)
My point is not about purity, your first
is actually pure. My point is - if function does some exceptional behavior - it must be handled with exception or with something else.