Do you usually prefix your classes with the letter 'C' or something else?

Started by
89 comments, last by Ravyne 7 years, 11 months ago

I still maintain my old C style after all these years (even in C++). When I start a project, I'll take the first two letters of the name and make that my prefix. After that, it is the "ol' way of doing things."


void ge_foo_bar( void* foo, const unsigned int bar );

"The code you write when you learn a new language is shit.
You either already know that and you are wise, or you don’t realize it for many years and you are an idiot. Either way, your learning code is objectively shit." - L. Spiro

"This is called programming. The art of typing shit into an editor/IDE is not programming, it's basically data entry. The part that makes a programmer a programmer is their problem solving skills." - Serapth

"The 'friend' relationship in c++ is the tightest coupling you can give two objects. Friends can reach out and touch your privates." - frob

Advertisement

I remember Hungarian Notation being discouraged back when I was first learning to program nearly twenty years ago :D

For some time now my general habit has been no prefixes on anything, but lately I've been experimenting with an underscore in front of non-public declarations.

Expanding a bit beyond talking about just declaration prefixes, and more about creating declarations in general: these days I'm programming mostly in Apple's Swift programming language. They recently developed (with community contributions) API design guidelines for public APIs written in the language, and it's one of the more thoughtful set of guidelines I've seen. Many of the guidelines are only applicable to Swift (its function syntax is C-style, but with named parameters, so many rules are built around that), but a few of the more general little gems I've liked:

  • Methods with side effects are named as imperative verbs, methods without are named as either nouns (like properties) or verbs in "-ing"/"-ed" form. So in a Vector type, "normalized" returns a new Vector, but "normalize" mutates the original instance. Declarations that indicate whether they have side effects really help you reason about your code.
  • The guidelines call for UpperCamelCase and lowerCamelCase, but what about acronyms like URL? Many guidelines I see seem to omit what to do with acronyms, but Swift's (very sensibly, IMO) says to uniformly uppercase or lowercase the acronym according to where it appears in the declaration, so "class URL { }", and "var urlForResource = makeURL()"
  • The guidelines say to document every declaration, but allow for the documentation to only include the summary if that suffices to fully describe the declaration. For example, "func add(a, b)" can be fully documented as simply "returns the sum of a and b" and has no need for what in this case would be redundant "@param" or "@returns" sections like "@param a the first parameter in the sum".
  • Also, document the complexity of any computed property (i.e., a "getter" method in some languages) that's not O(1), since users usually assume properties are O(1), and may run into trouble if they naïvely call an O(n^2) property in a major loop.
  • Finally, on documentation, excellent words to live by: "if you are having trouble describing your API's functionality in simple terms, you may have designed the wrong API."
I always prefix my classes with "C" and suffix them with either "Manager" "Helper" "Utility" or some other meaningless word just because.

I've simplified to the essentials over the years. I prefix for interfaces, cause C# still rolls that way and I like it. (Non-pure abstract base classes are suffixed with Base, usually.) Single underscore to label _private or _protected class variables*. And g_ for globals because those should look gross. That's pretty much the extent of it.

* The underscore thing also works great in languages that don't HAVE private scoping, or when I don't actually private scope them but they're considered implementation details.

I follow this kind of minimalist approach as well. Prefixing classes with C, or variables with their atomic type, or similar things doesn't really tell you anything useful with modern tooling. Even people who work with text-mode editors like emacs or Vi(m) will have CTags or some kind of IDE-like intellisense-thing going on.

Scope is still something helpful to know so I do 'g_' prefixes for globals and 'm_' (or sometimes, just '_') prefixes for private/protected members. I also like to know things like whether a variable is static or volatile at a glance, so I use 's_' and 'v_' prefixes there -- these are rare though.

As far as general naming, I use plural word-forms when dealing with collections of things, and boolean variables/functions are almost always prefixed with a word like 'is' or 'has' to reveal the question being answered -- like 'is_dead' or 'has_children()', among other things similar to what DonaldHays quotes above.

In C++ (as are all of my examples above), I defer to my own personal axiom of "do as the standard library does" regarding naming and other externally-visible conventions. For example, this is the reason I now use lower-case-with-underscores style, rather than CamelCase or pascalCase as I did at different points in the past. When I'm doing C#, my naming conventions follow the style of its standard libraries. My rationalization for why this axiom of mine is a good approach is that 1) these standard libraries represent the only style that has any credible claim that it "should be" the universal style, and 2) they've seen every odd corner case and combination thereof, and have laid down an answer; I don't have to waste brain-cells thinking it through and then being self-consistent on each rare occasion it comes up, months or years between.

Of course, if the place that makes sure your paychecks don't bounce has a house style -- and most do -- then you follow along with that because its part of what you're paid to do.

throw table_exception("(? ???)? ? ???");

I prefix everything with a C except for classes; just to keep people on their toes. At least that way if it doesn't start with a C then I know it's a class :rolleyes:

Seriously though, just encode useful information into your symbol names and you'll be good - I (like most people I suspect) don't actually find it useful to re-encode whether something is a class or not.

So I don't bother prefixing C - I will however attach prefixes for semantics that aren't captured by language's type system...

e.g. cameraPos, cameraAngle, cameraZoom, cameraEnabled

e.g. screenWidth, screenHeight

e.g. warningText, warningColour

At this point, the only reason I'd entertain prefixing a class name with "C" is if I'm mixing structs and classes in my code and I wanted to be able to forward declare the identifier correctly without going back to look at its declaration. In a codebase sufficiently large that hitting "Go to Definition" can take longer than a minute, this can actually be quite useful, if perhaps of dubious value in the general scheme of things. For small codebases, it's basically not a problem.

...but lately I've been experimenting with an underscore in front of non-public declarations.


This one makes sense to me. I can understand a prefix on non-public stuff and having such a consistent prefix works well with autocompletion.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

The real question is, do you prefix your structs with the letter 'S'?

I don't use any prefixes. Maybe, just for globals so I can remember to refactor them out. What I do when I don't know what something is, use hotkeys to go to the definition, find out what it is, and then hit a hotkey to return to where I was in the code before.

The idea has mostly fallen out of favour these days, but that's where it came from.


Indeed, partly because it's much better to let the compiler/tools enforce this safety for you.

Languages that are popular for Web backend development have largely just gained the ability to difference "raw" strings from "baked" strings, as an example.

Sadly, most languages - C++ included - still lack any good support for opaque type aliases, which is necessary to support "contextul" type semantics. A few newer procedural languagess are finally taking some pages out of functional books and gaining algebraic types, which at least helps a little, though they're usually "closed for extension" :(

Sean Middleditch – Game Systems Engineer – Join my team!

This topic is closed to new replies.

Advertisement