find
find locates objects by name in R’s search path. It returns the environments where a matching object exists. This is useful for debugging namespace conflicts, tracing where a function or variable comes from, and understanding R’s search order.
find lives in the utils package, which ships with base R and is always available.
Signature
find(what, mode = "any", numeric = FALSE, simple.words = TRUE)
Arguments:
what, object name to search for (whole word match by default)mode, filter by object mode:"any","function","numeric","character", etc.numeric, ifTRUE, return search path positions instead of environment namessimple.words, ifTRUE, matchwhatas a whole word (not a regex)
Returns: A character vector of environment names, or a named numeric vector of positions.
Basic usage
find("mean")
# [1] "package:base"
find("data.frame")
# [1] "package:base"
# Your own objects appear in .GlobalEnv
my_var <- 42
find("my_var")
# [1] ".GlobalEnv"
The search path is the chain of environments R consults whenever you type a bare name — it starts with your global environment, then walks through attached packages in order of attachment. Understanding this chain is essential for diagnosing why a particular function resolves to an unexpected package version or why a workspace variable silently overshadows a function you meant to call.
Finding multiple matches
find("cor")
# [1] ".GlobalEnv" "package:stats"
# You have a 'cor' object in your workspace
# and stats::cor is also on the search path
This is the classic namespace conflict: you have an object with the same name as a package function. Use find() to diagnose it.
The numeric argument
Set numeric = TRUE to get search path positions instead of names. The numbers correspond directly to positions in search(), which lists all environments R checks when resolving a name. Position 1 is typically .GlobalEnv, with attached packages occupying subsequent positions.
find("mean", numeric = TRUE)
#> .GlobalEnv package:base
#> 4
# Verify against search() output
search()
#> [1] ".GlobalEnv" "package:stats" "package:base" ...
The numeric positions returned by find(..., numeric = TRUE) correspond directly to indices in search(), making it straightforward to cross-reference. This is helpful in scripts that need to identify where a name lives programmatically — for example, checking whether a user-defined function masks a package function before calling it.
Filtering by mode
The mode argument restricts matches to objects of a specific type — "function" for functions, "numeric" for numbers, "character" for strings. Without mode filtering, find() returns every object with that name regardless of type, which matters when a variable and a function share the same name.
find("cor", mode = "function")
#> [1] "package:stats"
# Combine mode with numeric for position-based filtering
find("cor", mode = "function", numeric = TRUE)
#> package:stats
#> 2
Common mode values: "any", "function", "numeric", "character", "logical", "list", "environment". The mode argument uses R’s internal storage modes, so "numeric" matches both integer and double vectors, while "character" matches only character vectors. This level of filtering lets you disambiguate names that appear as multiple types on the search path.
simple.words and regular expressions
By default (simple.words = TRUE), find matches the name exactly as a whole word:
find("data.frame")
# [1] "package:base"
Set simple.words = FALSE to use regex matching. This changes find() from an exact-name lookup into a pattern-matching tool, where the what argument is treated as a regular expression. The dot character in data.frame needs escaping with a backslash since . matches any single character in regex — failing to escape it leads to surprising matches against names like dataframe or dataXframe.
find("data\\.frame$", simple.words = FALSE)
# [1] "package:base"
Regex matching is case-sensitive, even if you might expect it not to be.
Diagnosing namespace conflicts
The most common use of find is figuring out why a different function runs than expected. When you load dplyr, stats::filter gets masked — find("filter") reveals the conflict immediately by showing both packages on the search path. Similarly, a variable in your workspace masks a package function with the same name; find() shows the variable in .GlobalEnv first, but adding mode = "function" reveals the hidden package function behind it.
# dplyr::filter masks stats::filter after library(dplyr)
library(dplyr)
find("filter")
#> [1] ".GlobalEnv" "package:stats" "package:dplyr"
# A workspace variable masking a package function
df <- data.frame(x = 1:5)
find("df") #> [1] ".GlobalEnv"
find("df", mode = "function") #> [1] "package:base"
Relationship to apropos
apropos() finds objects by partial name matching — it returns all names containing a pattern. find() does the reverse: given an exact name, it tells you where that object lives on the search path. Use apropos to discover functions you do not know the exact name of; use find to trace the origin of a name you already have.
apropos("glm") # returns names matching pattern
find("glm") # character(0) — no object literally named "glm"
find("anova.glm") #> [1] "package:stats"
Common pitfalls
Several misunderstandings trip up new users. find() searches R’s in-memory search path, not files on disk (list.files() handles filesystem searches). It is always case-sensitive, unlike apropos. When an object is not found, it returns character(0) — not NULL — so is.null(find("x")) is always FALSE.
x <- 42
find("x") #> [1] ".GlobalEnv" (any object)
find("x", mode = "numeric") #> [1] ".GlobalEnv"
find("Mean") # character(0) — case matters
find("mean") #> [1] "package:base"
find("nonexistent") #> character(0)
is.null(find("nonexistent")) #> FALSE (character(0) ≠ NULL)