http://www.perlmonks.org?node_id=952626


in reply to Re: RFC: Tutorial: use strict; now what!?
in thread RFC: Tutorial: use strict; now what!?

beginners who use soft references should be using hashes instead,
Hashes can be the solution. However, in almost all cases a hash based solution is done is such away it has all the disadvantages of not using strict, and none of the advantages.

Writing $hash{key} isn't any better than no strict; $key. In fact, it's worse. If you don't have strict enabled, and you typo and write $kye (once), you still get a compile time warning (assuming they are enabled). If you typo $hash{kye}, at best you get a runtime warning of an uninitialized value, depending on how it's used. But you may get no warning or error, regardless whether you have strict or warnings enabled.

Only if you would write:

my $KEY = "..."; ... $hash{$KEY};
you get protected against typos, but I very seldomly see people using hashes that way. But then you still don't get all the benefits of using regular, lexically scoped, variables:
my $KEY1 = "something"; ... my $KEY2 = "something"; ... $hash{$KEY1} = "..."; $hash{$KEY2} = "..."; # Ooops.
Perl will warn you if you declare a variable with the same name in the same scope. A benefit you lose if you implement variables as hash keys.

For me, code that uses hashes as if the entries were variables is a red flag. It indicates the most dangerous type of programmer. It's someone who thinks he's past the grasshopper stage, but really isn't yet.

Hashes as a bag of variables should be treated as Fugu. Only after 25 years of training, the first 14 of which all you do is cook rice 16h/day, 365 days/year are you allowed to look at the fish, and it takes another 25 years to master the slicing. Aka, it's only the experts, and they usually won't do it. It's certainly not for beginners.

I rather see someone using a soft reference, than a hash as a bag of variables. That cure is worse than the disease.

Replies are listed 'Best First'.
Re^3: RFC: Tutorial: use strict; now what!?
by moritz (Cardinal) on Feb 09, 2012 at 05:06 UTC
    However, in almost all cases a hash based solution is done is such away it has all the disadvantages of not using strict, and none of the advantages.

    I disagree. Most beginner's uses of soft references are along the lines of

    while (<>) { while (/([a-z]+)/g) { my $word = $1; $$word++; } } print "I've seen the word 'compiler'\n" if $compiler; # similar checks for a few other variables here

    If you do that with a hash instead, you have a very clear benefit: you don't run into the risk of accidentally changing any our-scoped scalars in the current package.

Re^3: RFC: Tutorial: use strict; now what!?
by tangent (Parson) on Feb 09, 2012 at 14:44 UTC
    I am trying to follow this as I use hashes all over the place. What exactly is a soft reference. Perldoc says this:
    Symbolic references are names of variables or other objects, just as a symbolic link in a Unix filesystem contains merely the name of a file. The *glob notation is something of a symbolic reference. (Symbolic references are sometimes called "soft references", but please don't call them that; references are confusing enough without useless synonyms.)
    I understand the difference between hard and soft links in a filesystem, but in Perl?
      $foo = 23; $soft = 'foo'; # soft reference $hard = \$foo; # hard reference print "soft=$$soft, hard=$$hard\n";
      A soft reference holds a variable's name, while a hard reference holds its memory address. When you dereference a soft reference, you search for a name in the symbol table. When you dereference a hard reference, you fetch the variable at that address.
        Thanks for explaining, I didn't know you could do that. BTW when I run that I get "soft=, hard=23"
      I am trying to follow this as I use hashes all over the place. What exactly is a soft reference.

      tangent, you'll get plenty of explanations of symbolic references. But even after you understand them well it may not be clear how hashes come into this, in almost the same breath.

      To recap, moritz offered hashes as an alternative to hard references. There was some discussion of this and JavaFan noted hashes can invite some of the same issues strict 'refs' is meant to avoid. You may not see the connection; it took me a moment to pick it up.

      Seen one way, use strict; is a typo-catcher. In the simple case:

      our $x13 = 'foo'; print $x31;

      ... may not work as you expect because you really meant to type $x13 both times. But use strict; will complain that you did not declare $x31 and so the typo is caught.

      If you attempt to take a hard reference and make a typo, you'll get an error, too. But if you take a symbolic reference and don't use strict; then you will not get early notice of your typo.

      Where hashes begin to resemble (in a certain mental state) symbolic references is when you start stuffing a lot of unrelated data into a hash with literal keys; and then later you want to take something out:

      my %hash; $hash{boy} = 'Arnold'; $hash{pension_balance} = 172.50; $hash{filehandle} = $fh; print $hash{pensionbalance};

      The typo will not be caught, with or without use strict; instead, perl will happily autovivify $hash{pensionbalance} for you and immediately print it... although it's undefined. This can be an annoying thing to track down.

      For more on this, see Re: Accessing hash from within module, where I demonstrate exactly this kind of risky approach... and note that it's almost as evil as global variables. I would not even have mentioned it if the OP didn't seem solidly committed to globals in the first place. As questionable as it is, I still think it's better than no strict 'refs';

      I'm not the guy you kill, I'm the guy you buy. —Michael Clayton
        Thanks for taking the time to explain Xiong, and I get the connection now, even though I had to read through everything a few times. Being an obedient student, I always use warnings as well as strict, and note that I get a warning if I try to print $hash{pensionbalance} and also if I say something like:
        my $debts = 100; my $money_left = $debts - $hash{pensionbalance}; # Use of uninitialized value in subtraction (-)
        Am I safe to assume then that use warnings will always keep me safe?
Re^3: RFC: Tutorial: use strict; now what!?
by chromatic (Archbishop) on Feb 09, 2012 at 00:29 UTC
    I rather see someone using a soft reference, than a hash as a bag of variables.

    Except that you can only use symbolic references with package globals in Perl 5, so you're susceptible to the risks of action at a distance.

      Is that suppose to say "Perl 6" where you said "Perl 5"?

      Nevermind.

Re^3: RFC: Tutorial: use strict; now what!?
by ikegami (Patriarch) on Feb 09, 2012 at 05:50 UTC

    However, in almost all cases a hash based solution is done is such away it has all the disadvantages of not using strict

    Not even close.

    How is the following remotely the same as a program without strict:

    while (<>) { my ($k, $v) = split; $h{$k} = $v; } for my $k (keys(%h)) { ... $h{$k} ... }
      It's not so hard:
      package P; while (<>) { my ($k, $v) = split; $$k = $v; } for my $k (keys(%P::)) { ... $$k ... }

        ... and the maintenance programmer who adds one or two features later will think you for occasionally, silently overwriting a few of his our-variables.

        It's not so hard

        Really? I don't see how the code you posted shows that the code I posted suffers from the same problems that strict refs is suppose to fix. Am I missing something?

        In fact, your code actually reinforces my point. our $x = 123; affects your code but not mine, so hashes are NOT just as bad as symbolic refs.