Type and variable naming

Is there a convention for naming types and variables?

For example, I have a type named Context which means that I can’t name a variable below Context. I could rename type to Context_Type but then would need to add _Type to the rest of the types in this library lest I be inconsistent.

Alternatively, I can name the variable Ctx and leave the type as Context (also Dev : Device, Devices : Device_List, etc.) which is the approach I’m taking now.

What is the canonical Ada way? I much prefer to use full variable names (in Ada) as opposed to abbreviations. I’m trying to follow the AdaCore naming approach as much is possible but it fails in the case above.

  function Init (Context : out Context) return C.int with
   Import => True, Convention => C, External_Name => "libusb_init";

And a follow-up example below…

I can’t have a Device_Descriptor since that’s a record type in my library. I decided to use the _Kind suffix but I’m not happy about it.

type Descriptor_Kind is
   (Device_Descriptor_Kind,
    Config_Descriptor_Kind,
    String_Descriptor_Kind,

Not sure there is an Ada way, though there are good words in the Ada Style Guide. I’d probably use Ctx, Dev, Devices. I remember a case where someone wanted to write

Put (Long_Name_Describing_Message : Long_Name_Describing_Message_Kind);

which I got changed to

Put (M : Long_Name_Describing_Message_Kind);

At one point, Grady Booch’s convention would have been to write The_{type} : {type}.

Some people might say Init (This : in out Context).

For the Descriptor_Kind problem, could you use For_Descriptor, For_Config etc?

1 Like

I used to always have a _Type suffix for types, but then got annoyed with names that happen to include that word (eg a register field with name “signal type”, which would be Signal_Type_Type if I tried to be consistent). I now use _T instead and never have to worry about annoying cases like that.

2 Likes

BTW, I too tend to prefer longer clearer names, with _ always separating words. I find it really annoying when people arbitrarily omit some letters, even if it’s only 1 or 2 characters shorter and negatively impacts readability (eg ‘strge’ instead of ‘storage’ just to save 2 characters. Yuck!).

Sometimes when I have an equation that involves multiple long variable names, I use renaming locally in a declare block and have the equation use the short names.

2 Likes

I work on code that uses Name_T for type, or only T for the main type of a package. So it is used like this: Package.T.
Like @Micronian2, I think abbreviation is bad for readability.

“Thus, programs must be written for people to read, and only incidentally for machines to execute.” (Harold Abelson and Gerald Jay Sussman, Structure and Interpretation of Computer Programs)
:wink:

1 Like

I’ve used _G for generics, _P for access types. I don’t think I’ve ever had to use _T.

You can do this with a slight modification of specifying the package that the Context type was declared in:

function Init (Context : out LibUSB.Context) return C.int with
   Import => True, Convention => C, External_Name => "libusb_init";

Basically you just need to tell the compiler that the second context isn’t meant to be the variable.

You can find my thinking about this under “Naming Convention” in the PragmAda Coding Standard. The basic principle is that the parts of an identifier, like comments, must add value: they must not repeat what is obvious from the code. Just as in

X := X + 1; -- Add 1 to X

the comment adds no value and should be omitted, so in

type Thing_Type ...

_Type adds no value and should be omitted.

Note that the conflict is not usually between type and variable names, but between type and parameter names.

I can’t comment directly on Context, since I don’t know what it is.

Regarding your second example, the literals of an enumeration type are obviously of that type, so the type name should not be repeated in the literals:

type Descriptor_Kind is (Device, Config, ...);

Descriptor_Name might be a good choice for this.

A little thought will usually suffice to produce a good type name. This type collects the information about a Thing: Thing_Info. This type identifies specific Whatsits: Whatsit_ID. This type names the kinds of descriptors: Descriptor_Name.

As has been pointed out, the package name can be used to distinguish between a type and parameter with identical simple names, but many people find this confusing, so I don’t recommend it.

Parameter names, and especially entry, generic, and procedure parameter names, should work well with named parameter association.

Put (M => ...);

is meaningless.

Put (Message => ...);

is much better.

Research shows that the first few characters of an identifier are the most important for distinguishing it; having lots of identifiers that start the same makes code more difficult to understand. So having lots of identifiers that start with The_ is a bad idea.

Ada.Text_IO has a lot of Puts where the thing to be put is called Item, which I find unhelpful.

I think the Put I was complaining about might actually have been called Send (and you could have a point about Message vs M).

My preference is not to use named association for the ‘interesting’ parameter; Ada.Text_IO.Put ("foo", File => F); (this might be taking it to extremes!)

Probably it’s time to look through :open_book: Ada Quality and Style Guide!

Context : {package_name}.Context;

Yep, I was mentioning that above as well. Using his package names it would be:

Context : out LibUSB.Context

FWIW, I have real difficulty with this one:

Specifically, leave at least one blank space… Outside, but not inside, parentheses.

It seems to be inspired by this principle:

Use the same spacing as you would in regular prose.

That strikes me as an invalid analogy when it comes to using parentheses, which almost always involve calling subprograms. The correct analogy there is not prose; it’s mathematics. I’ve never seen a math text that puts spaces between a function / functional / operator and its argument. It’s always f(x), not f (x), which looks painful. (As if to drive this home… on my monitor, that second “f (x)” word-wrapped between “f” and “(x)”.) I think there is some additional space between f and the parens but definitely not an interword space.

It doesn’t bother me enough that I’ll dig into the compiler / pretty-printer options to figure out how to change it, but just as with f (x), the standard formatting looks painful to me. I don’t think I’ve seen any other language go that route.

The only exceptions I can think to this offhand are package instantiation and type declarations (arrays, discriminated types, …). The rule on spacing parentheses makes complete sense to me in those cases.

2 Likes

Well, it’s not maths, is it. Nor is it prose, ofc.

You may have noticed some folk using -gnatyadsljjkdcmnksd (just keyboard walloping there!), but in about 2000 I decided just to use -gnaty and get used to GNAT’s defaults, which include the space between the subprogram name and the first paren after it (a rule shared by the GNU C coding guidelines). I find the Ada style you recommend just a bit painful!

Against my position, the ARM uses the style you prefer.

-gnatyl (check reference manual layout) doesn’t complain about a missing space. In fact, I think it doesn’t complain either way. For gnatpp, try --RM-style-spacing

1 Like

It is a formal language, so it is closer to mathematical language than natural language.

Yeah, I don’t particularly like GNAT default formatting, so I turn it all off when using Alire.

You wouldn’t have liked he Rational Environment (on R1000 machines). Source code was parsed (“semanticised”!) and stored in an internal form, and you had little if any control over what it looked like when presented on screen.

My introduction to Ada was watching videotapes of Ichbiah, Barnes, and Firth presenting their newly christened language (Ada 80) at the Ada Launch (1980-12-10). One of them (Ichbiah, IIRC) said that Ada used English reserved words (except elsif) so that, when identifiers are English_Words_Separated_By_Underlines, Ada source will read sort of like English text. So this rule follows the intentions of the language designers.

But in nearly 40 years of using Ada, I have seen far too much time and effort expended arguing about style issues, and have come to the conclusion that a language should include as much of this sort of thing as possible as language rules. Then people would have to find something else to argue about. This is why King includes so many style rules.

2 Likes

Against my position, the ARM uses the style you prefer.

Yes, I noticed that, and the option in gnatpp, too! I can’t remember if gnat itself allows that option, though. As I said, it doesn’t bother me so much that I’ll bother to get around it, just enough to make a nuisance of myself. :grin: