# list(FIND) vs. (theoretical) list(CONTAINS)

**URL:** https://discourse.cmake.org/t/list-find-vs-theoretical-list-contains/3814
**Category:** Development
**Created:** [July 22, 2021, 8:13am UTC](https://discourse.cmake.org/t/list-find-vs-theoretical-list-contains/3814 "2021-07-22T08:13:14Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![ferdnyc](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ferdnyc/32/267_2.png) [@ferdnyc](https://discourse.cmake.org/u/ferdnyc)
#### Post date: [July 22, 2021, 8:13am UTC](https://discourse.cmake.org/t/list-find-vs-theoretical-list-contains/3814/1 "2021-07-22T08:13:14Z")

</div>

It’s a bit of a bummer that, because `list(FIND...)` returns `0`-based index values, and `if()` interprets `0` and _only_ `0` as a `FALSE` value, the results of a `list(FIND...)` have to be compared to `-1` in order to be used as truth values.

Woe betide the `CMakeLists.txt` author who assumes this will do what they think it does:

```cmake
# NOTE: Example of BROKEN code, DO NOT USE
list(FIND AVAILABLE_THINGS ${something} _found_it)
if(_found_it)
  message(STATUS "Found ${something}!")
endif()

```

If `${something}` is in the first list postition, they’ll get a `0` for `_found_it` and the test will fail. If it’s _actually_ not found, they’ll get a `-1` for `_found_it` and the test will **succeed**.

But sometimes, you really do just want to test for presence in a list. It’s a pattern that’s used extensively in the bundled scripts, in fact. Here’s an example from `FindCURL.cmake`:

```cmake
foreach(component IN LISTS CURL_FIND_COMPONENTS)
  list(FIND CURL_KNOWN_PROTOCOLS ${component} _found)
  if(NOT _found EQUAL -1)
    list(FIND CURL_SUPPORTED_PROTOCOLS ${component} _found)
    if(NOT _found EQUAL -1)
      set(CURL_${component}_FOUND TRUE)
    elseif(CURL_FIND_REQUIRED)
      message(FATAL_ERROR "CURL: Required protocol ${component} is not found")
    endif()
  else()
    list(FIND CURL_SUPPORTED_FEATURES ${component} _found)
    if(NOT _found EQUAL -1)
      set(CURL_${component}_FOUND TRUE)
    elseif(CURL_FIND_REQUIRED)
      message(FATAL_ERROR "CURL: Required feature ${component} is not found")
    endif()
  endif()
endforeach()

```

If CMake truly supported a boolean list-membership test, let’s call it `list(CONTAINS)`, one possible rewrite for that loop woud be:

```cmake
foreach(component IN LISTS CURL_FIND_COMPONENTS)
  list(CONTAINS CURL_KNOWN_PROTOCOLS ${component} _known_proto)
  if(_known_proto)
    set(_type "protocol")
    list(CONTAINS CURL_SUPPORTED_PROTOCOLS ${component} CURL_${component}_FOUND)
  else()
    set(_type "feature")
    list(CONTAINS CURL_SUPPORTED_FEATURES ${component} CURL_${component}_FOUND)
  endif()
  if(CURL_FIND_REQUIRED AND NOT CURL_${component}_FOUND)
    message(FATAL_ERROR "CURL: Required ${_type} ${component} is not found")
  endif()
endforeach()

```

(You could also squirrel away the `_type` string as `CURL_${component}_TYPE` with 0 extra lines of code, in case it would be useful to have later.)

So my questions are:

1. Has a `list(CONTAINS)` or similar been considered in the past?
2. If so, was the idea rejected? Why?
3. Would patches1 to add such a command be entertained?

#### Notes

1. (Patches which would be fantastically easy to write, effectively `HandleContainsCommand` would just be a copy-paste — as much as I tend to loathe copy-paste code — of the existing `HandleFindCommand` from `cmListCommand.cxx`, but ~~returning~~ storing boolean values instead of list indices.)

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [July 22, 2021, 11:52am UTC](https://discourse.cmake.org/t/list-find-vs-theoretical-list-contains/3814/2 "2021-07-22T11:52:02Z")

</div>

If you want to test for list membership, there is `if ("${item}" IN_LIST list_var)`.

---

<div class="post-metadata">

### Author: ![ferdnyc](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ferdnyc/32/267_2.png) [@ferdnyc](https://discourse.cmake.org/u/ferdnyc)
#### Post date: [July 22, 2021, 1:21pm UTC](https://discourse.cmake.org/t/list-find-vs-theoretical-list-contains/3814/3 "2021-07-22T13:21:22Z")

</div>

I _completely_ forgot about `IN_LIST`!

I even checked the `if()` docs, but

1. Unlike the `list(...)` docs, there’s no handy TOC at the top to provide an overview of the possible forms. (Maybe I’ll submit a PR for that.)
2. `IN_LIST` isn’t included in the set of operations listed in the [Condition Syntax section](https://cmake.org/cmake/help/v3.21/command/if.html#condition-syntax).
3. I’m blind/careless, and just somehow failed to spot it at the bottom of the [Existence Checks section](https://cmake.org/cmake/help/v3.21/command/if.html#existence-checks).

D’oh! Thanks.

---

<div class="post-metadata">

### Author: ![ferdnyc](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ferdnyc/32/267_2.png) [@ferdnyc](https://discourse.cmake.org/u/ferdnyc)
#### Post date: [July 22, 2021, 1:23pm UTC](https://discourse.cmake.org/t/list-find-vs-theoretical-list-contains/3814/4 "2021-07-22T13:23:05Z")

</div>

> [@ferdnyc](#):
>
> Unlike the `list(...)` docs, there’s no handy TOC at the top to provide an overview of the possible forms. (Maybe I’ll submit a PR for that.)

In fact, the more I compare the two, the more lacking the `if()` documentation appears compared to `list()`. It really does need some love.
