When structures were first introduced, the conversion between a structure string and a normal string was very naive -- the entire structure string was stuffed into the regular string. That included nulls, and whatever else was in there. However, we found out that this was really not a good idea because it caused all sorts of weird problems for users. People were using a string in a structure as an honest-to-god string (go figure) and not as a bucket of bytes. But the conversion was treating it more like a bucket of bytes than as a string.
So around 2006r4 or 2007r1, we changed the conversion function so that it's more sensible. A structure string is a string, not a bucket of bytes. So you use it to store textual data, not binary data. When the conversion to a real string happens, we truncate after the null byte. This makes things behave much more sensibly for the majority of users.
But what if you really do want a bucket of bytes and you want to be able to convert it to an RB string? Well, there's an easy enough trick for that rare situation:
Structure MyBagOfBytes
someBytes( 79 ) as UInt8
End Structure
Structure MyContainerStructure
something as Integer
bagOBytes as MyBagOfBytes
somethingElse as Double
End Structure
someData as String = myContainer.bagOBytes.StringValue( littleEndian )
Basically, you can use the fact that you're allowed to embed structures, and the fact that structures have a StringValue accessor in them. By using these two facts, you can get a bucket of bytes and shove it into a string instead of having to constantly write your own Trim function which trims null bytes as well as whitespace like you used to do.
I'm not sure I understand the reasoning behind this change - An RB Sting *is* a bucket of bytes, so why doesn't it make sense that a String in a structure is a bucket of bytes? If I wanted a nul terminated string in a structure I'd use a CString.
I don't see how this change fixes anything other than naive user's misguided expectations. I can see this being a PITA for people who expect a String to be a bucket of bytes however, 'cause it is a bucket of bytes everywhere else!
There are two reasons for this:
1) RB strings are variable length. The have knowledge about how many bytes long the string is and where its data lives. Structure strings are fixed-length and have no such data. Basically, there's no way to know what part of the "string" is valid and what part isn't. So the user does this:
someStruct.someString = "Hello"
MsgBox someStruct.someString + " world"
and what they end up with is totally bogus because there's no way to tell that the user only actually assigned the first five bytes, and the rest aren't really used.
2) This is the way VB works.
Seems a proper fix would be not to allow Strings in structures at all. This change still doesn't feel right - "This is the way VB works" is a dubious path...
I don't agree at all -- this seems perfectly sensible to me. It works the way you would expect it to work if you're not putting a bunch of thought into it. It's pretty obvious that these two pieces of code *should* behave the same, and the do now:
someStruct.someString = "Test"
MsgBox someStruct.someString + "Wahoo"
// and
someString = "Test"
MsgBox someString + "Wahoo"
Honestly Frank, I think you're reading into it way too much. If you want a bucket of bytes, be explicit about what you want. That goes for whether you're using structures or not. MemoryBlock and Ptr are very powerful ways for you to work with binary data, so use it. Monkeying about with strings will only serve to cause confusion in the long run since "string" implies "text."
"String" may imply "text" but that doesn't mean it *is* text. GetSaveInfo comes to mind, but I digress...
To tell you the truth I'm still skittish of structures altogether - everytime I tried to use'm in the past I ran into a bug or impassable limitation. Many of these issues have been, or hopefully will be addressed but often it's just easier to pretend structures don't exist. Maybe I'll try'em again in 2008...
GetSaveInfo, and other older APIs are following a horrible historical context. I hate history some days...
As for being skittish of structures, there's really no reason to be that way. I've used them fairly extensively, and really love the hell out of them.
Yeah but you also like everything in one window too :)
I can see why this makes sense but I can see Frank's point too.
it almost seems that if I wanted a "string" in a structire I should have ahd to make it a Uint8 all the time or Bytes and not a "string" since an RB String is NOT what I'm really using in a structure.
That said, making it so things behave more predicatably is a good move.
What do you mean, "truncate after the null byte"? I sure hope you don't mean the first null byte in the structure, because that would involve lots of data loss! I'm a bit confused as to why anyone would want to grab strings from structures and do *anything* text-ish with them before defining encoding.
@Asher -- I do, and it only results in data loss if you don't understand how to use the feature properly (the same could be said of just about any storage feature).
Defining an encoding has nothing to do with it. Nul is a perfectly legal ASCII and UTF-8 character, for instance. So it doesn't much better if you define the encoding -- you still have a bunch of nul bytes which the majority of people don't expect.
Any similar side affects to embedding a MemoryBlock in a structure?
Structures can't contain any reference counted things, so you can't put any objects into them (including MemoryBlocks).