Search code examples
perl

How to make perl number constant to be always a number when serializing to json


Here is the code that is working as I expect:

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';
use feature qw(say);

use constant MY_CONSTANT => 42;

use JSON::XS;

say encode_json { value => MY_CONSTANT };

This code output:

{"value":42}

But if the constant is used in string concatenation, then instated of a number in json I get string:

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';
use feature qw(say);

use constant MY_CONSTANT => 42;

use JSON::XS;

say encode_json { value => MY_CONSTANT };

my $smth = 'asdf' . MY_CONSTANT;

Here is the output:

{"value":"42"}

For me it was very unexpected that the "constant" changes it behaviour depending of how it it used.

Is there a way to define a constant with number in perl that will be converted to number value in json even it is used in concatenation.


Solution

  • Ideally, Perl considers fourty-two to be fourty two, whether you initialized the variable using "42" or 42. JSON::XS breaks that model, which causes results like the ones you saw.

    You could use a sub (rather than a constant) to return a fresh scalar every time.

    sub MY_CONSTANT() { return 42 }
    

    The return is important as it prevents the conversion of the sub to a constant.

    But a better solution might be to switch to Cpanel::JSON::XS and use Cpanel::JSON::XS::Type to tell the encoder how to serialize the field.