Crazy things can happend in dynamically typed languages (such as in Perl)

October 13, 2016
dynamic typed vs static typed languages

Alright, some people really love programming languages which are dynamically typed. Some say that statically typed is the only way. I do not know which camp I belong to. Or do I even want to belong any. How ever I found crazy thing which happened with dynamically typed language.

What it actually means when language is dynamic typed or static typed. I am not the top expert to answer to this question but in the nutshell it is something like…

In dynamically typed language you can declare variable like this:

$number = 1;
$word = "something";

In statically typed language you have to declare variable like this:

int $number = 1;
String $word = "something";

Here comes the crazy thing I promised

If you have ever developed with Perl you know that in Perl you can do many things like you want. Perl is dynamically typed language. I was adding some functionality into a already existing piece of code. There was already many checks and if something failed – error message was appended to $errors variable.

I added this block to that existing code:

if ( $errors->{what_ever} ){
    # Do something
}

That block broke everything. And it did it the way I could never expect. Plus there was absolutely no errors(even that strict and warnings exists). Here are two proof of concepts:

1. This is similar to my situation where everything failed.

 #!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my $errors;

print Dumper($errors); # $VAR1 = undef;

if( $errors ){
    # This is not true
    print "This is not true\n";
}

if ( $errors->{what_ever} ){
    # Do something
}

print Dumper($errors); # $VAR1 = {};

if( $errors ){
    # This is true
    print "This is true\n";
}

2. This is the valid version which works.

 #!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my $errors = {};

print Dumper($errors); # $VAR1 = {};

if( $errors ){
    # This is true
    print "This is true\n";
}

if ( $errors->{what_ever} ){
    # Do something
}

print Dumper($errors); # $VAR1 = {};

if( keys %{$errors} ){
    # This is not true
    print "This is not true\n";
}

So what really happened in that first piece of code?

First I declared variable

my $errors;

It tells to Perl that “hey I want to use scalar called errors, please let me”.

Then little bit later comes the block:

if ( $errors->{what_ever} ){
    # Do something
}

There I asked “dear Perl do you remember that scalar called errors, please test if that scalar hash key called what_ever”. Then Perl thinks “Sure I remember it and sure I can test it. Oh wait, scalars do not have keys. Only hashes have keys. Well I make this errors variable hash”Here is the big deal. Perl defines $errors to be hash. I could never expect it will do it in if statement.

Then code runs forward and comes

if( $errors ){
    # This is true
    print "This is true\n";
}

Here I am asking: “Please Perl one more question: Can you tell if $errors is true”. Perl answers: “Of course it is true, it is the hash”. What I expected here is that perl says “It is false because there is nothing in there”.

So what do you think, is this crazy or not?

8 Comment

  1. Spammer says: Reply

    It’s called autovivification. You can turn off that “feature” using the autovivification module from CPAN.

    1. Tuukka says: Reply

      Thank you for the comment!

      Yeah I see this autovivification thing is brilliant. But still
      I would not expect that it changes undefined to hash ref just by saying:

      if($errors->{something){}

      Actually it changes even if I say

      warn $errors->{something};

      I totally understand it if I say:

      $errors->{something} = 1337;

      There is nice article about this on PerlMaven: http://perlmaven.com/autovivification

      Those examples make sence to me. But the thing I pointed out earlier does not. I think there is a huge difference.

  2. Perler says: Reply

    Has nothing to do with autovivification. A reference to a hash is a scalar which is true even if the hash is empty. You have confused a hash ref with a hash. Not the same.

  3. raiph says: Reply

    Fwiw, like most such problems you can find in Perl 5, this has been fixed to work as you would understand it in Perl 6:

    [S]ubscripting itself does not cause autovivification: It only happens when the result of the subscripting chain is assigned to (or otherwise mutated).

    (from https://docs.perl6.org/language/subscripts#Autovivification)

  4. philote says: Reply

    This is a bit of a Perl oddity. But if you know you’re going to be using a hash to store something, declare a hash instead of a scalar:
    “my %errors;”

    This prevents the issue you had, because “if (%hash)” only returns true if there are items in the hash.

    What you are doing is using a scalar variable, which Perl turns into a reference to a hash when you use it like a hash (in your “if” statement). Perl is very good at trying to “do what I mean” (DWIM) and will make inferences like this at times. So in your case, the scalar “$errors” was then a reference to a hash and therefore no longer undefined or “false”.

  5. Eugen says: Reply

    Because of Perl is dynamically typed language When you do: $errors->{ what_ever } you say that $errors should be hash ref then you check ‘what_ever’.
    That work both cases: on read and on write.
    But I will agree with you that it is not expected autovivification to work when you just read.
    Writing if( $errors->{ what_ever } ) I just actually check if( ref $errors eq ‘HASHREF’ && $errors->{ what_ever } )

  6. emazep says: Reply

    I agree that the autovivification has unexpected side-effects, because they are triggered even by a read read-only operation (such as a test), but the problem in your code arises more as a consequence of something which is nearly always a mistake (in any programming language), that is, testing a reference. In your simple case of a single-level hash, if you have tested the hash instead of the reference (that is %$errors instead of $errors), you would have had no unexpected results (because %$errors is an empty hash). Here is the code to show that:

    my $errors;

    if ( $errors->{what_ever} ) {
    print “Key found!\n” # Prints nothing.
    }

    # 2nd attempt
    if ( $errors->{what_ever} ) {
    print “Key found!\n” # Prints nothing
    }

    if ( $errors ) {
    print “Reference found!\n” # It prints.
    }

    if ( %$errors ) {
    print “Non empty hash found!\n” # Prints nothing.
    }

    Initializing $errors like this:

    my $errors = {};

    would have been even clearer.

  7. Jason Simpson says: Reply

    Yeah, To explain in a handful or two of words. your scalar started undefined (and thus false), then referenced it as though it WERE defined — defined as a reference to a hash. That has was created, the (scalar) reference is now *defined* (to point to the hash). No longer undefined, it is thus not false.

    Understand that scalars can be references, and don’t confuse references with what they reference.

Leave a Reply