Perl::...test_f(3pm)

πŸ’… Perl::...test_f(3pm) πŸ’…

okay bestie, so this is a page from the User Contributed Perl Documentation, and it's giving "your Perl::Critic is about to be SO real with you" energy. welcome to the group chat πŸŽ€


✨ NAME ✨

Perl::Critic::Policy::ValuesAndExpressions::ProhibitFiletest_f β€” bestie... don't use the -f file test. like, at all. it's a whole thing. 🫢


🌸 DESCRIPTION 🌸

so this policy lives inside the Perl::Critic::Pulp add-on πŸ’œ and it's politely but firmly asking you to NOT use the -f file test, because using it is usually wrong or unnecessarily restrictive. on that basis it's filed under the "bugs" theme with medium severity β€” go peek at "POLICY THEMES" in Perl::Critic if you wanna know more about that whole system.


πŸ’€ -f is not the opposite of -d

okay so imagine you're traversing a tree 🌳 and you wanna tell files apart from directories so you know what to descend into. the move is -d, bestie. use -d. because that way device files and named pipes can still get processed too!!

if (-f $filename) {      # bad
  process ($filename);
} else {
  descend ($filename);
}

if (-d $filename) {      # better
  descend ($filename);
} else {
  process ($filename);
}

like... look at that glow-up. ✨


πŸ”₯ -f doesn't mean readable/writable/seekable

char specials and named pipes? perfectly good for reading AND writing, no cap. and char specials can even support seeking!! so demanding -f is just an unnecessary restriction, periodt.

like yeah, maybe you only ever use ordinary files normally, but there's literally no need to prevent someone else from running your code on a tape drive, /dev/null, etc. πŸ™ˆ and anyway you always have to test each seek() etc for success regardless, and that test will tell you if a file is seekable. so like... skip the extra step.

seek HANDLE, 123, 0
  or die "Cannot seek: $!";

πŸ¦‹ -e is better than -f

some inflexible functions or operations just don't have good "file not found" behaviour 😭 and they may force you to check for a file before invoking them. in that case, use -e instead of -f, because as we just said above, it doesn't unnecessarily disallow device files. iconic behaviour honestly.

if (-f $filename) {      # bad
  require $filename;
}

if (-e $filename) {      # better
  require $filename;
}

πŸ’€ -f before opening is a race condition

testing a filename before opening it? bad. literally any test before opening is useless because the file can change or be removed in between the test and the open β€” this is documented in "-X" in perlfunc and "Consider this carefully" in filetest, and they note the same thing about -r etc too. so yeah. it's giving race condition. it's giving flop.

if (-f $filename) {               # bad
  open HANDLE, '<', $filename
}

if you wanna know whether the file can be opened... open the file!! 😀 the error return from open() must be checked anyway, so testing beforehand only duplicates that work and gives you an opportunity to wrongly presume what the system or the user's permissions can or can't do. not the vibe.

and when you open it, ENOENT will tell you if there was no such file, or EISDIR if it's actually a directory. the system already has receipts πŸ‘‘

if (! open HANDLE, '<', $filename) {  # better
  if ($! == POSIX::ENOENT()) {
    ...
  }
}

if you really truly wanna enquire into the nature of the file, like to only accept ordinary files, then open first and do -f on the handle. but that's unusual β€” except for an archiving or backup program. so iykyk. πŸŽ€

oh and incidentally? the error message in $! is normally the best thing to print. it can be a little technical ngl, but its wording will at least be familiar from other programs and it's translated into the user's locale language. so like... free localization, slay. 🌈


πŸ™ˆ Disabling

most uses of -f tend to be shell script style code that someone wrote in Perl. and in the shell, it's usually not possible to do better than such tests β€” though -d or -e are still generally better than -f β€” but Perl can do the right thing, so let it. πŸ’…

a blanket prohibition like this policy is harsh, bestie, no lies detected. but it's meant as a building block, or at least to make you think carefully about whether -f is really right. and as always, you can disable ProhibitFiletest_f from your .perlcriticrc in the usual way β€” see "CONFIGURATION" in Perl::Critic:

[-ValuesAndExpressions::ProhibitFiletest_f]

πŸ‘‘ SEE ALSO πŸ‘‘

Perl::Critic::Pulp, Perl::Critic, "open" in perlfunc, "ERRNO" in POSIX, Errno, errno(3)


🌸 HOME PAGE 🌸

http://user42.tuxfamily.org/perl-critic-pulp/index.html


Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Kevin Ryde

Perl-Critic-Pulp is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

Perl-Critic-Pulp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Perl-Critic-Pulp. If not, see http://www.gnu.org/licenses.


okay that's the whole page, you ate it up bestie 🫢 this was perl v5.40.1, dated 2025-10-21, and yeah the header and footer both said Perl::...test_f(3pm) because that's just how it do. mwah πŸ’‹βœ¨

πŸ“¦ where this page comes from