void as a function parameter

36b416ed76cbaff49c8f6b7511458883
0
poita 101 May 27, 2006 at 09:34

Is there any difference between:

int myFunc() {…}

and

int myFunc(void) {…}

?

I’ve always assumed that there is no difference but now I’m wondering why people would even bother using the second one.

Thanks in advance

116 Replies

Please log in or register to post a reply.

6b7e1a4b42e4b47d92fdef8bf2bd8e2c
0
Jare 101 May 27, 2006 at 10:05

Old habits die hard. They are identical in C++.

C4b4ac681e11772d2e07ed9a84cffe3f
0
kusma 101 May 27, 2006 at 10:32

poita: some compilers complain if you don’t use void in c-code.

065f0635a4c94d685583c20132a4559d
0
Ed_Mack 101 May 27, 2006 at 10:33

int myFunc() {…} is generally considered better form in C++ :)

25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 10:38

@poita

I’ve always assumed that there is no difference but now I’m wondering why people would even bother using the second one.

Because it looks complicated …

In short: don’t bother.

6aa952514ff4e5439df1e9e6d337b864
0
roel 101 May 27, 2006 at 10:51

well, bother if it is likely that your code gets compiled on an old C compiler.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 27, 2006 at 11:55

The problem with void as a parameter is that it’s not a parameter.

Ok this requires some illustration. You can’t write code like this:

void function(int x, void y, int z)
{
    // ...
}

It serves no purpose whatsoever and just like you’d have to remove ‘void y’ from the above example, it’s best not to write void for a completely empty parameter list.

Unfortunately C++ isn’t consistent with that for functions. You can’t omit the void in front of the function in the example above. Yet it would be completely unambiguous and safe as long as the compiler would enforce that you can’t return any value from such function. Note by the way that we don’t write ‘return void’ either.

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 May 27, 2006 at 13:28

The difference in C is that with (void), you’re specifying that it has no parameters, while with () you’re specifying that the parameters are unspecified unless it is not a functiondeclaration but a functiondefinition, in which case it’s the same as (void). Talking about consistency :). (Note that this is also different from (…), which means it can be called with any number and types of arguments). Of course the () in function declarations doesn’t behave in C++ as in C because of function overloads and all, plus the fact that it isn’t very type-safe.
@Nick

Unfortunately C++ isn’t consistent with that for functions. You can’t omit the void in front of the function in the example above. Yet it would be completely unambiguous and safe as long as the compiler would enforce that you can’t return any value from such function.

In fact it is ambiguous.

int main()
{
    bla(); // a function declaration or a function call expression?
}

Note by the way that we don’t write ‘return void’ either.

That’s because ‘return [typename]’ makes no sense. You’re not writing ‘return int’ either. But returning a void is perfectly legal:

void foo();

void bar()
{
    return (void)23;  // ok
    return foo();     // ok
}
36b416ed76cbaff49c8f6b7511458883
0
poita 101 May 27, 2006 at 13:43

@.oisyn

The difference in C is that with (void), you’re specifying that it has no parameters, while with () you’re specifying that the parameters are unspecified (note that this is also different from (…), which means it can be called with any number and types of arguments). Of course the latter doesn’t work in C++ with function overloads and all, plus the fact that it isn’t very type-safe.

In fact it is ambiguous.

int main()
{
    bla(); // a function declaration or a function call expression?
}

So what’s the difference between specifying no arguments and having unspecified arguments. (I’m using C++ btw)

Also, I don’t see any ambiguity there. As far as I’m aware, you can’t declare a function inside another function so it’s definitely a call.

@.oisyn

That’s because ‘return [typename]’ makes no sense. You’re not writing ‘return int’ either. But returning a void is perfectly legal:

void foo();

void bar()
{
    return (void)23;  // ok
    return foo();     // ok
}

What does casting to a void do? :blink:

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 27, 2006 at 13:46

@.oisyn

The difference in C is that with (void), you’re specifying that it has no parameters, while with () you’re specifying that the parameters are unspecified…

Sorry? You make it sound like with () there are arguments but they are unspecified. Correct me if I’m wrong but there’s diddly-squat difference between (void) and () beyond the syntax.

In fact it is ambiguous.

int main()
{
    bla(); // a function declaration or a function call expression?
}

I was utterly surprised writing void in front of bla actually compiled. :surrender

What’s this useful for anyway?

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 May 27, 2006 at 14:54

@poita

So what’s the difference between specifying no arguments and having unspecified arguments. (I’m using C++ btw)

It’s only applicable to C, in C++ () and (void) have exactly the same meaning.
It’s an old remnant in C, back in the days where people didn’t care about safety ;)

// function that has no params
void foo(void);

// function that may have params, but I don't know what they are at this point
void bar();

// function that has no params
void baz()
{
}

int main()
{
    foo(); // ok, foo has no params
    foo(34); // error

    bar(); // ok, don't know what the params are so allow everything
    bar(1, 2, 3); // ok

    baz(); // ok, same as foo
    baz(34); // error
}

In a sourcefile, you are allowed to define bar with a parameter list:

void foo(void);
void bar();

void foo(int i) { } // error, different signature
void bar(int i) { } // ok, signature was unspecified earlier

Also, I don’t see any ambiguity there. As far as I’m aware, you can’t declare a function inside another function so it’s definitely a call.

Then you are not aware ;). You can declare functions and variables just as well inside functions as you could outside functions. That’s the whole reason why this doesn’t do what you (probably) expect to:

class MyType
{
    MyType();
};

int main()
{
    MyType myVar(); // variable definition with default constructor initialization? Guess again!
}

myVar is a function returning a MyType

What does casting to a void do? :blink:

It voids the result of the expression ;)

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 May 27, 2006 at 14:58

@Nick

Sorry? You make it sound like with () there are arguments but they are unspecified. Correct me if I’m wrong but there’s diddly-squat difference between (void) and () beyond the syntax.

See above, it only is in C. In C++ they are indeed exactly the same.

I was utterly surprised writing void in front of bla actually compiled. :surrender What’s this useful for anyway?

To declare functions inside other functions. The declaration only lives in the scope of the current block. This can be useful to avoid cluttering the global namespace in the current sourcefile:

namespace
{
    int someIdentifier = 0;
}

/* lot of code that uses someIdentifier
    ...
*/

/* then, you decide to include a library in your program
that has a function called 'someIdentifier' you need to use */
void someFunc()
{
    someIdentifier(23);  // error, someIdentifier is an int.
    void someIdentifier(int);
    someIdentifier(23);  // it's ok now
}

of course, if someIdentifier() is in a namespace you’re screwed as you aren’t allowed to declare namespaces inside functions as well (they need to fix that imo)

36b416ed76cbaff49c8f6b7511458883
0
poita 101 May 27, 2006 at 15:17

@.oisyn

It’s only applicable to C, in C++ () and (void) have exactly the same meaning.
It’s an old remnant in C, back in the days where people didn’t care about safety ;)

Ah, I actually remember reading something about that back in the days of learning the language.
@.oisyn

Then you are not aware ;). You can declare functions and variables just as well inside functions as you could outside functions. That’s the whole reason why this doesn’t do what you (probably) expect to:

class MyType
{
    MyType();
};

int main()
{
    MyType myVar(); // variable definition with default constructor initialization? Guess again!
}

myVar is a function returning a MyType

Wow, I’ve been missing out. Could come in handy.
@.oisyn

It voids the result of the expression ;)

Is there any practical reason you’d want to do that?

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 27, 2006 at 18:33

Thanks for heads-up .oisyn!

I find it quite confusing though. I can’t find a practicaly use for it that can’t be done in a clean way otherwise. I believe that allowing to omit void for functions that don’t return anything would be more useful and easier to understand. But if you have arguments why it’s a good thing I’d love to hear them!

25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 19:26

@.oisyn

of course, if someIdentifier() is in a namespace you’re screwed as you aren’t allowed to declare namespaces inside functions as well (they need to fix that imo)

Then you would just write

void someFunc()
{
     someNamespace::someIdentifier(23);  // it's ok now
}

or maybe

void someFunc()
{
     using someNamespace::someIndentifier;
     someIdentifier(23);  // it's ok now
}

I’m not sure if the latter works though …

6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 May 27, 2006 at 19:30

We maintain C code that continues to cause issues because functions are declared with () and then defined with parameters. For example, some version of the system use float and other use doubles.

// foo.c
void foo(a, b)
float a;
float b;
{
   // do something with a and b
}

// bar.c
// we need foo, so declare it
void foo();

void bar()
{
    double a, b; // oops, I forgot the function takes floats
    a = 1.0;
    b = 2.0;
    foo(a, b); // this compiles and does NOT cast the params to floats
}

Be happy you have type safety that avoids this in C++. :wallbash:

@Nick: I think .oisyn aready answered your question. To support removal of void return types you would have to disallow declaration of functions within functions.

25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 19:34

@Nick

Unfortunately C++ isn’t consistent with that for functions. You can’t omit the void in front of the function in the example above. Yet it would be completely unambiguous and safe as long as the compiler would enforce that you can’t return any value from such function. Note by the way that we don’t write ‘return void’ either.

The problem is that a certain popular compiler thinks the return type is int if you do so =)

6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 May 27, 2006 at 19:39

@bramz: Neither of those work in the case described.

// someIdentifier.cpp
namespace someNamespace {
void someIdentifier(int) { ... }
}

// main.cpp
int main()
{
    someNamespace::someIdentifier(23); // this won't compile
    return 0;
}
99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 27, 2006 at 19:42

@monjardin

I think .oisyn aready answered your question. To support removal of void return types you would have to disallow declaration of functions within functions.

Yes, I know, but my actual question was is it more useful to have declaration of functions within functions or have a more consistent syntax for functions that don’t return anything? In other words: Is C++ flawed and should they fix this some time (if they could) or is there a good reason to keep declarations of functions within functions and we should just continue to write void in front of our declarations of functions that return nothing? :blink:

Does anyone know how C# handles this? I’m too lazy to check myself… :p

6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 May 27, 2006 at 19:50

I really don’t have an opinion either way. I don’t recall the last time I declared a funciton inside a function. I think VC++ (6.0?) did assume and int return type at one point (as I believe bramz was alluding). All I have in front of me right now is 2005 express.

It says:

error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

I don’t know what C# does either and I don’t have it on my laptop. :(
I’m too cheap to pay for Internet access at home when I can get it for free with a nice cup of coffee. :yes:

25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 19:56

@monjardin

@bramz: Neither of those work in the case described.

Are we talking about the same thing? I’ve checked it with gcc and _both_ compile just fine …

6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 May 27, 2006 at 20:02

They compile with the function defined in a seperate file and without including that file or declaring the function in file scope?? I am asserting that a project consisting of only the two files described and with no additional code does not compile in VC++ 2005. It should work with no problem if you place all the code in one file, but that’s not the point. ;)
Anyway, I’ll try it out in GCC. It will take me a few minutes to reboot into Linux… :geek:

25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 20:02

@bramz

Are we talking about the same thing? I’ve checked it with gcc and _both_ compile just fine …

This is what I’ve tried:

#include <iostream>

namespace someNamespace
{
    void someIdentifier(int a)
    {
        std::cout << a << std::endl;
    }
}

namespace 
{
    int someIdentifier = 1;
}

void a() // prints 1
{
    someNamespace::someIdentifier(someIdentifier);
}

void b() // prints 2
{
    using someNamespace::someIdentifier;
    someIdentifier(2);
}
    
int main()
{
    a();
    b();
    return 0;
}
25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 20:04

@monjardin

They compile with the function defined in a seperate file and without including that file or declaring the function in file scope?? I am asserting that a project consisting of only the two files described and with no additional code does not compile in VC++ 2005. It should work with no problem if you place all the code in one file, but that’s not the point. ;)
Anyway, I’ll try it out in GCC. It will take me a few minutes to reboot into Linux… :geek:

Duh! =) I was assuming the reader was smart enough to fill in those insignificant details by himself :whistle:

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 May 27, 2006 at 20:06

bramz: the call is fine, it’s the declaration that is the problem. You’re not able to declare someNamespace::someIdentifier within a function (well, unless your currently in the someNamespace scope of course).

Nick: I don’t see why void has to be removed for functions that don’t return anything. It’ll break ALL current code and C++-like languages such as C# and Java are using it as well. There is not an obvious problem with it, so why bother? BTW, it’s also handy for templates

template<class T> T func()
{
    return someOtherFunc<T>();
}

Compiles fine for T=void

25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 20:12

@.oisyn

bramz: the call is fine, it’s the declaration that is the problem. You’re not able to declare someNamespace::someIdentifier within a function (well, unless your currently in the someNamespace scope of course).

Well, exactly, but that doesn’t matter, does it? The reason why we’d like to declare it inside the function is because the compiler wouldn’t confuse it with the variable. But since the function is now inside someNamespace, we have other means to tell the compiler what someIdentifier to use. In fact, even without the variable, we’d still need to tell the compiler in what namespace to look (apart from ADL of course). So in short: we can’t, but we don’t need to anyway.

6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 May 27, 2006 at 20:21

And that’s why it only comes up in esoteric discussions like this one. ;)

25bbd22b0b17f557748f601922880554
0
bramz 101 May 27, 2006 at 20:30

BTW, what do you do in case it’s the other way around?

#include <iostream>
    
void someIdentifier(int a)
{
    std::cout << a << std::endl;
}

namespace 
{
    int someIdentifier = 1;
}
    
int main()
{
    someIdentifier = 2; // oh bugger
}
6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 May 27, 2006 at 20:34

Well… :blink: Don’t do that! :D

I think ::someIdentifier will disambiguate the function, but I have know idea how to get the variable.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 168 May 27, 2006 at 21:03

Well, you can’t get to it if it’s in an anonymous namespace :blink:

6d318bb67270aa12b325e2cd7b64ff7a
0
pater 101 May 27, 2006 at 21:30

You shouldn’t be declaring global variables that way, anyhow… :P

Ef55e1db61c529fd7248ee5b5ea2d9a4
0
Borogove 101 May 27, 2006 at 22:30

@poita

Is there any practical reason you’d want to do that? {cast the result of an expression to void}

If at high warning levels, your compiler warns on, e.g., the result of a function call being ignored, you can use the void cast to suppress that warning:

printf(“blah”); // warning: function result is int, ignored
(void)printf(“blah”); // no warning

Da26e799270ce5e8b62659ed77b11cef
0
Axel 101 May 27, 2006 at 23:24

@bramz

Because it looks complicated …

And because its more consistent.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 28, 2006 at 08:18

@.oisyn

I don’t see why void has to be removed for functions that don’t return anything.

For the same reason we stopped writing (void) for empty parameter lists. If function declarations within functions were not allowed then writing void in front of a function that doesn’t return a value is just as obsolete. If your function does’t take arguments, don’t write it, if it doesn’t return a value, don’t write it. At least don’t be forced to write it…

It’ll break ALL current code and C++-like languages such as C# and Java are using it as well. There is not an obvious problem with it, so why bother?

I know it could break current code (but hardly ALL code). But I’m thinking progressively here. Improving the signal/noise ratio. There was no “obvious problem” with K&R style declarations but I’m glad it’s gone (for the most part). I don’t like writing extra words that have no purpose.

Would you add function declarations inside functions as a feature for a new imperative programming language?

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 10:41

This is probably off-topic, but as far as the improvements for the C++ are concerned.. one thing I would like see:

  1. ‘this’ should be a reference.
  2. accessing member variables only thru this-reference.

This way people wouldn’t need to use some prefixes such as m_ to mark member-variables and there wouldn’t be the problem local variables masking member ones.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 28, 2006 at 11:23

@juhnu

  1. ‘this’ should be a reference.

Agreed.

  1. accessing member variables only thru this-reference.

Please no. That’s five extra characters for every member variable you access. Imagine what a simple Matrix class would look like. For places where it matters, I use ‘this->’ and I would prefer a ‘this.’ syntax but there are plenty situations where it creates a bad signal/noise ratio. The use of ‘m_’ should die completely though.

Edit: Just to clarify, I think accessing member variables though ‘this.’ is a good thing, but it shouldn’t be forced.

Da26e799270ce5e8b62659ed77b11cef
0
Axel 101 May 28, 2006 at 11:43

“this” will not become a reference, because it would naturally break compatibility for no good reason but syntactic sugar.

And I agree with Nick that its no good idea to force member variables to be accessed through “this”. Besides it would break existing code too.

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 13:02

@Axel

“this” will not become a reference, because it would naturally break compatibility for no good reason but syntactic sugar.

Yeah you are right. Both of these would break existing code, so there’s no way things would change. However the reference would ‘the right thing to do’ though. I just googled about this and found this:

Why is “this” not a reference?
Because “this” was introduced into C++ (really into C with Classes) before references were added. Also, I chose “this” to follow Simula usage, rather than the (later) Smalltalk use of “self”.

http://www.research.att.com/\~bs/bs_faq2.html#this
@Axel

And I agree with Nick that its no good idea to force member variables to be accessed through “this”.

Lots of people are using different naming conventions for local and member variables because of this problem and I think writing “this.” wouldn’t be that bad, at least better than ‘m_’ or some other non-standard prefix. If you see some C# coding guidelines they recommend you to access member variables always thru this reference.

25bbd22b0b17f557748f601922880554
0
bramz 101 May 28, 2006 at 13:26

@juhnu

  1. ‘this’ should be a reference.
  2. accessing member variables only thru this-reference. This way people wouldn’t need to use some prefixes such as m_ to mark member-variables and there wouldn’t be the problem local variables masking member ones.

These are the sort of “improvements” of which you have to wonder: “what happens to existing code?”. So, though (1) might have been a better idea, it won’t happen. About (2), today you already have the choice to access all your member variables through this anyway, so why break all that existing code?

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 28, 2006 at 13:32

@Axel

“this” will not become a reference, because it would naturally break compatibility for no good reason but syntactic sugar.

I wonder if, hypothetically, ‘this’ could automatically evaluate to a reference type or a pointer type (sort of like an implicit cast operator), it could possibly break any existing code…

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 13:42

@Nick

I wonder if, hypothetically, ‘this’ could automatically evaluate to a reference type or a pointer type (sort of like an implicit cast operator), it could possibly break any existing code…

or they could introduce a new keyword “self” ;)

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 May 28, 2006 at 13:49
#define this (*this)

:blink:

About member access: that should definitely NOT change. Or do you think you should always type the fully qualified name for any global as well (e.g., ::mynamespace::myfunction instead of myfunction)? Because they’re not so unrelated

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 28, 2006 at 13:49

@juhnu

or they could introduce a new keyword “self” ;)

Then I rather keep writing ‘this->’. :sad: And in fact that would instantly break all code that uses ‘self’ as an identifier.

Seriously though, I’d love to find one example of currently valid C++ code that would break when ‘this’ can automatically evaluate to a reference.

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 May 28, 2006 at 14:02

Or, if we had some sort of typeof operator

template<class T> struct thisref_t : public T
{
    T * operator -> () { return this; }
};

#define this static_cast<thisref_t<typeof(*this)> &>(*this)

class MyClass()
{
    void foo();
    void bar()
    {
        this.foo(); // ok
        this->foo(); // ok
    }
};

Then again, that would disable the use of an operator-> defined in MyClass

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 14:02

@Nick

Then I rather keep writing ‘this->’. :sad: And in fact that would instantly break all code that uses ‘self’ as an identifier. Seriously though, I’d love to find one example of currently valid C++ code that would break when ‘this’ can automatically evaluate to a reference.

Yeah, I’d prefer writing ‘this->’ over ‘self.’ too actually. The automatic evaluation to a reference type is an interesting idea. I can’t think of any example rightaway where it wouldn’t work. ‘this’ should be a pointer by default, and implicitly casted to a reference when needed.

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 14:07

@.oisyn

Then again, that would disable the use of an operator-> defined in MyClass

and it would have problems when you want to pass ‘this’-pointer to a function.

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 14:16

@bramz

About (2), today you already have the choice to access all your member variables through this anyway, so why break all that existing code?

..because then the compiler would help in catching some bugs like in this:

struct Foo {
   int legCount;
   void SetLegCount(int legcount) {
     this->legCount=legCount;
   } 
};

To avoid this I usually use ‘p’-prefix for function parameters. Maybe if there was a keyword to define the normal member access or a stricter one for a function?

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 May 28, 2006 at 14:30

I think I found an interesting (but unfortunate) counter-example:

class ABC
{
    void doX(ABC *abc);
    void doX(ABC &abc);

    void doY();
    {
        doX(this);   // Call first or second version?
    }
};

So clearly it wouldn’t work to have ‘this.’ syntax with backward compatibility.

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 14:39

@Nick

I think I found an interesting (but unfortunate) counter-example:

class ABC
{
    void doX(ABC *abc);
    void doX(ABC &abc);

    void doY();
    {
        doX(this);   // Call first or second version?
    }
};

So clearly it wouldn’t work to have ‘this.’ syntax with backward compatibility.

That would call the first one as the ‘this’ would be evaluated as a pointer.

25bbd22b0b17f557748f601922880554
0
bramz 101 May 28, 2006 at 14:49

I think we can conclude that, today, the benefits of this as a reference (or automatic reference/pointer thing) does not outweight its burden =)

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 28, 2006 at 15:38

@bramz

I think we can conclude that, today, the benefits of this as a reference (or automatic reference/pointer thing) does not outweight its burden =)

well..I’d like to hold off judgement on a thing like that, sir, until all the facts are in. =)

25bbd22b0b17f557748f601922880554
0
bramz 101 May 29, 2006 at 12:38

What other facts do you want?

Thing is, we can’t get it to being a reference exclusively, for obvious reasons. So, if we want it to act as reference, we should give it a dual character of being both a reference and pointer, but that poses ambiguities that confuse matters in a way that’s not proportional to the rather mundane problem at hand: being able to write a dot instead of an arrow. Frankly, I hardly ever use the this pointer anyway. Or more correctly: if I do, it mostly is to pass it as an argument to a function. This minor syntantic change is really not worth the troubles …

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 29, 2006 at 13:23

@bramz

What other facts do you want?

Can you think of a situation where the dual-nature of a this-pointer/reference would cause problems in the existing code?

25bbd22b0b17f557748f601922880554
0
bramz 101 May 29, 2006 at 13:25

@juhnu

Can you think of a situation where the dual-nature of a this-pointer/reference would cause problems in the existing code?

See above … operator-> and foo(bar*) + foo(bar&)

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 May 29, 2006 at 13:37

@bramz

See above … operator-> and foo(bar*) + foo(bar&)

ah yes, the operator-> would be a problem indeed, but foo(bar*)/foo(bar&) wouldn’t….. ok I give up ;)

6ad5f8c742f1e8ec61000e2b0900fc76
0
davepermen 101 May 29, 2006 at 18:02

i’d prefer my over self..

my.counter ++; just sounds as good or bad as self.counter ++; (imho, my sound better).

but i don’t care about it at all :D and there is no chance because of backwards compatibility..

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 01, 2006 at 16:30

@Nick

The use of ‘m_’ should die completely though.

Care to explain why? I like my m_ ´s.

6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 Jun 01, 2006 at 17:21

@davepermen

i’d prefer my over self..

Do as .oisyn pointed out:

#define my (*this)

Of course, you’re a C# guy anyway right? ;)

40df6f0cd8571262dabedf4bdcf1e093
0
Groove 101 Jun 01, 2006 at 17:52

I prefer self too. It’s a more commom one also used in Python

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 Jun 01, 2006 at 18:27

@SigKILL

Care to explain why? I like my m_ ´s.

I dislike the underscore, my preference would be mMemberVariable and sStaticVariable and such. Unfortunately, the m_ is a coding standard at our company. But on the bright side of things, Visual Assist has the feature to interpret the sequence [m] [shift] as m_ :blink:

25bbd22b0b17f557748f601922880554
0
bramz 101 Jun 01, 2006 at 18:41

this->, this., my., self., foo., bar->, it really doesn’t matter does it? It’s not English literature. C++ has this-> and that’s what we’re going to have to use. If you can’t deal with it, then design your own language. Abusing the preprocessor to “fix” the syntax to your own taste, is just plain evil. One should be expelled from class for doing that. Reminds me of those pascal veterans who defined begin and end to { and }. Can you image combining STL code with that?

Quote:
Originally Posted by Nick
The use of ‘m_’ should die completely though. Care to explain why? I like my m_ ´s.

I’d like to know why myself. Over the years, I’ve used myFoo, m_foo and now I’m using foo_. The latter is my personal favourite, but it really doesn’t matter which one you use, does it? It’s just a matter of taste (avoid the leading underscore though, that’s in the gray zone of names-reserved-to-the-implementation). As long as you’re doing it consistently (within the scope of one file at least), any programmer worth speaking of will be able understand it. There are more effective ways to achieve incomprehensibility.

6ad5f8c742f1e8ec61000e2b0900fc76
0
davepermen 101 Jun 01, 2006 at 20:50

it should die because it’s not a language feature but a coding convention.. thus they can lead to errors a compiler can not detect.

if m_ would be what this-> is today, then it would be fine.. but it isn’t.. it’s a “shotcut” people made because they didn’t understood this->…

and yes, i’m a c# junkie, and no, i don’t bother about stuff like this->, this., my., self., etc… but if i had the choise… :D

25bbd22b0b17f557748f601922880554
0
bramz 101 Jun 01, 2006 at 22:54

@davepermen

if m_ would be what this-> is today, then it would be fine.. but it isn’t.. it’s a “shotcut” people made because they didn’t understood this->…

In some sort of funny and ironic way, m_ is what’s this-> is today*. If you choose to use this->foo for all your members, then that’s fine. However, if you choose to use m_foo, then that’s an equally fine coding convention. Being a shortcut implies that people understood what they were shortcutting in the first place =)

* of course, you can’t simply go and replace this-> by m_ everywhere, but I didn’t need to explain that, did I? ;)

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 01, 2006 at 23:03

@bramz

I’d like to know why myself. Over the years, I’ve used myFoo, m_foo and now I’m using foo_. The latter is my personal favourite, but it really doesn’t matter which one you use, does it? It’s just a matter of taste (avoid the leading underscore though, that’s in the gray zone of names-reserved-to-the-implementation). As long as you’re doing it consistently (within the scope of one file at least), any programmer worth speaking of will be able understand it. There are more effective ways to achieve incomprehensibility.

It generally lowers the signal/noise ratio.

It’s clearly intended to increase the ‘signal’ part, by telling us which variables are member variables. And it is sometimes assumed not to touch the ‘noise’ part. Unfortunately, it doesn’t get very close to that goal:

  • Most IDE’s have powerful coding assistance. If it’s really necessary to know whether we’re working with a member or not, it often suffices to hover the mouse over the variable. When you don’t need to know whether it’s a member, or don’t need to be reminded of it over and over again, ‘m_’ is nothing but noise.
  • Functions ought to be short. You should be able to see function arguments and local variables, so everything else is a member variable. The only exceptions are globals, but these should be rare, and should use the short scope short name / long scope long name convention. If your application has long functions or more than three globals, consider redesigning, not adding ‘m_’ to each and every member variable.
  • Mathematical variable names are typically short for compactness. For example a Vector class needs only x, y, z. Polluting this by adding ‘m_’ makes it far harder to read already complicated formulas.
  • This brings me to my favorite argument: misinformation. Is every variable without ‘m_’ definitely not a member variable, and is every variable with ‘m_’ idefinitely a member variable? In the Vector example we might be tempted omit the ‘m_’ for readability but then we can’t rely on the first assumption any more. And when refactoring we might copy a member variable to a function because it’s only used locally, forgetting to remove the ‘m_’. Or someone might use ‘m_’ for a whole different reason. It’s all manually managed and to err is human, so we can just never rely on ‘m_’ being correct information.
  • We have a lot more screen real-estate these days. Use it. It’s easy to have two columns of code; for example a header file and it’s corresponding source file. This way you know which variables are members, and a whole lot more useful information, in a glimpse. No need to duplicate that information by adding noise to the source file.
  • It’s cryptic. Nobody likes decyphering code, it’s hard enough as it is with explicit names. If you have to or if it clarifies things add ‘this->’ to member variables and ‘global’ to global variables, but don’t invent your own codes. Even if you think they’re used widely, they’re not.

Note that none of this is addressed personally at anyone using this notation I just tried to give a few main reasons why in my opinion using ‘m_’ is a bad idea. And the ‘m_’ could also be any other wart.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 01, 2006 at 23:59

@bramz

I’d like to know why myself. Over the years, I’ve used myFoo, m_foo and now I’m using foo_. The latter is my personal favourite, but it really doesn’t matter which one you use, does it? It’s just a matter of taste (avoid the leading underscore though, that’s in the gray zone of names-reserved-to-the-implementation). As long as you’re doing it consistently (within the scope of one file at least), any programmer worth speaking of will be able understand it. There are more effective ways to achieve incomprehensibility.

And now the personal answer… (You didn’t think you could get rid of me that easily, did you?) :p

It’s interesting that you’ve used three ‘conventions’. It perfectly illustrates the cryptic-ness and misinformation arguments. First of all ‘my’ is used in so many contexts that it has practically no meaning. Frankly I’ve never seen it used to denote member variables. But apparently you realized that too so you switched to ‘m_’. It’s a tiny bit more commonly used, but while switching you must have had a lot of code using both ‘my’ and ‘m_’. I assume you were the only one reading that code because switching conventions always creates misinformation for others. And finally you settled for adding ‘_’ to the end (I bet you still have ‘m_’ around). People use that for all sorts of reasons so it’s either non-information or misinformation, and definitely cryptic. How much of a convention is it when you’ve used three different ones, and there are probably several more out there?

And don’t take this too personally but do forgive my bluntness: Who do you think you are to consider “any programmer worth speaking of” to fully understand your cryptography (twice revisioned)? If you invent another one tomorrow does that make everyone else a worse programmer? Clearly there’s something wrong with using these member variable indications, not with the persons who have to read it.

I do can consider “any programmer worth speaking of” someone who understands ‘this->’ and ‘global’ and knows where to look for the exact definition of a variable… So just stop adhering to one ‘convention’ (out of many), that only applies to specific situations. Instead constantly evaluate the signal/noise ratio by using clear names, being explicit when it helps clarifying the code, and assuming the readers to know the language and nothing more.

860fe478a2545d6c07b88c759292499e
0
SmokingRope 101 Jun 02, 2006 at 02:21

I had a similar desire to have a local, global and params operators which could be used like this. Each of the keywords would make intellisense pop up the corresponding variables. I’ve found that by placing the ‘m_’ in my member variables theres less ambiguity when you have something like:

void MyClass::Function(int p_x)
{
    m_x = p_x;
};

You can’t guarantee that the ‘m_’ means member variable but it typicaly ensures that you’re not assigning to your parameter or some other name/scoping issue.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 02, 2006 at 06:55
void MyClass::Function(int x)
{
    this->x = x;
};

‘Nuff said.

25bbd22b0b17f557748f601922880554
0
bramz 101 Jun 02, 2006 at 09:32

First of all, I’ve switched styles because I’ve switched environments. Not as in the IDE kind of environments, but as in the people kind of environments. Nowdays I’ve got accustomed to the trailing underscore, so that’s perhaps why it’s my favourite. Yes, in my/our codebase, we have code in both styles. But we don’t have both styles in one file. If I go back to the old code to fix bugs or to add new features, I do use the old style. Consistent within at least one file.

If you think m_ or whatever style doesn’t add to the signal but only to the noise, then that’s fine for me. It’s your choice, it’s your style. I’m not going to say that what you do is bad or wrong, because it isn’t. Personally it takes me more time to figure out wether something is a member or not in your style, than in a style using my, m_ or trailing _. But that’s perhaps because I’m not used to it.

This is no less of a style issue than whether using camelStyleNames or underscores_like_stl, whether to start typenames with a capital and variables and functions with a lower case or to start everything with a capital, whether to use tabs or spaces, whether to write int* a or int *a or int * a. I’m sure you have figured out good reasons why to choose one above the other, but frankly, I don’t care. It’s a matter of personal taste (*). The only thing that is important is to be consistent, unless there’s a good reason to make an exception. There are far more important things to put in a “code convention” than this.

(*) There are of course a few things like avoiding leading underscores and double underscores that are more than a matter of taste. Also using allcaps for macro names and nothing but macro names is generally thought of as a good way to avoid creepy name clash surprises.

36b416ed76cbaff49c8f6b7511458883
0
poita 101 Jun 02, 2006 at 11:30

I must be missing something here but why do people use m_ anyway? It seems like a pointless waste of time and makes your code look ugly.

Can someone please enlighten me? :-/

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 Jun 02, 2006 at 11:33

@Nick

void MyClass::Function(int x)
{
    this->x = x;
};

‘Nuff said.

That’s quite error prone and exactly why I would prefer accessing members only this-> (at least optionally)

void MyClass::Function(int X) some_funky_id_here_which_forces_using_this {
   this->x = x; //compile time error
}
6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 Jun 02, 2006 at 13:03

@poita

I must be missing something here but why do people use m_ anyway?

I believe it came from Micro$oft and they required its use internally. Take a look at the MFC sources for an excellent example of Hungarian notation abuse.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 02, 2006 at 13:51

@bramz

First of all, I’ve switched styles because I’ve switched environments. Not as in the IDE kind of environments, but as in the people kind of environments. Nowdays I’ve got accustomed to the trailing underscore, so that’s perhaps why it’s my favourite. Yes, in my/our codebase, we have code in both styles. But we don’t have both styles in one file. If I go back to the old code to fix bugs or to add new features, I do use the old style. Consistent within at least one file.

In my opinion that’s just plain horrible. It requires you to constantly switch your brain just to keep consistent to the artificial rule. That’s probably still slightly manageable with two or three people who know the code base. But what if you have more people on the team, some even preferring their own dialect of Hungarian notation? Besides, if you know the code base, any prefix or postfix becomes insignificant. It’s just plain noise.

If you don’t use prefixes/postfixes, life’s a lot easier. Everybody can understand the code, it’s compact without being cryptic. They can use code assistence for correct information, they can read the function’s arguments and local variables, and/or they can look at the header files to get all the information at once. And most of all, it’s not in the way when you don’t need it. If you can’t remember a class’s members or a function’s variables then you really have to consider refactoring things.

Personally it takes me more time to figure out wether something is a member or not in your style, than in a style using my, m_ or trailing _.

Certainly. But how many times do you really have to know whether a variable is a member? Is it really worth all the hassle to write and read ‘m_’ and keep things consistent? How much time did you loose writing all that, correcting it, debugging it?

Personally I practically always already know whether a variable is a member or not, just by reading the code. I don’t have to be reminded of it every time I use that same variable. The header file is always close and hovering the mouse over variables is handy for the one-time occasions.

This is no more of a style issue than whether using camelStyleNames or underscores_like_stl, whether to start typenames with a capital and variables and functions with a lower case or to start everything with a capital, whether to use tabs or spaces, whether to write int* a or int *a or int * a. I’m sure you have figured out good reasons why to choose one above the other, but frankly, I don’t care. It’s a matter of personal taste (*). The only thing that is important is to be consistent, unless there’s a good reason to make an exception. There are far more important things to put in a “code convention” than this.

As long as it’s C++ and English I’m quite ok with any style as long as it’s concise. But it’s definitely not all a matter of taste. Some ‘habits’ create code that is on average harder to read, harder to understand, harder to debug, and/or harder to manage…

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 02, 2006 at 14:13

@juhnu

That’s quite error prone…

Is it? It’s just as error prone as “m_x = x;” as far as I know. It just relies on language features everybody understands, instead of ad hoc rules.

And this is the perfect opportunity to stress the importance of testing. I can write dozens of ‘error prone’ situations, but with a minimum of testing the errors would instantly be exposed and trivial to fix. So I wouldn’t turn clean and verifiably working code into ascii soup just because that could make it less error prone. I’d expect the contrary…

860fe478a2545d6c07b88c759292499e
0
SmokingRope 101 Jun 02, 2006 at 14:23

Well assuming you’ve actually got a consistent naming scheme, knowing the scope of a variable helps quite a bit when performing memory management.

You know the ‘m_’ pointer will be deleted in the destructor. You know ‘p_’ pointer probably shouldn’t be deleted. You know ‘l_’ pointer needs to be deleted or you’re gonna piss somebody off.

6f0a333c785da81d479a0f58c2ccb203
0
monjardin 102 Jun 02, 2006 at 18:11

Or you could use a smart pointer and not worry about the scope. :whistle:

I wasn’t familiar with that convention, but I believe assuming that a member pointer is released in the destuctor could cause major inconsistancies.

Also, if p shouldn’t be deleted then why not pass it as a reference (if it can’t be NULL)?

25bbd22b0b17f557748f601922880554
0
bramz 101 Jun 02, 2006 at 19:14

@Nick

In my opinion that’s just plain horrible.

no, that’s just plain reality.

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 Jun 03, 2006 at 03:39

@Nick

Is it? It’s just as error prone as “m_x = x;” as far as I know. It just relies on language features everybody understands, instead of ad hoc rules.

I think you missed the idea here a little bit. “m_x = x” is not an equivalent case. The problem is that this->x = x; won’t give you a compile time error in case x is not actually defined in the local scope.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 03, 2006 at 08:52

@juhnu

I think you missed the idea here a little bit. “m_x = x” is not an equivalent case. The problem is that this->x = x; won’t give you a compile time error in case x is not actually defined in the local scope.

I know, but why would you want a compile time error there in the first place? If you test your software, which I hope you do, then a bug like this is absolutely trivial to spot and correct. Frankly an experienced programmer doesn’t write such trivial bugs any more. There are far more complicated bugs where any kind of notation just doesn’t help. It’s the same thing with Hungarian notation. How many times does using the wrong type pass testing, and Hungarian effectively prevents it? The only thing that helps in my opinion is to write clear, uncluttered code.

Anyway, I was only replying to the “quite error prone” part of your suggestion. It’s error prone but in practice ignorably little, comparable to any other typo that is trivial to correct. So I used it as an argument that ‘m_’ is of little help. In fact just like Hungarian notation I ignore it when I see it, while using ‘this->’ isn’t part of the variable name so it’s not that easily ignored. But I see that this not being part of the variable name is exactly what you’re trying to address…

As an extension of C++, your suggestion makes sense. Just like we can specifiy ‘const’ for a function that doesn’t modify any member variables, we could simply specify ‘this’ for functions where member access has to be explicit. I still don’t think it would help much (when already using ‘this->’ it doesn’t increase signal/noise, it’s just a one-time trigger for compiler errors, after that it’s noise). I’d rather just have elegant code that has been tested. But if it would stop the use of ‘m_’ so people can use a language/compiler supported notation, I’m all for it. :yes:

6b7e1a4b42e4b47d92fdef8bf2bd8e2c
0
Jare 101 Jun 03, 2006 at 10:56

@Nick

I know, but why would you want a compile time error there in the first place? If you test your software, which I hope you do, then a bug like this is absolutely trivial to spot and correct. Frankly an experienced programmer doesn’t write such trivial bugs any more.

Sorry if I sound condescending, but there’s a point in religious debates where everyone needs to let go.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 03, 2006 at 12:11

@Jare

Sorry if I sound condescending, but there’s a point in religious debates where everyone needs to let go.

I’m sorry but it’s not a religious debate. There are real-world technical arguments pro and against the use of ‘m_’. Everybody is free to make his own conclusions, I just gave some extra arguments in case some people missed them.

And if it were a religious debate, then yes, there’s a point where everyone needs to let go. I acknowledge the advantages of ‘m_’, I just hope everybody acknowledges its disadvantages as well. It’s impossible to have a healthy debate without understanding each other’s arguments. Nobody comes to these forums to hear himself speak.

It’s just that in my personal opinion the disadvantages (still) outweigh the advantages. That’s all. I’m not trying to ‘convert’ anyone, just give a complete list of arguments. Heck, I’d love to hear more arguments of its advantages, maybe I’m missing some…

6ad5f8c742f1e8ec61000e2b0900fc76
0
davepermen 101 Jun 03, 2006 at 16:47

hm.. i can hear myself speaking in this forum… uuuhhh…

:D

no, but really.. the problem would be solved if this-> would be mandratory.. not optional. of course, nobody would want that, because the shortcut (leaving out this->) is so handy..

wellwell.. i don’t use any of those things.. but i do catch myself sometimes call the class-local variable “myVariable”.. and very often, the passed parameters with same name will get a new in front.. that means:

class Vector {
   float x;
   float y;
   float z;
   public Vector(float newX, float newY, float newZ) {
      x = newX;
      y = newY;
      z = newZ;
   }
}

and in the same way, if i write some assign operator, it would be otherX, or what ever..

thats less general than the m_ p_ and l_, but then again, it does only implicit state the variable-locality-type. instead it describes what the variable is actually ment for.. this is the new value, this is the original value, this is another value, this is the old value.. etc..

i prefer names that simply describe a variable for it’s purpose. everything else is, for me, non-useful overhead.

6b7e1a4b42e4b47d92fdef8bf2bd8e2c
0
Jare 101 Jun 03, 2006 at 23:29

@Nick

I’m sorry but it’s not a religious debate.

Lacking a formal definition of what a “religious debate” is, I’ll offer two ideas:

  • It has (repeatedly) shown up in pretty much every programming discussion forum for a long time. And never managed to generate anything near a reasonable conclusion, rather ending only when all the parties grow bored.

  • Arguments are either reduced to expressing personal preferences, or rely too much on peripheral or circumstantial details for validity and applicability.

It’s perfectly fine to offer opinions, ideas, experiences and even bits of knowledge about these topics, but there’s a point when the debate degenerates into desperate attempts at justification, or even worse, absurd statements. To me, ideas like “an experienced programmer doesn’t make such trivial mistakes anymore” or “why would you want a compile time error there in the first place?” fall squarely in that category.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 04, 2006 at 12:46

@Jare

It has (repeatedly) shown up in pretty much every programming discussion forum for a long time. And never managed to generate anything near a reasonable conclusion, rather ending only when all the parties grow bored.

I’m sorry if you got bored. I myself found davepermen’s post one of the most interesting and learnful. Also juhnu’s suggestion is worth some thought.

And discussions like this do get conclusions in the long run. Hungarian notation is advised against in C# style guides and on its way out. And I’m telling you, ‘m_’ is next.

Arguments are either reduced to expressing personal preferences, or rely too much on peripheral or circumstantial details for validity and applicability.

I’m sorry, but which of my six primary arguments were expressing personal preference? Or which rely too much on peripheral or circumstantial details? To me they are pretty much facts but I’m willing to reconsider them if you would be so kind to point out the flaws.

It’s perfectly fine to offer opinions, ideas, experiences and even bits of knowledge about these topics, but there’s a point when the debate degenerates into desperate attempts at justification, or even worse, absurd statements. To me, ideas like “an experienced programmer doesn’t make such trivial mistakes anymore” or “why would you want a compile time error there in the first place?” fall squarely in that category.

My aplogies. I realize those are blunt statements. I’ll rephrase the thought: When someone encounters his first bugs caused by using incorrect types, Hungarian notation looks like an excellent idea. And for that person it can actually help for a while to be reminded of using types correctly. But it complicates things for other people in a team who learned to be aware of these problems and deal with them without artificial rules. They need to learn a new cryptic code, spend time applying it correctly, uglifying their code, and not getting any real benefit from it. After a while, the person who experienced his first type bugs makes far less mistakes, finds them trivial to debug, and has far worse logic bugs to deal with where no change in notation could ever help. The fact that he makes less mistakes with types can hardly be attributed to Hungarian notation, he just learned to be aware of them and is more careful when he encounters similar situations. The rest of the time, Hungarian notation is noise for him as well, but he’ll probably still advise his team members to use it because it once helped him and might help them as well. While in fact it’s more likely that newcomers will go though a phase where they make type errors as well, Hungarian notation or not.

It’s almost exactly the same with the use of ‘m_’. Everybody makes member vs. local vs. argument variable bugs at some point. And then some people will use whatever means necessary to prevent those bugs. But the fact of the matter is that you just can’t prevent them at all. You can only learn from your mistakes and become more aware of potential bugs. You create a discipline to test these things (both code-wise by looking at the exact declaration, and execution-wise by checking the desired behavior). The use of ‘m_’ just ends up being noise when you have to deal with real logic errors. It might even make people too confident that their code is correct, while testing is the only way to make sure. And ironically many don’t blame the use of ‘m_’ when they do find a bug like this, but instead thinking they should use it more rigorously (causing them to spend/lose more time with unhelpful notation and forcing it upon others).

Now, before anyone jumps at my neck: I’m not claiming that a person who uses Hungarian notation or ‘m_’ is an inexperienced programmer who still has a lot to learn. Programming has many aspects and everybody encounter certain bugs at different times; some while still learning the guts of the language, some after years of experience. But I do believe that the use of ‘m_’ is an overreaction to try to eliminate these bugs while actually after a while most if not all people deal with them by building more awareness, testing more, and looking up the exact declarations. Writing ‘m_’ stays behind like a scar…

860fe478a2545d6c07b88c759292499e
0
SmokingRope 101 Jun 04, 2006 at 13:04

I just went through and cleaned up some of my more recent classes to ensure i had proper naming conventions for all my variables. This included using proper caps/lowercase, fixing some ‘bad’ names and placing prefixes on the code.

I noticed that by having an ‘m_’ in my variable name it was much easier to do a find and replace on the right variable throughout complete source files.

On the other hand conducting a find and replace with a variable name which had not been properly prefixed returned any number of false positives.

*Especially any variables with names less than 3 characters in length*

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 04, 2006 at 14:49

@SmokingRope

I just went through and cleaned up some of my more recent classes to ensure i had proper naming conventions for all my variables. This included using proper caps/lowercase, fixing some ‘bad’ names and placing prefixes on the code.

I noticed that by having an ‘m_’ in my variable name it was much easier to do a find and replace on the right variable throughout complete source files.

On the other hand conducting a find and replace with a variable name which had not been properly prefixed returned any number of false positives.

*Especially any variables with names less than 3 characters in length*

Great, so would you use fully qualified names from now on to simplify that particular situation even more?

namespace X
{
    class Y
    {
        void X::Y::a()
        {
            X::Y::x = 0;
        }

        int X::Y::x;
    };
}

Now you can search/replace anything with almost no risk of screwing things up. Woot! :w00t: Or maybe we can go back to C or even assembly and make every variable global so it has to be unique…

Seriously now, that’s a very far-fetched ‘advantage’ of using ‘m_’. If you used more meaningful names from the start you would have never needed it. Davepermen’s suggestions could be very useful. Granted, I too have to refactor names once in a while and have to locate its uses, but it’s definitely not worth it to uglify my names with a prefix. The whole purpose of the refactoring was to prettify them. This situation should be a lesson to take some extra time to come up with meaningful names, not to keep using ‘m_’.

In Visual C# 2005, there’s even a Refactor menu, where you can just select a name, rename it, and all its uses change with it without any risk. That’s the direction we’re heading and should keep heading. :worthy:

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 04, 2006 at 15:19

My ´m_´ convention is inspired by McConnells book ´Code Complete´, where it is given as an example of a naming convention. I guess everybody agrees that there should always be a global naming convention. The problem I see with not naming a varible after it´s scope is that I read C++ code fast and I hate having to stop reading the source code whenever the scope is not clear (that includes looking three lines up to look for the declaration).

This could ofcourse be helped with a coloring scheme, but I don´t really believe in the idea of writing code for IDE´s. I have to admit that your (Nicks) reasons for not liking ´m_´is very little convincing. The variables role should be reflected in its name, and using ´m_´seems like a nice convention. I only use m_´s in classes though. I have a few structs spread around that mainly hold data. These do not use the m_ convention.

860fe478a2545d6c07b88c759292499e
0
SmokingRope 101 Jun 04, 2006 at 16:34

@Nick

Now you can search/replace anything with almost no risk of screwing things up.

That’s a very important point right there.

6b7e1a4b42e4b47d92fdef8bf2bd8e2c
0
Jare 101 Jun 04, 2006 at 19:36

@Nick

I’m sorry if you got bored.

I said these threads only end when people get bored. The fact that I’m answering in this thread indicates precisely that I’m NOT. Yet. ;)@Nick

which rely too much on peripheral or circumstantial details?

The usual example: “m_” adds a much larger amount of noise/signal to a member named “x” than to a member named “InternalUnicodeCharacterMap”. That’s why sweeping generalizations such as “m_ adds noise” are not useful facts when establishing comparisons and analyzing tradeoffs.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 04, 2006 at 20:53

@SigKILL

The problem I see with not naming a varible after it´s scope is that I read C++ code fast and I hate having to stop reading the source code whenever the scope is not clear (that includes looking three lines up to look for the declaration).

I take it you use Hungarian notation as well then so you can read non-stop? :surrender

And I like to read code reasonably fast as well. That’s exactly why I avoid adding any kind of cryptic prefix that repeats itself over and over again. I typically also remember what I read three lines up…

This could ofcourse be helped with a coloring scheme, but I don´t really believe in the idea of writing code for IDE´s.

If you don’t uglify your code with prefixes the reader is free to do what he likes. That can be hovering the mouse over variables only when necessary, arranging the header and source file in two columns, looking at arguments and local variables, or indeed a coloring scheme. Everybody can read it without decrypting, and it’s more likely to focus on elegance (e.g. davepermen’s approach). So it’s not relying on IDE features per se, but it is 2006 and they are available for everyone.

If you do add prefixes, you force your preference upon others. It’s utterly useless when combined with the way I like to read code. And I don’t want to learn your habits and everybody else’s Hungarian dialect. My code, just like davepermen’s, expresses exactly what is intended, so nobody can really have a problem with it.

By the way, if you don’t believe in writing code for IDE’s, can I ask what source control you use? Or do you prefer keeping all the old code in the source files as well? See, it’s for the better that we do rely on some tools to be available one way or another, to improve code/coding quality… It’s indeed a bad idea to code for one specific IDE, because that would again force your preference upon others, but you don’t have to deny the existence of coding assistance completely. There are sufficient ways to determine a variable’s scope (and type) efficiently without mutilating the actual code.

The variables role should be reflected in its name…

Absolutely, but whether or not it’s a member variable is of little importance to its role. Consider this situation: You have a long function and you wish to split it up. There will no doubt be variables that need to be available in each part, so you have the option of either storing them as class members or passing them as function arguments. They are stored somewhere else, but the code is still perfectly equivalent, and the roles of variables hasn’t changed whatsoever. Reversely, you can also merge functions when you see their functionality isn’t needed separately, and you can make some member variables local. So exactly in what form a variable appears is quite irrelevant to the logic, the stuff that really matters.

newX, otherX, globalX, tempX, etc, these are useful to understanding the code.

I only use m_´s in classes though. I have a few structs spread around that mainly hold data. These do not use the m_ convention.

And you expect the readers of your code to adhere to this exception instantly? What makes a struct so different from a class? Do you expect people to constantly check whether they’re working with a struct or a class? It’s another perfect example of misinformation. Thank you for that.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 04, 2006 at 21:24

@SmokingRope

That’s a very important point right there.

What point? I hope you realize I was being sarcastic. The risk of screwing things up with search/replace is no better with ‘m_’ appended.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 04, 2006 at 22:03

@Jare

The usual example: “m_” adds a much larger amount of noise/signal to a member named “x” than to a member named “InternalUnicodeCharacterMap”. That’s why sweeping generalizations such as “m_ adds noise” are not useful facts when establishing comparisons and analyzing tradeoffs.

An adult with a penis on his forehead isn’t better off than a baby with a penis on its forehead even if it does help determine the gender. :rolleyes:

Anyway, by your logic you should make every name as long as possible to minimize the noise part. Or, since you admit it does add a lot of noise at least to short variable names, the argument could also be used to justify omitting ‘m_’. But that breaks consistency and makes it unreliable. So either way you twist it, you end up with noise.

The alternative is pure elegance. Give variables the names you really want to give it, without warts (or penises). Use what works best for the situation and clarifying the logic: x, newX, nextElement, internalUnicodeCharacterMap…

6ad5f8c742f1e8ec61000e2b0900fc76
0
davepermen 101 Jun 05, 2006 at 00:03

m_ doesn’t help to describe what a variables purpose and use is. it does only define where it’s stored.. and this should not be needed, just as it should not be needed in the name what type a variable is (hungarian notation).

this is the compilers job to determine wether something is used the right or wrong way, and the ide’s job to realtime detect and red-underline it.

and instead of renaming by search-replace, you should rename by help of a refactoring-tool in the ide, that actually renames only your variable, not the string that has the same name of your variable.
at least in vc# 2005 ee, this works great :D

oh, and, tahnks nick, to understand what i wanted to say :D

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 05, 2006 at 09:32

I´m sort of hoping that you´re kidding, Nick. The purpose of a coding convention is to avoid a number of local deciscions by making (a few) global decisions. I expect anyone that work with my personal code to adapt to my coding conventions (which can be described in less than a page). A programmer has to adapt to new coding conventions every time he work on a different project/team/firm (depending on company policy), so I´m not sure what your point is. I´ve worked at one company where there was no m_ convention, and this really got to be a problem at semi-large projects (hovering mouse, looking through headers, looking through that small block of code that declares 6 new variables). Parts of the code was not well written, so it might not be a good example. The only valid argument in your posts (IMO) is that you think prefixes are ugly. I´m not convinced by that since it is obviously a personal preference.

P.S. Programmers are not idiots (I´m not claimin everyone is smart, though ;). There are no problem using the m_ convention for private class members and not it in data-structs. There are no problem not using the m_ prefix in you vector class either. Coding conventions is not absolute. You always have the liberty to do some local quirks as long as it is well documented.

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 05, 2006 at 10:32

@davepermen

m_ doesn’t help to describe what a variables purpose and use is. it does only define where it’s stored.. and this should not be needed, just as it should not be needed in the name what type a variable is (hungarian notation).

this is the compilers job to determine wether something is used the right or wrong way, and the ide’s job to realtime detect and red-underline it.

and instead of renaming by search-replace, you should rename by help of a refactoring-tool in the ide, that actually renames only your variable, not the string that has the same name of your variable.
at least in vc# 2005 ee, this works great :D

oh, and, tahnks nick, to understand what i wanted to say :D

Where it is stored actually help a lot. If I´m unfamiliar with the function updateInternalSystems() in the large SuperTanker class, I can simply read through the function and know (without looking at the header) what the class looks like (actually what the class that is of my interest looks like). It is so easy to not see (or to forget) the float in “float tankVolume = blah,blah,blah;” before the first morning coffee..

If you want it to be the compilers job to determine if something is right or not, you should probably not use C++. I´m not sure how this is an argument against the use of m_. The ´looseness´of C++ allows for quite many tricks that are ackward in many other languages (try making a singleton class in VB5, its icky).

The problem with writing for the IDE is that I might port (atleast parts of) the code to another platform. If I´m able to use one cross-platform IDE that might be fine, but I´m not keen about linking to one specific IDE (there might be a better one out in a few years, or the company that creates it might not exists).

I´m not religous about the use of m_, but I would think good coders (as Nick and permen) is able to see the advantages of a naming convention. It is also an surprise that you have so many arguments against m_, but none that actually matters (except it being ugly).

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 05, 2006 at 11:33

@davepermen

this is the compilers job to determine wether something is used the right or wrong way, and the ide’s job to realtime detect and red-underline it. and instead of renaming by search-replace, you should rename by help of a refactoring-tool in the ide, that actually renames only your variable, not the string that has the same name of your variable.
at least in vc# 2005 ee, this works great :D

I agree Visual C# 2005 is great, and we’ll be able to rely on IDE tools more and more in the future, but it’s a bit wrong to assume that’s the standard yet (especially for other languages). It’s not an argument for using ‘m_’, I’m just saying there are many other ways to determine the scope of variables. My favorite is having the header and source file in two columns. If you have them underlined, that’s awesome, but I’m just pointing out that’s not always available and there are plenty of alternatives.

oh, and, tahnks nick, to understand what i wanted to say :D

You’re welcome. I really love your suggestions and will try to use more of such hints where appropriate. Having unique variable names is a good thing and can be a valuable alternative to ‘this->x’ when it improves elegance.

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 05, 2006 at 13:22
99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 05, 2006 at 14:20

@SigKILL

I´m sort of hoping that you´re kidding, Nick. The purpose of a coding convention is to avoid a number of local deciscions by making (a few) global decisions.

I’m certainly not kidding. I hate being forced to read all different conventions for a variable’s scope and type.

I expect anyone that work with my personal code to adapt to my coding conventions (which can be described in less than a page). A programmer has to adapt to new coding conventions every time he work on a different project/team/firm (depending on company policy)…

That’s manageable when working in the same closed environment for months or years. But it’s a pain when working with code from different projects. Do you write all the conventions on the wall? What happens when you break one?

I don’t have the time to adapt to people’s artificial code conventions. When I see code that uses scope or type prefixes I ignore them, so they are nothing but noise. I just always end up checking the declaration to avoid misinformation. Code without them isn’t littered with redundant information that I’ve already read. It’s generally more lucid.

I´ve worked at one company where there was no m_ convention, and this really got to be a problem at semi-large projects (hovering mouse, looking through headers, looking through that small block of code that declares 6 new variables). Parts of the code was not well written, so it might not be a good example.

There you go. Using ‘m_’ wouldn’t have improved it one bit. It’s badly written code and making it adhere to some artificial convention doesn’t make it any better.

Too often I see scope and type prefixes being used as an excuse for not using more informative variable names. When I read ‘m_pszString’ it tells me jack shit. When I read ‘fileName’ I know exactly what it’s for (with a bit of context of course). I don’t really care if it’s null-terminated string or an std::string, next week it might be something different and still have the same role. But I do want it to be clear from the variable’s name what that role is.

The only valid argument in your posts (IMO) is that you think prefixes are ugly. I´m not convinced by that since it is obviously a personal preference.

Wait a second. You agree it’s a valid argument that it’s ugly. But then you change that to being a personal preference “obviously”. Once again let me ask you: Do you use Hungarian notation? Why (not)?

It’s an ugly wart any way you look at it. It’s some cryptic character(s) with an underscore. It’s dangling at the side of the variable name (hopefully one that gives me some real information).

P.S. Programmers are not idiots (I´m not claimin everyone is smart, though ;).

Which is exactly why they don’t need to be reminded of every variable’s scope and type over and over again.

There are no problem using the m_ convention for private class members and not it in data-structs. There are no problem not using the m_ prefix in you vector class either. Coding conventions is not absolute. You always have the liberty to do some local quirks as long as it is well documented.

I think it’s a major flaw. If you want to adhere to a convention, do it right or it becomes misinformation. If I was to adopt the convention and I don’t see ‘m_’ I want to be sure it’s not a member. With your variation I can never be sure and have to check the declaration anyway to see if it’s a struct’s member. I would end up just ignoring it and it would be nothing but ugly noise. And it can get worse. What if you decided to make a class a struct or a struct a class? Are you sure that removing ‘m_’ doesn’t break anything, or you’re adding ‘m_’ to the right variables? You can easily get confused by your own code. Even when structs are treated equally, you can never guarantee that it’s always correct. With bramz’s approach you can even have different conventions in a single project. That’s all misinformation leading to confusion and actually ignoring them all. But then it’s already too late and you’re pretty much stuck with it for the rest of the project.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 05, 2006 at 15:03

@SigKILL

It is so easy to not see (or to forget) the float in “float tankVolume = blah,blah,blah;” before the first morning coffee..

But you wouldn’t miss prefixes? Take it as a friend’s advice: Drink some coffee before leaving for work. Take your time to read the header file, it’s there for a reason and contains lots of other useful information. It’s very important to have an overview of things so you don’t feel like you’re in a maze of code. I know countless situations where a person thought he had fixed a bug but actually wrote a dirty hack or coincidentally avoided the bug, while breaking the design and/or introducing new bugs.

It is also an surprise that you have so many arguments against m_, but none that actually matters (except it being ugly).

Again, do you use Hungarian notation? Its ugliness is the main reason why people avoid it when they can (to me the only valid situation for using it is in a typeless language). After all why would anyone make his code ugly? It’s a very important argument, or we wouldn’t have this many discussions about style.

Besides, people who prefer a prefix don’t have a real problem reading code without prefixes (but can have problems with other people’s dialects), while people who avoid prefixes do get annoyed by the ugliness.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 05, 2006 at 15:48

@SigKILL

Some thoughts about this in C#

http://blogs.msdn.com/rickhos/archive/2004/07/09/178816.aspx

Nice discussion, thanks!

I believe the most important thing is to give it a serious thought. When working in a closed environment and the code won’t be used outside the team and ever member agrees, then sure, use scope prefixes and stick to it if that’s what you really prefer. But when the code is going to be read and written by inside and outside people I think it’s best to avoid any discussion and not adhere to a convention. Just let everybody deal with how to determine a variable’s scope their own way. It can also motivate them to think a little longer about variable names that are clear for everyone, and make them spend more time in header files so they get a better understanding of the design.

Anyway, my favorite quotes from that blog:

  • Full Hungarian notation: Avoid this like the plague.
  • Underscore notation: Visible to the point of distraction. I feel if I need the hint in the first place, then perhaps there should be more encapsulation or fewer locals occurring in the code.
  • Semi-Hungarian notation: If your classes have so many member / local interactions that you absolutely need a system for separation to keep things straight, it may be an indication of design issues. Often, re-evaluating encapsulation, class hierarchy, and interface will give you more manageable code than simply using prefixed names as a band-aid. I have used them myself, and I’ve found the biggest challenge is sticking with the scheme once I’ve started using it. If I have a few member variables that I’m using one time each in two member functions, it’s exceedingly easy to get lazy and not follow my own naming convention. Suddenly my code is that much less readable for having used the convention in the first place.
  • No prefixes: I am comfortable with this style because it helps me to think critically about my own data localization. Used correctly, this is the most elegant solution, but can also lead to the most problems when dealing with many developers with a range of development experience.

He’s right about that last thing. It can lead to some problems with developers with a ‘different’ experience. But I highly doubt that using prefixes is the right solution (as also indicated by the previous points). They’ll have some problems for a while with or without them, and you’d annoy everybody else with the ‘training wheels’ for the rest of the project. In my opinion it’s best to help them become aware of potential problems, learn how to debug and test them, and how to write clear code and read other people’s code fluently using the available tools.

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 05, 2006 at 15:49

The main reason for not using hungarian notation is that the data type should be abstracted away. Other reasons includes that it combines meaning with representation and encourage uninformative names (like the well-known hwnd). However, the scope matters. I´m willing to sacrifice beauty over functionality any day (to a certain extent), and I don´t agree that the m_´s are ugly; I only said it was a valid argument. If I could trust every programmer to give variables a name such that the scope is obvious I would never consider the m_ convention. I have every reason to believe that a ´good´ name for a class member might sound like a good name for a local variable for another programmer . You can´t fail the name ´m_tankVolume´, it´s the class member that represents the tank volume.

I´m sort of confused: do you dislike coding conventions in general? and I´m not seeing how your other arguments is in disfavor of the m_ convention (I might have missed something?). Working on a few big projects I have to say strict coding conventions is a must (along with refactoring). It really helps you being able to get to know new parts of the code fast. If someone breaks the conventions in a non-obvious way, it is managment problem (you should have code review). You should always adapt to companys coding conventions. I´ve heard several stories about people being fired because they are not able/willing to adapt.

I´ve never had any problem turning data structs over to classes. You would have direct access to my data structs member variables, while you access class members through functions. Data structs have at most constructors and destructor and no member functions.

EDIT: Oops, this is reffering to your 04:03 post.

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 05, 2006 at 17:20

@Nick

… In my opinion it’s best to help them become aware of potential problems, learn how to debug and test them, and how to write clear code and read other people’s code fluently using the available tools.

I´m sure this have been tried multiple times, but after a few employers have been through the firm (maybe some summer interns) I would guess that I atleast would rather give them a code convention paper and spend my time doing other stuff. One of the reasons I like the m_ convention is that it feels ´heavier´to do “m_myVariable = something;”, than “myVariable = something;”. It sort of reflect that you change something outside of the current scope, while local variables feels lighter to work with. When working with multiple threads it always makes me stop to think if I should have locked a mutex or something before doing this. I do agree that the ´heavines´ seems a little off-beat on lightwheight classes, but I´m willing to sacrifice that…

860fe478a2545d6c07b88c759292499e
0
SmokingRope 101 Jun 05, 2006 at 17:36

Having a prefix convention helps solve any number of ‘coders block’ problems. While writing your code you know you need to use the prefix so you spit that out right away, then because it specifies what scope the variable is, you can more clearly declare the statement which affects that variable. Because the variable prefix describes the scope it also helps describe the context of the function/method clearly.

6b7e1a4b42e4b47d92fdef8bf2bd8e2c
0
Jare 101 Jun 05, 2006 at 18:06

@SigKILL

Parts of the code was not well written, so it might not be a good example.

Examples are no substitute for reality, no matter how good they are. Unless you actually want to avoid facing reality.

25bbd22b0b17f557748f601922880554
0
bramz 101 Jun 05, 2006 at 18:46

@Nick

I don’t have the time to adapt to people’s artificial code conventions. When I see code that uses scope or type prefixes I ignore them, so they are nothing but noise. I just always end up checking the declaration to avoid misinformation. Code without them isn’t littered with redundant information that I’ve already read. It’s generally more lucid.

Quite funny that a few pages back you found it sooo horrible that our codebase has code in several styles. Apparently, it’s was sooo difficult to adapt. That’s not longer an issue anymore? Way to go, Nick!

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 05, 2006 at 18:57

@Jare

Examples are no substitute for reality, no matter how good they are. Unless you actually want to avoid facing reality.

:blink: Good examples are supposed to illustrate reality. If you avoid facing reality then reality will face you, and your example from reality will become a non-example in mind. :blink:

6b7e1a4b42e4b47d92fdef8bf2bd8e2c
0
Jare 101 Jun 05, 2006 at 19:35

Well, bad codebases are a reality, why wouldn’t they serve as a good example?

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 05, 2006 at 20:43

@SigKILL

The main reason for not using hungarian notation is that the data type should be abstracted away.

The location of a variable should be abstracted away as well. Like I illustrated before, variables can change scope without changing roles, especially during refactoring, exactly like they can change type. I don’t see why you treat scope and type prefixes differently. I believe the number of bugs caused by scope erros and type errors is pretty equal. And I need to know the types of variables more often (it’s easier to remember whether it’s a member

I´m sort of confused: do you dislike coding conventions in general?

No, but I dislike coding conventions that are ugly, leave no room for elegance, and can create misinformation. CamelCase is a useful style convention but it would be perfectly acceptable not to use it when there’s a more elegant solution for a certain situation. And I’m quite picky about parenthesis placement and indentation but I once wrote code like this (names are symbolic):

if(flags & FLAG1) doA();
if(state > 0) {
if(flags & FLAG2) doB();
if(state > 0) {
if(flags & FLAG3) doC();
if(state > 0) {
if(flags & FLAG4) doD();
if(state > 0) {
if(flags & FLAG5) doE();
}}}}

This becomes an ugly ‘staircase’ when using general parenthesis and indentation rules (there are actually more stages in my code and the real variable names make it very clear what it does). So even though the convention is intended to improve elegance I had to deviate from it to get good code elegance. Just like with CamelCase this never causes misinformation.

Rules like ‘m_’ on the other hand are only meaningful when applied very strictly. You’re relying on human hands to keep it consistent, and it becomes misinformation when you break it (intentional or unintentional). So you don’t have any freedom. It also uglifies code instead of improving elegance.

The only option to keep things consistent is to back away from a strict convention that forces you to do a ‘mechanical’ task. You can either read the correct variable scope in the header file or use code assistance to do the ‘mechanical’ task correctly.

It really helps you being able to get to know new parts of the code fast.

I beg to differ. This is the second time you’ve used the word “fast” in this context, and it makes my skin creep. It is truely impossible to get to know code fast. Like I said before you end up writing bugs and breaking the design. You really have to study the headers to get to know the code. Just reading the functions, with scope hints or not, is largely insufficient. Personally I would never risk touching a class’s code without mastering its design and keeping the header file right next to the source file or using other assistance.

If someone breaks the conventions in a non-obvious way, it is managment problem (you should have code review). You should always adapt to companys coding conventions. I´ve heard several stories about people being fired because they are not able/willing to adapt.

Every project needs guideline conventions, and people should adapt to them naturally.

If you make your rules too strict, you end up firing the most skilled team members who know how to think for themselves.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 05, 2006 at 22:05

@SigKILL

I´m sure this have been tried multiple times, but after a few employers have been through the firm (maybe some summer interns) I would guess that I atleast would rather give them a code convention paper and spend my time doing other stuff.

That’s just horrible. I perfer to help my collegues and discuss coding aspects so we all learn from it. And it saves me work because they know a large part of what I know and can help me out just like I help them out. On top of that everybody has his own expertise and I adhere as much to their decisions as they adhere to mine. Sometimes we have to work out a compromise but in the end everybody agrees. Two are smarter than one, three are smarter than two, etc.

And speaking about summer interns: When I was interning at NVIDIA there was another intern who in one day fixed a bug which a team had been struggling with for over a week. So never underestimate people. If you treat them like equals they can and will teach you a few tricks as well.

One of the reasons I like the m_ convention is that it feels ´heavier´to do “m_myVariable = something;”, than “myVariable = something;”. It sort of reflect that you change something outside of the current scope, while local variables feels lighter to work with.

That doesn’t work in the following situations:

class ABC
{
public:
    int a;
    int b;
    int c;
};

class XYZ
{
    void alpha()
    {
        ABC abc;

        abc.a = 1;   // Member variable used merely as local variable

        int &secondElement = buffer[1];

        secondElement = 2;   // Making a 'heavy' change through a local variable
    }

    int buffer[10];
};

A realistic situation is for example a wrapper class for a Direct3D vertex buffer. The wrapper class has the vertex buffer (pointer) as a member variable. But to fill the vertex buffer you need to lock it and retrieve a pointer. That’s a local variable to do ‘heavy’ changes to the class state.

Anyway, there’s no reason to be more careful with member variables, or be less careful with local variables. It’s equally likely to cause a bug with either. After all local variables get assigned to member variables and vice versa.

Lastly, functions don’t tell you with a prefix whether they change any member variable. SetFontType might change a member variable or a global variable or a singleton’s member variable or call a Win32 function. Nobody adds ‘m_’ to an accessor function.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 05, 2006 at 22:23

@bramz

Quite funny that a few pages back you found it sooo horrible that our codebase has code in several styles. Apparently, it’s was sooo difficult to adapt. That’s not longer an issue anymore? Way to go, Nick!

It’s definitely still the exact same issue. Noise. It’s not because I ignore the prefixes that I don’t care they’re there. It takes effort to ignore them. To quote the blog SigKILL linked to again: “Visible to the point of distraction”, “…it’s exceedingly easy to get lazy and not follow my own naming convention. Suddenly my code is that much less readable for having used the convention in the first place”.

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 06, 2006 at 09:50

Nick: I start wondering if you have ever read a book on software construction. Good books include “The mythical man month”, “Large Scale C++ Software design” and “Code complete”. I´m very confused since your arguments doesn´t really make sense to me (or are really bad).

No one wants divas on their team, and I´m not seeing how a good programmer will have any problem adapting to strict coding conventions (and still be able to do a good job). It takes less time adapting to coding conventions than arguing why they are not good. And you work for a company, which owns the code you write so you better make it to their specification.

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 06, 2006 at 13:41

@SigKILL

Nick: I start wondering if you have ever read a book on software construction. Good books include “The mythical man month”, “Large Scale C++ Software design” and “Code complete”. I´m very confused since your arguments doesn´t really make sense to me (or are really bad).

They do to a lot of people, if not the vast majority. The use of scope prefixes is not advised by Java and C#. The arguments are almost identical to those for not using Hungarian notation, which ironically do seem to make sense to you. Also, the blog you linked to contains much of the same arguments I’ve been using. Which makes me wonder why ‘my’ arguments really don’t make sense to you (or are really bad).

In ‘The Mythical Man Month’ you might want to read about accidental complexity and essential complexity. The use of ‘m_’ falls squarely under accidental complexity. Also good reads are ‘Refactoring to Patterns’ and ‘Software Architecture in Practice’.

It takes less time adapting to coding conventions than arguing why they are not good. And you work for a company, which owns the code you write so you better make it to their specification.

This way you avoid all discussion. You dislike Hungarian notation but ‘m_’ is not worth arguing about? If a company wants you to use Hungarian notation wouldn’t you express any disagreement? I’m not saying you should break the conventions, heck I’d use ‘m_’ if I had to, but that has nothing to do with whether they are actually a good thing or a bad thing.

6ad5f8c742f1e8ec61000e2b0900fc76
0
davepermen 101 Jun 06, 2006 at 16:48

i don’t get why anyone would have to look into the header..? you only have to look at the function.. then you can see wich ones are parameters, wich one are function-local, and wich are (the rest) class-members..

of course, there are ‘globals’.. but we all know we shouldn’t use them, right? :D (and thus, when you need to use one, put it into a namespace, or use the ::GlobalAccessor)

SigKILL, you state there is no argument that makes sence made by me.. but there is.. the same as for hungarian: you don’t need type information, it should be abstracted away. the NAME of the variable should explain it’s usage (and thus, it’s theoretical type..)

the same is for locality.. a variables name should explain as well, where it belongs to. myVariable and m_Variable will by a big chance be the same, but myVariable is more readable.. m_, what’s that? my is a word everyone can understand..

myValue = newValue;
myValue = otherValue;

and this can even build up to more complex things like threadLocalContainer and stuff (where there is no simple m_ helping out).

it abstracts away the scope of a variable, wich should not be explicitely specified, just as the type shouldn’t.

wether you build up some strange naming system like m_, p_, l_, g_, or something else, to find some general tokens, or you rather use your brain and think about what the value really is (this is a newValue (most parameters in constructors have that name), this is an otherValue (copy constructor), this is the originalValue.. etc..

4e70f904a74bd2aa8773733b25b77d41
0
SigKILL 101 Jun 06, 2006 at 18:05

Nick: If a company uses hungarian notation I would use it without argument. There is the discussion of good vs. bad coding conventions, and there is an discussion wheter to adapt to coding conventions or not. You should always adapt to coding conventions without argument (even if you might disagree with them). I thought I made that clear.

I´ve never heard anyone (except you) claiming that ugliness is the main argument against hungarian notation. See my previous posts why I don´t like hungarian notation.

I have a hard time convincing myself that scope should be abstracted away. All projects I have worked with the last 3 or 4 years have been multithreaded and changing a local variable vs. a member variable do make a huge difference. You could put enough mutexes around such that you´re always able to change things safely, but I have to be careful about which threads are locked. Anyways, when changing the scope of the variable adding/removing a prefix is the least of your problems. Just like your example when splitting functions you would read through the functions to make sure you haven´t broken some logic anyways. And typically in my experience; making a local variable to a member variable will change its role, since a local variable represent local (typically temporary) data/states, while member variables represent non-local class data (typically class states).

When it comes to Java, the Sun recommendation is to use PascalCase for member variables and camelCase for local variables (see http://java.sun.com/docs/codeconv/ ). I´m not familiar with C# conventions.

If you think that getting to know new code fast is impossible, you should try using strict coding conventions. It actually helps clearifying the logic (which is what matters IMO) when everything conforms to the same set of rules.

860fe478a2545d6c07b88c759292499e
0
SmokingRope 101 Jun 06, 2006 at 18:17

@davepermen

wether you build up some strange naming system like m_, p_, l_, g_

Don’t forget:

mt_ for class template paramter
ft_ for function/method template parameter

87e614b8b888bb2c4485c1ac16d8c779
0
moe 101 Jun 06, 2006 at 18:20

I have tried so hard not to answer to this thread but apparently I failed…

m_, what’s that?

(realising you were ironic) In my head “m_” stands for member. Hence it indicates a member variable. If I say “my”, it is as if it belongs to me but that can’t be right. It belongs to the class. So, I personally don’t like it if the “m_” is missing and I dame sure hate “my”. The same goes for the type. I prefer if it is there.

In fact I prefer if you go from general to special much like in inheritance. Therefor, I have names like “m_iNumTriangles”. As you see I also stress the importance to have an accurate name. But in addition to the prefix and the type.

In my opinion It take too much time if I need to hover the mouse over the variable or if I need to check the headers just to get the scope or the type. Even so it’s not actually long :lol:

Anyway, I would dare to say in the end everything is just another naming convention. Even leave the scope and the type asside is just another convention. In other words: You can’t argue about taste… And in my opinion that’s the only reason why discussions about naming conventions won’t die. There is no solution. There are just opinions. So, no offence to anyone.:lol:

99f6aeec9715bb034bba93ba2a7eb360
0
Nick 102 Jun 07, 2006 at 15:43

@moe

m_iNumTriangles

Gee, I wouldn’t have guessed ‘numTriangles’ was an integer… :rolleyes: And when working in some kind of Mesh class it doesn’t take a genious to determine that it’s a member variable. No offence really.

Even if I do have to check the header file, I only have to do it once. A prefix distracts me each and every time I read that variable. And it’s not just annoying to read. That example requires 5 extra key strokes. Considering how little the prefixes are of use, and how cryptic they are (they’re not fluently typed English words), that’s a lot. Don’t overengineer naming conventions. With all the variations people invent, it’s just much nicer not to use them at all and leave it up to the reader to determine scope and type, without risk of misinformation. I’m fine with reading the context and the header, davepermen loves his IDE’s features. Above all we refactor the code when it becomes more complicated than necessary (using more informative names, splitting up big classes and functions, getting rid of accidental complexity, etc). K.I.S.S.

I think I summed it all up in one paragraph, so I’m just going to leave it at this. If you’re forced to use scope and/or type prefixes, fine, use them and keep things consistent. But if you get the choice, at least consider these arguments and try to work without artificial prefixes. That’s all for me. :happy:

87e614b8b888bb2c4485c1ac16d8c779
0
moe 101 Jun 07, 2006 at 16:53

Gee, I wouldn’t have guessed ‘numTriangles’ was an integer…

Ha, you fell into my trap :)
In similar situations the dx-api used DWORD’s so I might have used m_dwNumTriangles for consistency witch you didn’t realize since you’re not used to prefixed. (Or you hate them so much that it prevented you from seeing more.) So even if you do not need the prefix yourself it helps to keep things consistent witch I think is important. Besides if one uses a trivial sample it apparently is not enough. But if you make it more complex everyone shouts out that it doesn’t fit a real live situation any more.

Even if I do have to check the header file, I only have to do it once.

Hmm, I wonder witch one it is… Do you have a photographic memory or do you only work in small source codes… :)
I certainly need to check things more than once. Maybe I am just not smart enough (Hence, I need the prefixes to remember) :)

5 extra key strokes

Since I have my hands on the keyboard it still takes less time than leave the keyboard move the mouse and wait until the tool tip pops up. Then move the mouse aside to see again what’s under it. Or switching into the header…

But if you get the choice, at least consider these arguments and try to work without artificial prefixes.

I did consider your arguments and I think you put quite some thoughts into it. It’s just that I have a different taste. Isn’t it more interesting if not everyone is the same… :)

That’s all for me.

I must have hit at least some soft spot since you give up now :)

No offence really.

None taken and none intended (therefore all the smilies). Anyway, I hope you are not mad at me now.
I agree it’s time to move on. I will desperatly try not to answer to this thread again as well. Or maybe a moderator could close it? After all it did start as something completely different and we are way off topic.