For me, the subroutine is the unit of abstraction. Give me subroutines (or methods or functions) and I can change the world.
Fixing Hashes
If you try and retrieve a non-existent key from a perl hash, it returns an undefined value. Often, that isn’t what I want.
No worries. With a simple subroutine, I can fix it.
sub get_hash_value (\%$)
{
my ($hash_ref, $key) = @_;
if (! exists $hash_ref->{$key}) {
die "KeyNotExists: $key\n";
}
return $hash_ref->{$key};
}
my %hash;
print $hash{'hardtospellkey'};
print get_hash_value(%hash, 'hardtospeelkey');
With warnings turned on, this is easily caught. Plus with emacs dabbrev, it is never a problem for me anyway – my mispellings are consistent.
But with a less enlightened language than perl, if you have this problem then as long as you also have subroutines, you can fix it.
Use of uninitialized value $hash{"hardtospellkey"} in print at t.pl line 14.
KeyNotExists: hardtospeelkey
Fixing Weakly Typed Numbers
use Scalar::Util 'looks_like_number'; sub ensure_number { my $val = shift; if (! looks_like_number($val)) { die "NotNumber: $val\n"; } return $val; } my $x = '1'; my $y = 'rhubarb'; print ensure_number($x) + ensure_number(2), "\n"; print ensure_number($x) + ensure_number($y), "\n";
In production code I’m likely to call that subroutine something more like _n.
3 NotNumber: rhubarb
Subroutine Call Speed
This is why I care about perl subroutine call speed – I have so many little routines stating exactly what I expect from my code. And it seems like it is quick enough.
It would be nice though to have something like emacs’ defsubst. Say a new keyword like inline_sub { ... }. So I can invent the syntax I want, secure in the knowledge that, code bloating aside, I’m not paying for it.
Autovivification – is a very comfortable thing, workarounds around it says that you doesn’t understand Perl-way programming good and you may read some books like “Intermediate Perl” and “High order Perl”, to understand that way and your programs will be much better without workarounds.
Second example (about numbers) i never used in my life in any language =). I can not even imagine where this might come in handy, so you worry about this.
Your problems with Perl programs is in not so good understanding of the language. Try to understand it principles or write your programs in python if deems more appropriate.
P.S. sorry for my bad English, i’m working on it.
It is ridiculous to suggest that wanting to avoid autovivification means that Jared isn’t a good Perl programmer. (It’s also irrelevant, since this post does not actually reference autovivification, which is when an undefined value is silently upgraded to an array or hash reference.)
Perl has a lot of features to make writing quick programs easy. Those same features are often a pain when you have to look through 50k lines of code and figure out why your data is silently being converted from one thing to another somewhere in the middle. In that context, finding a way to avoid accidental nonexistent hash key lookups is perfectly reasonable.
Ok, i was a little hasty in writing the answer. You right, autovivfication is nothing to do with in this case.
Not so many hashes or number or e.t.c. needs this functional. I can suggest to use “tied variables” for such tasks.
For example:
use 5.012; package Strict_hash; use Tie::Hash; use base qw(Tie::StdHash); sub FETCH { exists $_[0]{$_[1]} or die "KeyNotExists: $_[1]\n"; $_[0]{$_[1]}; } 1; package main; tie( my %h,'Strict_hash' ); %h = ( a => 1,c => 3); say $h{b};prints:
KeyNotExists: b
And i want to advise you not to try to find bottlenecks by yourself manually them almost impossible to predict, there is special programs for this (Devel::NYTProf for Perl for example).
@zloyrusskiy – you have managed to miss my point by some distance. Well done!
@hdp – you have summarized my intention neatly. Thanks!
I don’t know about you, but I tend to access hashes more than I add keys to them. One way to get this typo protection and avoid paying the cost on every access is to use Hash::Util’s (http://perldoc.perl.org/Hash/Util.html) lock_keys_plus:
#!/usr/bin/perl
use strict;
use warnings;
use Hash::Util qw/unlock_keys lock_keys_plus/;
my %h;
my $i = 0;
for my $k (qw/a b c d e f/) {
unlock_keys %h;
lock_keys_plus %h, $k;
$h{$k} = $i++;
}
print “$h{a}\n”;
print “$h{z}\n”;
Hi Chas,
I suspect I read more than I write too. I think I’ve come across the Hash::Util functions before but for some reason I’ve never used them in production code. Thanks for pointing them out.
Cheers