68

What is the difference between

if (defined $hash{$key}) { }

and

if (exists $hash{$key}) { }

When do I know which to use?

Dave Cross
  • 68,119
  • 3
  • 51
  • 97
Sandra Schlichting
  • 25,050
  • 33
  • 110
  • 162

5 Answers5

111

This is well-documented in the perldoc entries for defined and exists. Here's a quick summary:

defined $hash{key} tells you whether or not the value for the given key is defined (i.e. not undef). Use it to distinguish between undefined values and values that are false in a boolean context such as 0 and ''.

exists $hash{key} tells you whether or not %hash contains the given key. Use it to distinguish between undefined values and non-existent ones.

This is easiest to see with an example. Given this hash:

my %hash = (a => 1, b => 0, c => undef);

Here are the results for retrieval, defined-ness, and existence:

# key  value  defined  exists
a          1        1       1
b          0        1       1
c      undef        0       1
d      undef        0       0

In practice, people often write just if ($hash{key}) {...} because (in many common cases) only true values are meaningful/possible. If false values are valid you must add defined() to the test. exists() is used much less often. The most common case is probably when using a hash as a set. e.g.

my %set = map { $_ => undef } 'a' .. 'z';

Using undef for set values has a few advantages:

  1. It more accurately represents the intent (only the keys are meaningful, not the values).
  2. All undef values share a single allocation (which saves memory).
  3. exists() tests are slightly faster (because Perl doesn't have to retrieve the value, only determine that there is one).

It also has the disadvantage that you have to use exists() to check for set membership, which requires more typing and will do the wrong thing if you forget it.

Another place where exists is useful is to probe locked hashes before attempting to retrieve a value (which would trigger an exception).

Michael Carman
  • 30,628
  • 10
  • 74
  • 122
15

defined checks the value of the variable, exists checks if it has been previously declared/initialized. If it exists, plain and simple.

E.g.:

$hash{$key} = undef;
# various return values:
exists  $hash{$key};  # true
defined $hash{$key};  # false
$hash{$key};          # false

$hash{$key} = 0;
# various return values:
exists  $hash{$key};  # true
defined $hash{$key};  # true
$hash{$key};          # false
exists $hash{$foo};   # false
TLP
  • 66,756
  • 10
  • 92
  • 149
  • And `defined $hash{$foo}; #false` I suppose? – Sandra Schlichting Jun 30 '11 at 12:56
  • 2
    @Sandra Yes, uninitialized values are always undefined. Think of it as the difference between declaration and initialization: `my $var` exists, and contains the value `undef`. `my $var = 0` exists, and contains the value 0, therefore defined. – TLP Jun 30 '11 at 13:26
  • `$hash{$key}` returns the value for `$key`. While this can be interpreted as a Boolean, it isn't one. Your first example should return `undef`, the second one `0`. – Michael Carman Jun 30 '11 at 14:29
  • @Michael True, but this was in the context of if-statements (see question). – TLP Jun 30 '11 at 16:53
  • but beware. Using something like `if( defined $hash{$key} ) ...` may add the key (with undef as value) if the key does not exists. Thats why i always use `if( exists $hash{$key} && defined $hash{$key})`. – some_coder Sep 04 '13 at 09:28
  • 3
    @some_coder No, that is incorrect. You are thinking of [autovivification](http://en.wikipedia.org/wiki/Autovivification), and that occurs in Perl when you refer to a multi-dimensional structure: You create the level below to check the level above. E.g. `if (defined $hash{a}{b})` will create `$hash{a}` if it does not already exist. But it will never create `$hash{a}{b}`. – TLP Sep 04 '13 at 10:05
7

Perl documentation:

When used on a hash element, defined tells you whether the value is defined, not whether the key exists in the hash. Use exists for the latter purpose.

Igor
  • 26,650
  • 27
  • 89
  • 114
4

As stated in the perldoc on exists:

Given an expression that specifies an element of a hash, returns true if the specified element in the hash has ever been initialized, even if the corresponding value is undefined.

A hash or array element can be true only if it's defined and defined only if it exists, but the reverse doesn't necessarily hold true.

That is, a hash can contain an undefined element, and if that is the case, the defined-check will return false, whereas the exists-check will return true.

Therefore, you should use exists if you wish to know if a given entry exists in the hash, and defined if you wish to know if the given entry exists and is defined.

Community
  • 1
  • 1
Sebastian Paaske Tørholm
  • 49,493
  • 11
  • 100
  • 118
  • 1
    Yes. `exists` checks if the hash contains the given key, but not what the value of it is, while `defined` looks at value at the given key and sees if it is defined or not (and if the key doesn't exist, it gets back an `undef`, so it works even if the key's not there.) – Sebastian Paaske Tørholm Jun 30 '11 at 12:26
3

This example shows the difference. In general defined works for any structure and exist is related to hashes.

my %hash=("1"=>undef);
print "exists:".exists($hash{"1"})."\n";
print "defined:".defined($hash{"1"})."\n";

The difference is small and not so obvious, so expect that people will mess with it.

weismat
  • 7,195
  • 3
  • 43
  • 58