Suor/funcy

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.

Suor commented

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:

  1. You know that there is no Nones in a sequence.
  2. You don't care.
  3. 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.

Suor commented

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 )

Suor commented

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.