The Problem: Consider the following code:
use strict;
use JSON::XS;
use Cache::Memcached;
use Data::Dumper;
my $memd = new Cache::Memcached { 'servers' => [ "127.0.0.1:11211"], };
my $x={ "f" => [[134,1.7],[134,2]] };
print "before: \n";
print encode_json($x);
print "\n";
$memd->set("key",$x);
print "after: \n";
print encode_json($x);
print "\n";
You get this as the output:
before:
{"f":[[134,1.7],[134,2]]}
after:
{"f":[[134,"1.7"],[134,2]]}
Now, why is 1.7 now a string after the set() call? It's the same object I am encoding to json. So the serialization process in memcached's set() has stringified the float 1.7 into "1.7".You can actually replicate the same behaviour without memcached entirely, if you just do a Dumper($x) in between, the after Dumper() $x will have 1.7 as a string instead of a float.
I know Perl does not have strict typing, and that you can add 0 to a string (or multiply by 1) to make a variable into numeric representation. However, the above is definitely a problem.
The Solution, is to use Storable module and freeze the object $x before the store, and then of course, thaw $x when you retrieve it back out. See below:
use strict;
use Storable qw(freeze thaw);
use Cache::Memcached;
use JSON::XS;
my $memd = new Cache::Memcached { 'servers' => [ "127.0.0.1:11211"], };
my $x={ "foo" => [[134,1.7],[134,2]] };
print "before: \n";
print encode_json($x);
print "\n";
$memd->set("key", freeze($x));
print "after: \n";
print encode_json($x);
print "\n";
my $out=$memd->get("key");
print "thawed: \n";
print encode_json(thaw($out));
print "\n";
print "memcached version: ",$Cache::Memcached::VERSION,"\n";
print "json xs version: ",$JSON::XS::VERSION,"\n";
print "storable version: ",$Storable::VERSION,"\n";
You get this as the output:
before:
{"foo":[[134,1.7],[134,2]]}
after:
{"foo":[[134,1.7],[134,2]]}
thawed:
{"foo":[[134,1.7],[134,2]]}
memcached version: 1.30
json xs version: 2.26
storable version: 2.25
Voila! Everything stays as it is!