The Lounge is rated PG. If you're about to post something you wouldn't want your
kid sister to read then don't post it. No flame wars, no abusive conduct, no programming
questions and please don't post ads.
I (mostly) use Camel case exclusively in C# - because it's the standard. I can't seem to break myself of butOK and butCancel, dgvListNotes and so from though for controls, which harks back to my Hungarian C++ days.
I do use underscores - for Property bases only, to differentiate them from the Property and to make it harder for me to accidentally use the wrong one - set the Property instead of the base in the Property setter, and so forth...
If you get an email telling you that you can catch Swine Flu from tinned pork then just delete it. It's Spam.
I don't think that the fundamental aspects of the C/C++ type system that led to Hungarian notation have really changed.
I suspect that is wrong.
C used untyped parameter passing. Thus even if the method was expecting a int and only a int you could pass a pointer to it. Hungarian lessened the chance of that happening.
Additionally there were no IDEs nor online documentation. If you wanted to know what a method definition was you had the following choices
1. Look at the written documentation
2. Find the code in the code base. This was only possible if one had the source. And wasn't necessarily fast even then.
3. Find an example that already used it.
With hungarian the last case would provide all of the information about the method. Without it one then would need to look up each of the relevant variables.
This has never really been cleaned up. Even .NET developers call into these same APIs pretty frequently and they face the same issue. If you take a look at PInvoke.net[^], .NET developers have come up with declarations allowing
the Windows API to be called from their code. These declarations use the IntPtr type over and over again for all sorts of different things.
Not exactly sure what you are referring to but I suspect a majority of C# developers never use pinvoke. And of the remainder that do many do not use it frequently. And I would like to think that of those that do use it frequently (and unfrequently) that they wrap it in a C# API of their own creation. Thus there would not be any more ambiguity in the usage for them or others at that point.
I'm a .NET developer; in fact, it's my main job right now. I don't use PInvoke
all that frequently, but I probably do use it (i.e. use the Windows API) more
than any other API besides the .NET Framework itself. Yes, I do wrap up those
low-level calls pretty frequently. I have to write the wrapper, though, and in
doing that I face all of those same old issues of weak typing.
When you write a wrapper you are using a new API method of which you must become very familar. Thus you will be using a source (documentation) that tells you the exactly what information is needed. Thus there can be no benifit to you using hungarian notation at that time because you are using the documentation itself.
Subsequent to that you use your wrapper API. And your wrapper API (unless you did it wrong) is strongly typed. You don't use the pinvoke API at all. So hungarian notation has no benefit in this context.
If you, or someone else needs to maintain the pinvoke code later then they are, again, going to need to use the API documentation. Otherwise there is no point in maintaining the code.
The above is a representation of usage scenarios if the a pinvoke API is wrapped rather than just used. If it is not wrapped then type usage is more of a problem however the real problem is that the API is not correctly wrapped.
Here are some examples from the DWM header file (DWMAPI.H):
What does that have to do with anything?
But if you want to use that API - then wrap it. And then it falls into exactly what I said above.
So what are you saying? That Hungarian Notation was really valuable once, but that fundamental changes have now made it worthless?
It serves no purpose in C#, Java and for the most part C++.
It has less value in C due to increased use of IDEs and more so with the increased ease of access to documentation.
C can most definitely do type checking. A well-constructed C API that wanted to distinguish between a 32-bit "double word" and a 32-bit "unsigned int" (as the Windows API seems to want to do) most definitely could, e.g.
You are wrong or your phrasing is poorly done.
C does not type check parameters. Whatever you put on to the stack is what is delivered to the method.
Given these declarations, I cannot interchange instances ...
Method invocation is the problem now.
However in early C compilers even assignment was allowed between different types.
I agree... but if I expand my API, I'll need to write the underlying implementation. That's where I end up using unsafe types like IntPtr.
No idea what you are talking about. Stating it again, if you write a wrapper in C# then the following is true.
1. When you INITIALLY write it there is no gain from hungarian because you MUST know the C API to write the wrapper in the first place.
2. The USERS of your C# api do not need hungarian because the C# API itself is type safe.
3. The maintenance developer who must maintain the wrapper would only run into problems if the wrapper is over complex. And the problem then is not with type resolution but with the failure to wrap the C API in the first place in such a way that it was simple to use. (Adding new C methods falls into 1 above.)
I'd venture to say that Simonyi had at least the second and third of these at his disposal, and he still found Hungarian Notation useful.
He had no more access to documentation at that time than any other developer did.
This is just not true. It's possible to force behavior like that using typecasts (even C# has its little workarounds), but the behavior you're describing is fundamentally opposed to how C actually operates.
C methods do not do type checking. C compilers can use prototypes in headers to do type checking HOWEVER.
1. The prototype must be available.
2. The prototype must be correct.
And the above is irrelevant because it did NOT exist when hungarian was created.
Some of your earlier comments make me think that you believe this to still be the case on modern C compilers
And your comments make me think that you forgot the point of the thread.
At one time there were non-trivial problems for which hungarian notation seemed to offer something like a solution.
NOW, especially with languages created after C, some of the problems do NOT exist. And the remaining problems, even the rationalized ones, are trivial.
In item 1, what you're saying is that the people who actually have to deal with ambiguous Windows API types are just so knowledgeable that they don't need Hungarian Notation
Something is wrong with that statement. When you are writing a wrapper for the first time you are looking at the windows API methods. If you find that it is ambiguous when you are looking at the documentation itself then that is another discussion. So, I can only suppose that you are referring to the hungarian notation that Microsoft uses in their API. Which has nothing to do with my point. My point is about the code that you write to create the wrapper. You don't need to create new hungarian named id variables at that time to understand the Microsoft API.
They faced the same basic issues of type ambiguity,
I wrote C code for years before there was an ANSI standard. I know exactly what sort of ambiguities could arise from using others APIs as well as using my own.
And no the same problems do not exist now. Not even in C. And most definitely not in C#, C++ and Java.
Did they just do something silly, that you don't agree with?
I suggest that you re-read what I said. I didn't say it was silly then. And I used it then. The only problem then was that just as it was being widely popularized C++ was rapidly gaining ground and C++ always did do explicit method type checks. I continued to use it will C++ for a number of years until I realized there was no point.
...They are still not complete in their attempts to resolve the type ambiguity issues of the Windows API, though. If you hover over a method name in Visual Studio, for example, and see "IntPtr,"
Which of course is completely missing my original point. If you need to use a API method - create a wrapper. Then you would never be hovering over a IntPtr in the first place.
Beyond that, all of these notions that some fundamental change has occurred (e.g. that C didn't check parameter types, whereas new languages do) are just not correct.
You are mistaken.
C99 required function prototypes. C90 did not but allowed them. Before that compilers were free to do what they wanted but as C90 neared finalization they tended towards that standard of inferring one - but BASED on the parameters of the first usage.
Microsoft C 3.0 was released in 1985, the same year as Windows 1.0, and it supported function prototypes.
Which doesn't alter the fact that the use was entirely optional. So if you didn't include the header your code still worked - if you got the call correct.
And are you sure that that version of windows did parameter validation? There is a difference between validating the method and validating the parameters.
Your assertion that Hungarian Notation is basically an outgrowth of the pre-ANSI "K&R" C language is an interesting one (and it might even have been true for you, if you didn't have access to Microsoft C 3.0) but it's not backed up by actual history.
I used Microsoft C version 3.0.
Simonyi joined Microsoft in 1981. Simonyi came up with the idea before joining Microsoft.
Are you claiming that prototypes were widely available before 1981 and Simonyi developed hungarian notation despite that?
Others who think that hungarion notation is no longer useful.
When .NET code wants to call an API function, it's necessary to prototype the API function in the .NET language. The developer writing the prototype gets to select the names of the formal parameters. This developer should select names that are meaningful (even if you don't think these DLLImport declarations will be worked with very often).
So in terms of prototyping the the pinvoke method itself - the developer should choose a name that most closely mimics that of the documentation for the method itself. Regardless of what that name is.
Hungarian Notation seems like the obvious way to do this
The obvious way is to use exactly the same name as that used in the documentation for the method.
Then .NET code (likely a wrapper) must be written around these DLLImport declarations. This code will presumably declare IntPtr variables to pass into the Windows API functions
Nope. Not as parameters into the wrapper itself. It might need to use a IntPtr but in that case
1. The wrapper should paass appropriate C#/.Net data types to the method.
2. The method constructs a IntPtr using the passed in values as appropriate.
The above limits the scope of the IntPtr to the wrapper method itself. It is not visible outside the wrapper.
, and one can either use Hungarian Notation or avoid it. The issue is still there, though.
Nope. The scope of the code makes it obvious that one is constructing a data type like an IntPtr and how one is using it, the method only, means it need do nothing else special. One isn't "avoiding" it because the local scope makes it obvious. A more meaningful name choice is one that reflects the nature of the parameter that the IntPtr represents.
That seems like a very odd (and uncommon) way to write code. I can't imagine too
many people did that.
Quite easy for me to think that people forgot to include them.
Quite easy for me to think that, because they were optional, that some developers would consider them unnecessary and thus intentionally leave them out.
And I am sure that Simonyi's variable-naming style (which is all this really is)
evolved over his entire career.
Which is regardless of the point that it originated before he joined Microsoft and also that the original popularzation occurred very early.
"He developed the Hungarian notation convention for naming variables. These standards were originally part of his doctoral thesis."
"He received his Ph.D. in computer science from Stanford in 1977 with a dissertation on a software project management..."
Regardless, you're facing the same issues Windows 1.0 application developers
I just re-read the entire thread. Again what I said was that if you need to use a C API method then you wrap it.
If there is any exposure from that point then parameters that are passed are NOT interop types but are in instead .Net types. Requirements vary but pinvoke method usage is often simple and thus the only need for those types is to expose the functionality the rest of the .Net application via an API that takes C# native types. So there are no IntPtrs.
If more complexity in the API into the functional layer is required then it should definitely represent .Net native types because the layer API should not be a direct map to the C API (otherwise it would be a simple mapping or require additional mapping.)
Your statements however appear to be about local scope usage only. Again if it was me I would probably mimic the parameter names that appear ni the C API. And that has nothing to do with the hungarian notation that the names might or might not have but is instead based on the documented name any nothing else. Why someone else chose that name is irrelevant to why I use it.