Scalar values are contained in data structures that can accommodate various data types, including integers, numbers, strings and references. Perl converts between these types as necessary, according to how the variable is used.
I haven't traced the calls all the way through Win32::OLE to the Cells method invocation, but along the way Win32::OLE creates an OLE Variant for each argument passed to the method. In doing so, it looks at the type of data currently in the passed scalar value. The bit of code which, I think, is relevant here is the following:
/* Scalars */
if (SvIOK(sv)) {
V_VT(pVariant) = VT_I4;
V_I4(pVariant) = (LONG)SvIV(sv);
}
else if (SvNOK(sv)) {
V_VT(pVariant) = VT_R8;
V_R8(pVariant) = SvNV(sv);
}
else if (SvPOK(sv)) {
V_VT(pVariant) = VT_BSTR;
V_BSTR(pVariant) = AllocOleStringFromSV(aTHX_ sv, cp);
}
The SvIOK(sv), SvNOK(sv) and SvPOK(sv) macros check whether the scalar value (sv) currently contains an integer, number or string value respectively. You can see that the variant is initialized differently according to the results.
An OLE variant can contain various data types but the implication of the result reported above is that Excel doesn't convert types as perl does. If it is passed a variant containing an integer value, the call succeeds but if it is passed a variant containing a string that could be converted to the same integer value, it fails. Automatic conversion is one of the strengths/weaknesses of Perl (depending on whether you prefer strongly typed languages). I think it's very convenient myself.
You can see the type of value in a scalar value by using Devel::Peek. The following test program demonstrates the effect of "0 + $x" and shows that a scalar value can contain an integer and string value at the same time. You might imagine that there is some ambiguity in what should be passed to an OLE method in such a case: a string or an integer?
use strict;
use warnings;
use Devel::Peek;
my $x = '10';
Dump($x);
my $y = $x;
Dump($y);
my $z = 0 + $x;
Dump($z);
my $a = 10;
Dump($a);
print "\$a = $a\n";
Dump($a);
This produces
SV = PV(0x9c3c6d0) at 0x9c585c0
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x9c53bc8 "10"\0
CUR = 2
LEN = 4
SV = PV(0x9c3c730) at 0x9c58620
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x9c50250 "10"\0
CUR = 2
LEN = 4
SV = IV(0x9c585ac) at 0x9c585b0
REFCNT = 1
FLAGS = (PADMY,IOK,pIOK)
IV = 10
SV = IV(0x9c65674) at 0x9c65678
REFCNT = 1
FLAGS = (PADMY,IOK,pIOK)
IV = 10
$a = 10
SV = PVIV(0x9c3e6b8) at 0x9c65678
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 10
PV = 0x9c66cc8 "10"\0
CUR = 2
LEN = 4
The macros (SvIOK etc.) check the FLAGS. See Devel::Peek and Perlguts for more on how this works.
In summary, it's not Perl that fails to recognize the string contains a string representation of an integer, it's Win32::OLE and Excel. |