6

I need to be able to convert a naked pointer to a variant. I know that the pointer points to a variant, but I can't seem to get it back out. A straight cast (as I pretty much thought) fails:

Result := Variant(FAddress)^

returns a compiler error: [DCC Error] E2089 Invalid typecast

I've scoured the variants.pas unit as well, but nothing jumped out at me.

Obviously I'm missing something. What is the way to do this?

Nick Hodges
  • 16,902
  • 11
  • 68
  • 130

1 Answers1

16

If the pointer points at a Variant, then its type is PVariant. Type-cast it to that, and then dereference:

Result := PVariant(FAddress)^;

Better yet, declare FAddress with the right type to begin with, and then you don't need to typecast:

var
  FAddress: PVariant;

Result := FAddress^;

The compiler considers your attempted type-cast invalid because Variant is a bigger type than Pointer is. The compiler doesn't know where to get the additional data to create a full Variant value. And if the type-cast were valid, the use of the ^ operator isn't allowed on Variants anyway. You might have gotten away with this:

Result := Variant(FAddress^);

I've never liked that; if FAddress is an untyped pointer, then dereferencing it yields a value without any size or type at all, and it's just weird to type-cast such a thing.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Funny, I don't have a problem with `Variant(FAddress^)`. I don't see it as any different from `PVariant(FAddress)^`. – David Heffernan Apr 13 '11 at 18:58
  • Thanks, Rob, that seems to work. I'm actually modifying an existing library, and didn't want to (yet) make radical changes. – Nick Hodges Apr 13 '11 at 19:00
  • 1
    @David, in `Variant(FAddress^)`, the intermediate value in that expression has no type at all. I see it as momentarily programming "without a net," and that gives me the willies. In `PVariant(FAddress)^`, there's still a typeless thing somewhere, but we never access it directly. We assign a type to it first, and *then* start using it. – Rob Kennedy Apr 13 '11 at 19:07
  • @Rob I know what you are getting at, but think of it this way. Since you can't dereference a pointer typeless thing, how could it mean anything different from your preferred version? Another way to put it is that there isn't an intermediate value. There isn't an intermediate value in your version either. – David Heffernan Apr 13 '11 at 19:15
  • @Rob Or this way. In order to assign a variable, you need to specify the location *and* type of both lvalue and rvalue. You can't do assignment with just type, or just location. So you have to specify both and you can do that in either order. At least that's the mental model I've got! – David Heffernan Apr 13 '11 at 20:15
  • @David, in my mental model, there *is* an intermediate value. We start with `FAddress`, with type `Pointer`. Then we evaluate `FAddress^` to get a value of type who-knows-what. Finally, we evaluate the type-cast to get a value of type `Variant`. In my preferred way, we evaluate `PVariant(FAddress)` first to get a value of type `PVariant`. Then we dereference that to get a value of type `Variant`. At the CPU level, those aren't all separate evaluation steps, but at the level I'm used to from formal study of programming-language analysis, they're all separate steps with distinct semantics. – Rob Kennedy Apr 13 '11 at 20:36
  • @Rob I'd probably always write it that way round too, for what it's worth. How do you feel about typeless const parameters. You don't feel the need to get the address of them, cast to a typed parameter and then de-reference do you? – David Heffernan Apr 13 '11 at 20:39