Hi Rob,
I already changed my mind about that last night. I said it wouldn't be
an issue.
The issue I was worried about is a complex one that isn't easy to
explain. I can give an example, but I'm worried you'd just look at it
and say "nobody would ever do that" simply because my example is too
contrived. But writing a real example that illustrates the benefit
would take too long...
Also bear in mind that I already determined that I was wrong and that
this is a non-issue.
But, I'll explain anyway... here's a bad example to start with:
D Blah s 10a
/free
MyProc( Blah: %size(Blah) );
P MyProc B
D MyProc pi
D SomeParm 1a
D Length 10i 0 value
D Whatever s 10a based(p_Whatever)
/free
if Length >= %size(Whatever);
p_Whatever = %addr(SomeParm);
Whatever = *ALL'x';
else;
// field is too short
endif;
/end-free
P E
The point here is that the compiler doesn't check the UPPER bounds of
the length of a variable. It makes sure the variable is LONG ENOUGH, but
it doesn't look at whether it's LONGER than the procedure wants.
In the above example, the prototype defines 1A, even though I can pass
longer values. In this example, the caller provides a 10A, even though
the procedure defines a 1A. This doesn't matter, because I know the
variable will be passed by reference, so I can refer to a longer value.
I know, I know... you're thinking "but that's not the PROPER way to do
that... you should use *VARSIZE instead" like this:
D MyProc pi
D SomeParm 65535A options(*varsize)
D Length 10i 0 value
That's true -- but again, this is a contrived example because a real one
would take too much work to code, and I'd rather not spend 2 hours
explaining the situation :)
But a real situation where I might do this is if I needed a field that's
larger than 64k (I'm still at v5r4 -- but even if I weren't, I'd still
have lots of code around from when I was!) In that situation, I might
be using pointer logic to call a procedure, and I might have one BASED
65535 field that that's in a dynamically allocated buffer that's
millions of bytes long. (Even with 6.1 I'd have to use that technique
if I wanted to exceed 16 MB)
However, if the compiler copied my field to a temporary, and copied it
back, it'd only copy 65535 of the field, because that's all I had
defined on the prototype. Thus, breaking backward compatibility -- or
so I was thinking at the time.
I've also seen quite a lot of code from people who don't understand the
*VARSIZE keyword. Those people code 1A when their field varies. For
example, i've seen this example quite a lot on the Internet:
D RunCmd PR ExtPgm('QCMDEXC')
D cmd 1a
D len 15p 5 const
They don't worry about the fact that 'cmd' is only 1A, because they know
it's passed by reference, and the QCMDEXC API will pick up the full
length they pass in the 2nd parameter. If RPG copies it to a temporary,
it'll only copy 1 byte however, and that will truncate the string.
So I was thinking that this would break compatility -- but I changed my
mind. why did I change my mind?
Because there's no reason for RPG to use a temporary variable in these
cases. It'll just pass the field as-is. So the behavior won't change...
I was thinking that you might decide to pass a VARYING or Unicode field
or something like that. When it did that, it'd only copy the shorter
length defined on the prototype. But for existing code, you can't do
that, it wouldn't compile... so no backward compatibility issue there.
The procedure might have to be rewritten to make the new "autoconvert"
feature work properly in the future, but for existing code it wouldn't
break anything.
Again, I changed my mind about this last night already (and posted
that). I was wrong.
rob@xxxxxxxxx wrote:
Why would there have to be some sort of keyword or it would break backward
compatibility? Default is I pass in a variable, called program may, or
may not, change it, and passes it back to me. We're requesting the same
behavior. Only difference is variable casting. If there's a danger of
truncation then it should be handled in the called program. For example I
pass in a filled 5i and the called program is 2p. Why should every
program that uses the subprocedure have to handle the truncation? Takes
away from storing the logic in one place.
Rob Berendt
As an Amazon Associate we earn from qualifying purchases.