ref never returns undef!

emazep on 2006-10-27T02:33:23

Since I keep on finding here and there tests like this:

if (defined ref $thingy ...
let me point out that ref never returns undef. If its argument is not a reference, ref simply returns the empty string (even if called on undef!)

To have an idea on what I'm talking about (and on how common this redundant - and sometimes completely wrong - test is), have a look at here.
And to have a confirmation that a test like this is really superfluous (at best), have a look at the docs.

Update

Here is a slightly better crafted search - which searches just for the pattern defined\s*\(?\s*ref - which gives more results (though some of them are not pertinent to be honest).

Anyway thank everyone for the clarification about the origin of this meme (though now I have the same n1vux's curiosity ;-)

Ciao, Emanuele.


Legacy

Aristotle on 2006-10-27T03:00:37

I think it used to return undef on older Perls, which is where that meme came from.

Re:Legacy

link on 2006-10-27T09:13:49

It used to be documented as

Returns a TRUE value if EXPR is a reference, FALSE otherwise.

which could mean it returns "" or undef or alternates between them.

Re:Legacy

n1vux on 2006-10-27T18:27:20

which means removing the defined() without putting in a require 5.8.0; would potentially create a compatibility regression, on any implementation/releases that actually returned undef when FALSE was documented?

Do we know if it actually returned 'undef' or if it always returned q{} as it's FALSE (but defined) value?

Re:Legacy

DAxelrod on 2006-10-28T03:56:26

Since undef is false, wouldn't if (ref $thingy work in all cases?

Re:Legacy

bart on 2006-10-28T08:30:25

Sure it would. At least on the first page of results emazep's Code Search query, all code snippets take the form of
if(defined ref $x && ref $foo eq 'X') ...
This can be reduced to
if(ref $x && ref $foo eq 'X') ...
even if ref ever returned undef (which, last I heard, has always been considered false). Which it doesn't, even
ref undef
returns a true boolean, a value like !1. And then,
if(ref $foo eq 'X') ...
suffices. No warnings, now, ever. But maybe it did warn, in the past.

Re:Legacy

emazep on 2006-10-28T12:01:36

Well, not always.

Under the false assumption that if the argument is not a reference ref returns undef, a test like this

if (defined ref $thingy) { ... }
to check if $thingy is a reference or not, would clearly be wrong, non just redundant (you can find an example of this here).

Anyway my main complaint was about the fact that, even if the code is formally correct (whereas the test is used to supposedly avoid the possible warning from a subsequent test), such defined-ness test is redundant, or unnecessary, or superfluous (pick your favorite), since ref never returns undef.

In other words I mean that there is no reason to say

if (defined ref $thingy && ref $thingy eq 'HASH') { ... }
since
if (ref $thingy eq 'HASH') { ... }
gives no warnings as well (at least today), and it is less cluttered and more readable (and a little bit faster too ;-)

Ciao, Emanuele.

Re:Legacy

emazep on 2006-10-28T12:23:21

Update

Please forget my previous pointless post: I wrongly assumed that DAxelrod was talking about

if (defined ref $thingy) { ... }
while he clearly said
if (ref $thingy) { ... }
Ciao, Emanuele.