• Naming conventions (was Re: valgrind leak I can't find)

    From Janis Papanagnou@21:1/5 to Annada Behera on Thu Aug 22 15:32:18 2024
    On 22.08.2024 14:01, Annada Behera wrote:
    On Thu, 2024-08-22 at 08:18 -0300, Thiago Adams wrote:
    On 22/08/2024 08:01, Bart wrote:
    On 22/08/2024 09:41, Mark Summerfield wrote:

    This is the type's struct:

    typedef struct {
    int _size;
    int _cap;
    char** _values;
    } VecStr;

    What's with the leading underscores for member names?

    A convention. (I.e. one convention amongst dozens.)


    It means ending with ->_ later on, which seems pointless extra
    clutter.


    C++ is responsible for this.

    I don't think so. I've seen such conventions in many places, also
    very often in C contexts. Even standards use naming conventions.
    (This is no valuation. I don't give a valuation. Not yet.)

    In C++ I've seen all-caps constant names. (Why? Because C didn't
    have constants supported, only CPP elements used as constants,
    and that got inherited.) Then '_s' suffixes or 's_' prefixes for
    structs. '_t' suffixes for types (typedef entities). 'm_' or '_'
    prefixes for class attributes ("member variables"). Conventions
    to differentiate function parameters from member variables (for
    disambiguity on initialization) or for local function variables.

    I've got the feeling that (technical) information that has its
    definition already at another (appropriate) place gets merged
    into the entities (variables, functions, ...) that (IMO) should
    have _semantical_ names, and not something that looks like a C++
    name-mangled linker-object-name.


    C++ made the usage of 'this->' optional when calling member
    functions.

    I don't think this optionality is (per se) a Bad Thing.

    But to disambiguate or make intentions clear the use of 'this' is
    certainly (IMHO) better than adding technical name components to
    semantical names; you already have a language construct you can use
    for that.


    As a result, when C++ programmers encounter 'i' in the middle of a
    function, they might not know where it comes from.

    In the early 1990's we had coding standards that handles such;
    use of semantical names instead of 'i', locality principle (don't
    declare entities "far away" so you easier see where it's from), and
    use of explicit language features (like 'this') to make it obvious.
    (Maybe there were yet more suggestions - memories are faint.)


    If 'this->' were not optional, 'this->i' would clarify that.

    Indeed.

    Only that it can (also) be perceived as "clutter" (to use a name
    that Bart above associated already with the much terser '_').

    Most programmers I've met are reluctant to type more characters
    than "necessary", and - in the absence of standards/conventions -
    they seem to prefer using '_' or 'm_' or some such.


    To avoid confusion, many C++ programmers use prefixes like 'm_' that
    can't be ignored.

    Since many C programmers also work in C++, this pattern can sometimes
    influence C code as well.

    Although I think this is stupid thing to do when writing C, the same convention also exits in Python PEP-8 [1]

    _single_leading_underscore: weak “internal use” indicator.
    E.g. from M import * does not import objects whose names start with
    an underscore.

    [1]: https://peps.python.org/pep-0008/#descriptive-naming-styles

    It's a typical document. With valuations "better" (without rationale)
    and "ugly!" (which is nothing but a codified opinion).

    There's a lot such documents and yet more existing opinions on naming conventions than options to choose from. I'm sure everyone has one
    and it's not really worth to dispute about that. What individuals do
    in their private projects' context is their own business and companies
    most likely have their conventions documented. - Ah, but there's also
    the standards committees...

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Thiago Adams on Fri Aug 23 17:10:12 2024
    On 22.08.2024 16:01, Thiago Adams wrote:

    C++ also made the use of "struct/union/enum" before tags optional.

    For example:

    struct X x;

    In C++, we can write:

    X x;

    Yes, because it's the "natural" form of a 'Type entity;' declaration.

    With a 'class Player;' we write 'Player p;' as we do with an 'int i;'
    I don't think it would be a good idea to have to write 'class Player p;'
    or 'struct Player p;'. (Mileages may vary.)

    In C++ the C's special type 'struct' has been merged in a generalized
    form of type, a 'class'.

    It may be different for the inherited unions or enums, but anyway...
    If I declare a type and give it a name I want to refer to it by that
    name in object declarations and not repeat (unnecessary) keywords.
    (That's what I'm used to also from other programming languages.)


    Consequence?

    (C has to struggle with its own inconsistencies since ever. Whether
    some C++ language design conventions backfire to C... - well, hard to
    tell. I don't think we can clearly deduce or prove any such (social)
    effects; at least I cannot.)


    Programmers started using a suffix "C" for classes and "E" for enums.

    For example:

    CArray array;
    EType type;

    Yes, I'm well aware of some folks doing so. (That's one point I have
    expressed in my previous post. Yet I don't see any advantage in doing
    so and haven't heard any substantial rationale for that.)



    In C, we have a similar situation where it's sometimes unclear where a variable comes from.

    Consider this code:

    void f(int arg1){
    i = 2;
    }

    This can happen with external variables.

    For instance:

    int i;
    void f(int arg1){
    i = 2;
    }


    In this situation, I use a prefix "s_" for the variable, like this:


    int s_i;

    I'd most likely pass the value through a well defined interface
    in such cases; either use (here) the unused function return value,
    or add a function argument and pass '&i' to set '*iptr=2' instead
    of relying on side-effects accessing global variables, or in more
    complex application data cases add a function parameter-object.

    Preferences vary, of course, also depending on context.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Thiago Adams on Fri Aug 23 11:57:20 2024
    On 22.08.2024 16:01, Thiago Adams wrote:

    C++ also made the use of "struct/union/enum" before tags optional.

    For example:

    struct X x;

    In C++, we can write:

    X x;

    Consequence?

    That's possible because C defines separate name spaces of identifiers
    (not to be confused with C++ namespaces) for labels, tags, each struct
    or union type, and attributes; all other identifiers are in the ordinary
    name space. Because of the relevant grammar rules, names in the
    different spaces can never occur in locations where it is ambiguous as
    to which name space the identifier is from. Therefore, C allows you do
    use the same identifier in different name spaces in the same scope with different meanings. For example, identifiers in the tag name space are
    always prefixed with struct, union or enum, so they can never be
    confused with names from the ordinary name space.

    In C++, there are separate name spaces only for macros and labels. All
    other identifiers are in the same name space, including tags. Class,
    struct, and union members are not controlled by name spaces, but by
    scope rules that are different from those in C. That's what allows you
    to use a tag without a preceding "class", "struct", or "union" keyword.
    Note: The name space for macros isn't really comparable to the other
    name spaces I've mentioned, which is why C doesn't have such a name
    space. Macros are replaced with their expansions during translation
    phase 3, whereas the other name spaces only become meaningful during translation phase 8.

    If C were changed to allow use of tags without "struct" or "union"
    before them, the tag name space would have to be merged into the
    ordinary name space, and that would break all kinds of legacy code that
    uses the same identifier as a tag and as an identifier in the ordinary
    name space. That would be a backwards incompatible change, and the
    committee tends to avoid such changes.

    I once spent some time creating an example program that could be
    compiled in either C or C++, that displayed every construct that had
    defined behavior in both C and C++, but had incompatibly different
    behavior in the two languages. Most of the examples involved name
    spaces. Most of the other differences have at least unspecified behavior
    in one of the two languages; more often they are syntax errors or
    constraint violations in the wrong language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to James Kuyper on Sun Aug 25 18:55:19 2024
    On 23.08.2024 17:57, James Kuyper wrote:
    [...]

    That's possible because C defines separate name spaces of identifiers
    (not to be confused with C++ namespaces) for labels, tags, each struct
    or union type, and attributes; all other identifiers are in the ordinary
    name space. Because of the relevant grammar rules, names in the
    different spaces can never occur in locations where it is ambiguous as
    to which name space the identifier is from. Therefore, C allows you do
    use the same identifier in different name spaces in the same scope with different meanings. For example, identifiers in the tag name space are
    always prefixed with struct, union or enum, so they can never be
    confused with names from the ordinary name space.

    In C++, there are separate name spaces only for macros and labels. All
    other identifiers are in the same name space, including tags. Class,
    struct, and union members are not controlled by name spaces, but by
    scope rules that are different from those in C. That's what allows you
    to use a tag without a preceding "class", "struct", or "union" keyword.
    Note: The name space for macros isn't really comparable to the other
    name spaces I've mentioned, which is why C doesn't have such a name
    space. Macros are replaced with their expansions during translation
    phase 3, whereas the other name spaces only become meaningful during translation phase 8.

    If C were changed to allow use of tags without "struct" or "union"
    before them, the tag name space would have to be merged into the
    ordinary name space, and that would break all kinds of legacy code that
    uses the same identifier as a tag and as an identifier in the ordinary
    name space. That would be a backwards incompatible change, and the
    committee tends to avoid such changes.

    I recall (when I learned C) that the type definitions confused me.

    The clear things were ('typedef'-)definitions like

    typedef struct { double re, im; } complex;

    But then there were also examples like

    typedef struct tnode {
    ...
    struct tnode * right;
    } TREENODE, *TREEPTR;

    (Both examples taken from an old K&R book.)

    In the first case there's no struct name (only the typedef'd one.

    In the second case an explicit struct name (necessary for the
    type self-reference inside the struct) despite type names being
    defined. - Appeared crude to me (and still does).

    I don't recall internal name-spaces (as you explain them above)
    having been documented and explained. But I may be misremembering.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Janis Papanagnou on Sun Aug 25 23:47:45 2024
    On 8/25/24 12:55, Janis Papanagnou wrote:
    On 23.08.2024 17:57, James Kuyper wrote:
    [...]

    That's possible because C defines separate name spaces of identifiers
    (not to be confused with C++ namespaces) for labels, tags, each struct
    or union type, and attributes; all other identifiers are in the ordinary
    name space. Because of the relevant grammar rules, names in the
    different spaces can never occur in locations where it is ambiguous as
    to which name space the identifier is from. Therefore, C allows you do
    use the same identifier in different name spaces in the same scope with
    different meanings. For example, identifiers in the tag name space are
    always prefixed with struct, union or enum, so they can never be
    confused with names from the ordinary name space.

    In C++, there are separate name spaces only for macros and labels. All
    other identifiers are in the same name space, including tags. Class,
    struct, and union members are not controlled by name spaces, but by
    scope rules that are different from those in C. That's what allows you
    to use a tag without a preceding "class", "struct", or "union" keyword.
    Note: The name space for macros isn't really comparable to the other
    name spaces I've mentioned, which is why C doesn't have such a name
    space. Macros are replaced with their expansions during translation
    phase 3, whereas the other name spaces only become meaningful during
    translation phase 8.

    If C were changed to allow use of tags without "struct" or "union"
    before them, the tag name space would have to be merged into the
    ordinary name space, and that would break all kinds of legacy code that
    uses the same identifier as a tag and as an identifier in the ordinary
    name space. That would be a backwards incompatible change, and the
    committee tends to avoid such changes.

    I recall (when I learned C) that the type definitions confused me.

    The clear things were ('typedef'-)definitions like

    typedef struct { double re, im; } complex;

    But then there were also examples like

    typedef struct tnode {
    ...
    struct tnode * right;
    } TREENODE, *TREEPTR;

    (Both examples taken from an old K&R book.)

    In the first case there's no struct name (only the typedef'd one.

    "A declaration other than a static_assert or attribute declaration shall declare at least a declarator (other than the parameters of a function
    or the members of a structure or union), a tag, or the members of an enumeration." (6.7p2)

    Since the typedef declares a declarator (the typedef name) it don't need
    to declare a tag.

    In the second case an explicit struct name (necessary for the
    type self-reference inside the struct) despite type names being
    defined. - Appeared crude to me (and still does).


    I don't recall internal name-spaces (as you explain them above)
    having been documented and explained. But I may be misremembering.

    "The C Programming Language", 1st edition makes no mention of name
    spaces as such. However, the 2nd Edition was updated to match the latest
    draft version of the C89 standard, and explains name spaces in section
    A.11.1, which is titled "Lexical Scope". The final C89 standard
    described scope in section 3.1.2.1, and name spaces in 3.1.2.3.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)