Skip to content

first and last return nothing on empty results#17054

Merged
fdncred merged 1 commit intonushell:mainfrom
fdncred:first_list_return_nothing_on_empty
Nov 22, 2025
Merged

first and last return nothing on empty results#17054
fdncred merged 1 commit intonushell:mainfrom
fdncred:first_list_return_nothing_on_empty

Conversation

@fdncred
Copy link
Copy Markdown
Contributor

@fdncred fdncred commented Nov 21, 2025

This PR changes the behavior of first and last when encountering empty results. This is done so that one can more easily use default to provide a default value when results are empty. e.g.

[a b] | where $it == 'c' | last | default 'd'
# => d

Release notes summary - What our users need to know

We changed the behavior of first and last when encountering empty results. Previously first and last would error on an empty list. They now return null instead.

This is done so that one can more easily use default to provide a default value when results are empty. e.g.

[a b] | where $it == 'c' | last | default 'd'
# => d

[] | first | default 'hi'
# => hi

Tasks after submitting

@fdncred fdncred added notes:breaking-changes This PR implies a change affecting users and has to be noted in the release notes X:controversial There's disagreement over if/how this should be implemented. PRs implementing this may not be merged A:commands General additions or changes to commands labels Nov 21, 2025
Copy link
Copy Markdown
Contributor

@WindSoilder WindSoilder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, lGTM

@fdncred fdncred merged commit 706cd41 into nushell:main Nov 22, 2025
29 of 30 checks passed
@fdncred fdncred deleted the first_list_return_nothing_on_empty branch November 22, 2025 02:07
@github-actions github-actions bot added this to the v0.109.0 milestone Nov 22, 2025
@weirdan
Copy link
Copy Markdown
Contributor

weirdan commented Nov 22, 2025

Note that with this change in place you can't distinguish [] from [null] with last - you have to check for list length now. Previously, the following would have worked:

[null] | try { last } catch { print "empty" }

and now it will need to be

[null] | if ($in | is-not-empty) { last } else { print "empty" } # will also collect, because of $in

whereas previously the default could still be used on empty lists like this:

[] | try { last } | default "n/a"

@fdncred
Copy link
Copy Markdown
Contributor Author

fdncred commented Nov 22, 2025

but now you can do this, no try needed

[null] | last | default empty
empty
[] | last | default empty
empty

@weirdan
Copy link
Copy Markdown
Contributor

weirdan commented Nov 23, 2025

If you didn't care about null elements of the list, you could do

[] | default -e [null] | last
# or 
[] | default -e [empty] | last

But if you do care, you now can't tell if it was the last element that was null or if there were no elements at all (without an explicit length check).

@fdncred
Copy link
Copy Markdown
Contributor Author

fdncred commented Nov 23, 2025

But if you do care, you now can't tell if it was the last element that was null or if there were no elements at all (without an explicit length check).

I'm not trying to be rude, but why do I care to know if the last element was null or no elements at all. The point is to use it easily with default and replace what was there with a default value.

BTW - I'm fine with changing this as long as it works the same way it does now. e.g. we can add parameters to default or first/last but I think the way this PR changes things should be the default way it works.

@weirdan
Copy link
Copy Markdown
Contributor

weirdan commented Nov 23, 2025

why do I care to know if the last element was null or no elements at all.

If we follow that logic, then [] should be equal to [null], but it's not the case. You may want to care if the list (or stream) represents the results of some operations, where each individual operation may result in null (for example, processing a list of files), and you want to handle the case where there were no operations at all (no files found) differently to when the last/first operation resulted in null.

Previously, you had the option to do try { first } | default "n/a" (which I find very clear and expressive) if you didn't care about nulls / errors, or try { first } catch { handle the error } if you wanted to handle the empty list/stream case, but not the null case, or just first if you wanted the error to bubble up. There were multiple ways to handle different cases, depending on what you need. Now that the output domain of these functions is narrowed, that choice is gone, or, at the very least, will have to be done in a different place with a different method (length checks?).

I'm fine with changing this as long as it works the same way it does now.

If you mean 'now' as in 'on current main', that sounds a bit contradictory ("it's ok to change as long as nothing changes").

we can add parameters to default or first/last

What kind of parameter do you have in mind? Opt-in to null return on out-of-bounds read (e.g. first --optional, similar to get --optional), or opt-in to errors on out-of-bounds read (first --strict, like path expand --strict)?

@WindSoilder
Copy link
Copy Markdown
Contributor

What kind of parameter do you have in mind? Opt-in to null return on out-of-bounds read (e.g. first --optional, similar to get --optional), or opt-in to errors on out-of-bounds read (first --strict, like path expand --strict)?

Let's try to add --strict to first and last command

WindSoilder added a commit that referenced this pull request Nov 24, 2025
…empty list. (#17066)

As title, this pr adds `--strict` flag to `first` and `last` command, so
they will raise error on empty list. This is a follow up to #17054

## Release notes summary - What our users need to know
By default, `first` and `last` will return `null` on empty list, this pr
is going to add `--strict` to make it returns on error.

```
> [] | first --strict
Error: nu::shell::access_beyond_end

  × Row number too large (empty content).
   ╭─[entry #1:1:6]
 1 │ [] | first --strict
   ·      ──┬──
   ·        ╰── index too large (empty content)
   ╰────
```

## Tasks after submitting
NaN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A:commands General additions or changes to commands notes:breaking-changes This PR implies a change affecting users and has to be noted in the release notes X:controversial There's disagreement over if/how this should be implemented. PRs implementing this may not be merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants