• Comments
  • Looking at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getprivateprofilesectionnames.asp as an example, would I then be correct in assuming that this API could not (hypothetically) use a BSTR for the FileName since it needs to be able to distinguish NULL from a blank string?
  • You state: A: Probably for backwards compatibility with VB5, 4, 3, 2 and 1, which incidentally was called "Object Basic". Ah, the halcyon days of my youth. I think from memory if you have a public member variable in an earlier version of VB (maybe VB 4?) it does actually let you pass it Byref. It was changed in later versions (I can't find the actual MS article discussing it though).
  • You may well be right. Like I said, it was years and years ago that this decision was made, and I wasn't exactly heavily consulted at the time. If you happen to find a reference, I'd be amused to see it. Or, perhaps in my copious spare time I'll look through the VBA source code logs -- I have them around here somewhere...
  • AUGH! 'psz' and 'pwsz' do NOT mean what you claim they mean! as it is you claim equivalenze between 'psz' and 'sz', and type equivalence between 'psz' and 'pch'. treating 'psz' and 'sz' as the same screws up type algebra because you can't cancel 'p' and '*' to match types. i see a lot of people, and when i was at MSFT i saw a lot of internal MSFT code, that gets this wrong; people often claim that they use 'psz' and 'sz' interchangably except that an 'sz' is an owned buffer of some kind (e.g. char sz[32]) whereas 'psz' is a pointer to a buffer that you don't own, but again, that beefs the type algebra. 'pch', 'sz', and 'rgch' all imply type of 'char *'; 'psz' is a pointer to a char *, or 'char **pszFoo;'.
  • another comment about 'I already know the type because of the declaration' is: often the declaration and use are distant from each other. the benefit of using hungarian in that case is that you don't have to look at a line of code and then grovel around to find out how the vars are declared.
  • Though you make a good point, I'd counter that by saying that (a) many developers now use some pretty sophisticated editors that can find the declaration very quickly, and (b) I try to keep my routines under three screens long. If its a local variable, the type is nearby. If it's a member variable or a global variable then sure, sometimes it is a pain to find the storage type, but really, how often do you care whether that counter is a UINT or a DWORD?
  • Hey dave, I was just on my way to forward this your way, just to tweak you on the psz/sz thing. Guess I don't have to bother now. Glad you're still fighting the good fight.
  • Indeed, I have seen many inconsistent uses of this at Microsoft and elsewhere. And yours makes a lot of sense. But surely what's most important is to pick a convention and stick with it? No convention will be perfect.
  • Matthew: Indeed, that API would be a poor candidate for a BSTR, for several reasons, not the least of which is the NULL BSTR issue. Note also that it takes a pointer to TCHARs, which means that it has a different type signature depending on whether it is being used with or without UNICODE. BSTRs, by contrast, are always 16 bit characters on any Win32 operating system.
  • sz/psz is problematic because the language fights you. The distinction is important (sizeof(sz) is very different from sizeof(psz), ask any security expert), but the C/C++ language's autodecay rule means that when you say "sz" it turns into "psz" in rvalue context. In most code that I see, psz means "pointer to array of characters, null-terminated" and sz means "array of characters, null-terminated"; i.e., both are type "char*" when used as an rvalue(. pch is also of type "char*" but does not imply null termination.)
  • I've always thought that it would be handy to make that sort of thing a compile-time error. Describe the set of prefixes you plan to use and how they can be associated with each other, then make the compiler scream at you if you do something Wrong.
  • There's always the Ada way of doing things: creating new integer types, and new subtypes. However, I suspect that most of us don't have the patience for that. As far as I'm aware, there aren't any mainstream languages apart from Ada that allow us to declare the exact valid range of an integer variable, or differentiate apples from oranges within the type system (i.e. with support from the compiler). There's less need for Hungarian prefixes in a strong type system like Ada's, or the user-defined type systems of C++ - because the compiler can tell you you're making mistakes. However, if you have conversion operators and alternate constructors in C++, there's a chance of introducing type errors.
  • I've seen plenty of documentation for C++ programmers stating that a missing BSTR should be represented as "BSTR b = SysAllocString("")" (or equivalent), when in fact using NULL would be much more convenient and of course would not consume any resources. Here's an example, "Visual C++ ADO Programming" from ADO 2.8's documentation: "Coding a Missing Parameter — String When you need to code a missing String operand in Visual Basic, you merely omit the operand. You must specify the operand in Visual C++. Code a _bstr_t that has an empty string as a value. _bstr_t strMissing(L"");" http://msdn.microsoft.com/library/en-us/ado270/htm/pg_ado_programming_6.asp?FRAME=true
  • My primary argument for Hungarian has to do with making code easier to read. Even if the declaration of a local/member/global variable is just a screen away, that's still too far if I'm trying to quickly figure out this line of code where the debugger dropped me. My philosophy for Hungarian notation actually falls between your "sensible" and "pointless" philosophies. I don't look to Hungarian to tell me whether an integer is 16- or 32-bit, signed or unsigned, but I also don't look to it to tell me much semantic information -- I figure the actual variable name is good for that. I do want Hungarian to tell me that the variable is an integer (versus a real number, or a Boolean, or a rectangle, or a pen, or whatever). So "nChildren" is probably the number of children, whereas "bChildren" is probably true if there are any children, and "astrChildren" is probably an array of their names. It communicates enough of the type to know what the basic operations on the variable are, and, combined with the variable name, gives solid semantic information.
  • > 'psz' is a pointer to a char *, or 'char **pszFoo;' Dave, I don't think I'm with you on that one. I'd call a char** a ppsz, not a psz. Like this: char szFoo[] = "foo"; char* pszFoo = szFoo; char** ppszFoo = &pszFoo; I think this is by far the most common convention. I'd never seen a char** called a psz until just now.
Page 1 of 891 (13,355 items) 12345»