Ptr namespacing is kinda horked

| | Comments (10)

While looking more in-depth at a recent bug report, I realized that we have a fundamental flaw in the way the Ptr magic namespace works. I'm talking about the way that you're able to easily peek and poke values with a Ptr via a magic dataype name. The idea is an honorable one in that it fits nicely with the "easy to use, but still powerful" mantra that REALbasic follows. But due to the left-associative nature of the dot operator, this concept has some flaws.

Consider the following snippet of code:


Dim p as Ptr = SomethingThatReturnsAPtr()
p.Int32 = 21

This code demonstrates the magical namespace in all of its glory. What happens is that the scope lookup operation in the compiler sees "p", and knows it's a Ptr. Then it sees "." followed by an identifier. So it looks on Ptr to see what Int32 is, and it turns out that Int32 is perfectly valid to work with. Yay, life is good, and this is a very easy and readable way to deal with Ptrs. Now, consider this snippet instead:

Module Test
Global Structure Wahoo
i as Integer
End Structure
End Module

dim p as Ptr = SomethingThatReturnsAPtr()
p.Wahoo.i = 12


In this case, the scope lookup operator finds "p", knows that it's a Ptr. Then it sees a dot followed by Wahoo. Wahoo is a valid datatype for Ptr to work with, and so the next thing we find is another dot followed by "i". i is a valid member of the Wahoo structure, and so we're good to go. Again, this all works nicely and is very readable. But let's change the snippet a little bit.

Module Test
Public Structure Wahoo
i as Integer
End Structure
End Module

dim p as Ptr = SomethingThatReturnsAPtr()
p.Test.Wahoo.i = 12


In this case, we've made the structure Public instead of Global. So in order to access it via the Ptr, we naturally put in "Test.Wahoo" instead of just "Wahoo" so that we have the properly qualified name. But this is where left-associativity in the dot operator kills us. We find p, and we know it's a ptr. But then we find "Test", and that's not something that's legal on a Ptr. Heck, it's not even a type! So we fail because there's no such thing as a p.Test in the world. This is why the Ptr namespace concept is fundamentally flawed. When using items accessible via the current namespace level in an unqualified manner, everything is fine. But as soon as you have to start qualifying the names, it's going to fall apart.

One way to try to deal with this would be to add new magic methods onto the Ptr namespace that are familiar to anyone with a BASIC background: Peek and Poke. Something that would allow you to say:


somePtr.Poke( SomeClass.SomeStructure.SomeField, 12 )

In this manner, we can always assume that the first parameter to Poke (and the only parameter to Peek) is a datatype which may or may not be a fully-qualified namespace. Of course, you should still be able to do this (for consistency's sake):

dim i as Integer = somePtr.Peek( Integer )

The tricky part about this is the grammar for it. Nowhere else in the language is there the idea of a datatype field like this. CType comes close in that it assumes you'll get the datatype. But, in that case, it would get you to the structure (since that's a datatype), but not the field (which is the interesting bit, since we require the field's size information). So we'd have to come up with an entirely new grammatical representation for this oddball concept, which is very heavy-handed.

Another way to do this is to treat Peek and Poke like CType in that they don't deal with typed sizes, they deal with datatypes. So, for instance, you wouldn't go down to the structure field level within the call to Peek or Poke. Instead, you'd tell Peek and Poke "this is the datatype I want you to use." For instance:


dim i as Integer = somePtr.Peek( SomeClass.SomeStructure ).SomeField

This way, the grammar can continue to use the concept of a datatype like CType, type casting and IsA. The downside to this is that it might be confusing to users because it doesn't behave like the imported namespace functionality. The upside is that it's a cleaner implementation!

So yeah, something for me to continue mulling over. But the take-home point for you is to understand that Ptr and namespaces don't mix. It's not a bug that they don't mix, it's just a design shortcoming. The only way for you to work around the design flaw is to ensure that there's no namespace involved, then Ptr can work with the datatypes.

10 Comments

Could you look ahead and see what follows "Test" to see if it is a scoped item that would be legal ?

Or if "Test" IsA Module then you have to keep looking to see if what follows isa properly scoped typed thing that Ptr would deal with ?

From a syntax consistency perspective I much prefer

p.Test.Wahoo.i = 12


@Norman -- that would mean we'd have to have more than one token of lookhead, which comes with its own mess of problems. What's more, it doesn't solve the problem (which would ultimately require a context-sensitive grammar). If you cannot truly figure out what the user means until you've parsed the entire line, then it should probably be a right-associative operation instead of a left-associative one.

In that case it should probably use a token other than the dot.

@Mars -- I wasn't actually suggesting it as an option, but yes, if we did have a different associativity as a feature, we'd have to use something other than the dot operator. :-P

Oh no- my beloved syntax simplicity- slipping away right before my eyes!

Let's not delve into another operator/token just yet, ok guys? :)

@Travis -- I wouldn't worry about that too much. ;-)

Peek and Poke... Takes me back to the early 80s ... YUCK!!!!!

When using non-global structures how about (with good documentation):

p.(Test.Wahoo.i) = 12

Not ideal, but still more readable than peak and poke...

- Karen

@Karen -- so "Dim" and "REM" are ok, but "peek" and "poke" are ugly? ;-) The trouble with your suggestion is that it would warp the grammar too much to really be feasible. Suddenly you'd be able to do stuff like SomeClass.(SomeMethod.SomeOtherMethod) unless we explicitly started adding more error cases. It's hard to explain without boring you to death, so you'll have to take my word for it.

Regardless of the solution, I don't think you'll see much movement on this in the near future.

Associativity be damned .. the first syntax seems more "natural" and consistent
That's all I was meaning is somehow it'd be really nice to retain what seems to be a consistent style
I realize this makes life hell for the compiler writer but hey .........
It would at least be consistent with other accesses to the public structure members

Hi

If you have the time, could you tell us how to trap a KeyUp event on both Mac and Win? I cant find it in the language.

Thanks for sharing your knowledge!

Me

Leave a comment