bartender1382 has asked for the wisdom of the Perl Monks concerning the following question:

Below is my abbreviated code, which includes every line where I access or set an int value in a hash, before coding it into JSON then sending it out as an HTTP response/data.

The hash item, returnvalue, is an int. My code either returns a 7 or a 15.

When the code below sets returnvalue to 7 (SSSTAGE1), my Swift apps take the http data and decodes it with no problem.

When the code below sets returnvalue to 15 (SSCONVERTING), my Swift apps take the http data and gets a JSON type decoding error.

Further debugging in my Swift app shows that when set to 7 (SSSTAGE1) in the perl code below, the http data received shows:
returnvalue=>7, an int

Yet when returnvalue to 15 (SSCONVERTING), the http data shows:
returnvalue=>"15", a string

I know Perl can treat ints and strings interchangeably. So am curious if anyone has come across this before?

use enum qw( SSSUCCESS ... SSSTAGE1 ... SSCONVERTING ); use CGI; use JSON; local $SIG{CHLD} = "IGNORE"; my $q = new CGI; print $q->header(); my %out = ( username =>"", userid =>"", status =>"", filename =>"", rawfilename => "", ticket =>"", returnvalue => 0, message =>""); ... $out{returnvalue} = SSCONVERTING; ... if ($ticketinfo{status} == SSSTAGE1){ $out{returnvalue} = SSSTAGE1; } my $json = encode_json \%out; print $json; exit 0;

Replies are listed 'Best First'.
Re: Int becomes String when I convert to json
by choroba (Cardinal) on May 09, 2022 at 19:28 UTC
    That's why Cpanel::JSON::XS::Type exists.
    #!/usr/bin/perl use warnings; use strict; use Cpanel::JSON::XS; use Cpanel::JSON::XS::Type; my %out = (username => "", userid => "", status => "", filename => "", rawfilename => "", ticket => "", returnvalue => 0, message => ""); my $json = encode_json(\%out, {returnvalue => JSON_TYPE_INT, username => JSON_TYPE_STRING, userid => JSON_TYPE_STRING, status => JSON_TYPE_STRING, filename => JSON_TYPE_STRING, rawfilename => JSON_TYPE_STRING, ticket => JSON_TYPE_STRING, message => JSON_TYPE_STRING}); print $json;

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      I wonder if it's that a single digit it normally returns an int, but for a double digit a string.

      I'll try Cpanel::JSON::XS::Type, but sort of irks me that this is a "thing."

      Thank you
        > that a single digit it normally returns an int, but for a double digit a string.

        It's more complex than that. It depends on what you did with the value, on the version of Perl, what JSON module you use and its version, and sometimes even more. See my slides on the topic.

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Int becomes String when I convert to json
by Corion (Patriarch) on May 09, 2022 at 19:24 UTC

    Most likely, enum returns all values as strings.

    If you want to try to convince Perl (and JSON) that the value should be treated more like a number, try adding a zero to it:

    $out{returnvalue} = 0+SSSTAGE1;

    ... or simply do the conversion at the end:

    $out{returnvalue} = 0+$out{returnvalue};
      Hello Corion,
      Most likely, enum returns all values as strings.

      Just to clarify how the index is returned.

      Default simple usage will provide the index as numeric, but the user can invoke string context in the usual manners. That is, the user should not need to convert to number using 0+$index unless they already messed with the context previously.

      enum provides two indexing modes ENUM and BITMASK,with optional mnemonic prefix. ENUM mode is an incremented natural number index $n = $index++ and BITMASK is a binary basis multiplier assigned increment $n = $index *= 2.

      Throughout the module any standard numerical contexts such as hex, oct, underscore_inclusive are converted into standard decimal format.

      The index for the user supplied list literal is then set in a similar fashion to a constant, by creating a package name withif prefix, that is a code ref to a null-prototyped subroutine.

       *{$'calling'pkg$pfx$name} = sub () { $n }

      The upshot being that the context supplied for assignment of the sub should determine whether the scalar is stringified or numeric.

      hth


      do { $Monastery::Level::nCoyote = 'Hermit'. 'yey!' } or eval '$nCoyote = 10'
Re: Int becomes String when I convert to json
by Haarg (Priest) on May 10, 2022 at 00:25 UTC

    If at any time you use SSSTAGE1 as a string in your program, it may change how it gets converted to JSON by the JSON.pm module. JSON.pm will internally try to use JSON::XS if possible, which has a heuristic for encoding values like this that can be problematic.

    If you switched to the JSON::MaybeXS module instead, it would likely work as you expected. Internally, it will try to use the Cpanel::JSON::XS module, which has better behavior for values like this than JSON::XS.