News for hackers. Stuff that matters.
Re:More Dirty Coding Tricks from Game Developers (2010) by bitwize on Sunday August 02, 2015 @05:51PM (#9992630)
'const' in C and C++ is broken. Not only is it like a Chinese word that varies wildly in meaning depending on where you use it and how it is inflected, but in C-family languages, 'const' modifies type, making objects that benefit from the compiler hints 'const' implies type-incompatible with objects that do not. This results in the problem of some know-it-all deciding that a core API needs to be const-correct, and checks in changes making it so, only to find that the entire fucking code base is now broken.

Note that I'm not saying "don't use 'const'" with the above (and I'm CERTAINLY not saying "using '#define const' in your code base is a good idea"); only that 'const' in C-family languages has significant drawbacks which may affect the engineering tradeoffs you make when you decide whether to use it.

By contrast, languages such as Ada have explicit and implicit constantness restrictions ('in' parameters, for instance, cannot be modified), but these do not modify the type of the object, allowing objects with these restrictions to be type-compatible with objects without them.

Re:More Dirty Coding Tricks from Game Developers (2010) by CountSessine on Sunday August 02, 2015 @07:40PM (#9992968)
I don't really understand what you're saying.

'const' in C and C++ is broken. Not only is it like a Chinese word that varies wildly in meaning depending on where you use it and how it is inflected, but in C-family languages, 'const' modifies type, making objects that benefit from the compiler hints 'const' implies type-incompatible with objects that do not.

They're not type-incompatible in any way that doesn't violate those compiler hints in the first place - C and C++ fully support sensible coercion between const and non-const types. What more do you want?

This results in the problem of some know-it-all deciding that a core API needs to be const-correct, and checks in changes making it so, only to find that the entire fucking code base is now broken

Would you rather it compiled and silently broke? If some dingus breaks the build by changing an API without checking in the corresponding code using the API, how is that C/C++'s fault?

By contrast, languages such as Ada have explicit and implicit constantness restrictions ('in' parameters, for instance, cannot be modified), but these do not modify the type of the object, allowing objects with these restrictions to be type-compatible with objects without them.

This is bizarre. Can you take that 'in' parameter and then pass it on to another function as an 'in/out' parameter? If so, then either

1. Ada just made you a copy silently (bad)

2. Ada is broken and 'in' means nothing (worse).

If neither of those are true and an 'in' can't be transitively passed on as an 'in/out', then that's a type - however you want to refer to it, 'in' is then a type with all of the 'broken' type restrictions you're railing against in C/C++.

Re:More Dirty Coding Tricks from Game Developers (2010) by thisisnotatest on Monday August 03, 2015 @02:41AM (#9994152)
const is type-incompatible like this:

Suppose you want to write a function that returns all the nodes in a tree that satisfy some property. In C++ you have to define two different versions (or use templates to make the compiler clone it for you):

  vector<Node*> GetGoodNodes(Node* root);
  vector<const Node*> GetGoodNodes(const Node* root);
If more than one type is involved in the operation, there can be a combinatorial explosion.
Re:More Dirty Coding Tricks from Game Developers (2010) by kybernetyk on Monday August 03, 2015 @04:03AM (#9994357)
Yes, and what's wrong with that? You certainly don't want someone from the outside altering the nodes directly if you have an API which should be used instead.

Whenever I need to return a non-const reference/pointer to some inner data (which is not often) I name the method "mutableFoo()" to make clear what you're getting.

But most of the time (provided a sane API design) you won't have that problem anyway.

Re:More Dirty Coding Tricks from Game Developers (2010) by golergka on Monday August 03, 2015 @02:59AM (#9994195)
I don't feel that I understand purpose of this function yet.

Does this function return data point that it creates itself, or does it retrieve these nodes from somewhere else? If it's the first option, who's in charge of deleting them? If it's a second option, who's in charge of counting references to these objects? Also, if it's a second option, and this data points are retrieved from a certain storage, are you absolutely sure that whoever gets this data should be able to modify them?

Re:More Dirty Coding Tricks from Game Developers (2010) by SamReidHughes on Monday August 03, 2015 @04:45AM (#9994495)
> Does this function return data point that it creates itself, or does it retrieve these nodes from somewhere else?

It returns pointers to the nodes in the tree. You know this because the caller isn't supposed to (or allowed to) delete them, because if the caller was responsible for that, they'd be wrapped in smart pointers.

> If it's a second option, who's in charge of counting references to these objects?

The pointers in the return value are valid as long as their particular descendant of the function parameter isn't deleted. There's no need for reference counts, and if they're present at all, they aren't updated by this function, since the caller isn't responsible for decrementing them. If the caller was responsible, the return value would be a vector of smart pointers.

> Also, if it's a second option, and this data points are retrieved from a certain storage, are you absolutely sure that whoever gets this data should be able to modify them?

If they have a const node *, they shouldn't. If they don't, they should.

Re:More Dirty Coding Tricks from Game Developers (2010) by golergka on Monday August 03, 2015 @05:12AM (#9994593)
Thanks! Your first two answers would be obvious if we assume that we're working with modern codebase written by adequate developers, but that's a very strong assumption to make, so I wanted to be specific.

And your final answer is, well, exactly the point I was trying to steer the conversation to. In other words, if you declare both methods, it means that you're doing something wrong: you're giving away data mutably and immutably at the same time, and it just doesn't make sense.

Re:More Dirty Coding Tricks from Game Developers (2010) by SamReidHughes on Monday August 03, 2015 @05:16AM (#9994609)
You aren't.

If you have a non-const node, you can access its children non-constly _or_ constly (which you could do anyway, since you could make your reference to the node be const at any time). If you have a const node, you can only access its children constly.

This makes perfect sense.

Re:More Dirty Coding Tricks from Game Developers (2010) by golergka on Monday August 03, 2015 @05:57AM (#9994747)
My bad: didn't read the code carefully, thought that these were methods.
Re:More Dirty Coding Tricks from Game Developers (2010) by SamReidHughes on Monday August 03, 2015 @05:45AM (#9994703)
> if we assume that we're working with modern codebase written by adequate developers

Yeah, come to think of it if there's a chance this function came from a pre-C++11 codebase I wouldn't be so sure that the caller wasn't supposed to delete those nodes. Well, it'd be an odd thing for this particular function, I guess, but it's something I've seen or might have done, in general. In that case maybe I'd have had the function take an output parameter instead, in order to give it a scary variable name.

Re:More Dirty Coding Tricks from Game Developers (2010) by bitwize on Monday August 03, 2015 @02:26PM (#9998566)
First of all, Ada may have already made a copy of the value; small (register-sized) values tend to be passed by copy into subprograms.

If 'in' is a type than so is the concept of an lvalue in C and C++ -- because constants (and 'in' parameters which function as constants with local scope) in Ada are not lvalues; they cannot be assigned to by the semantics of the language. (In C and C++, every sense of 'const' can be gotten around; even const methods can mutate object instance variables by const_casting this.) You can call any constraint imposed by the language a type and that may be true in the abstract sense, but what counts when talking about types in a language is what the language's own type system has to say on the matter.

Parameter modes (in, out, in out) form a part of the type of the subprogram (procedure or function) the parameter is a part of, but constantness is not a part of the type of the value in Ada. Note that this is not the only way types differ in Ada than in C++ when it comes to access: C++ types encode information about how a parameter is passed, Ada types do not. The Ada declaration:

    procedure Foo(I : in Integer);
may be equivalent to C++

    void foo(int i);
or

    void foo(const int& i);
depending on how the compiler chooses to pass the values. Note that even 'in out' parameters may be passed by value through a 'pass by copy-in copy-out' mechanism, so whether a parameter is passed by value or reference is largely handled behind the scenes, so the type system doesn't include that information. If it did, Ada would be even more verbose and unwieldy than its reputation suggests, as type enforcement is much more strict in Ada.
Re:More Dirty Coding Tricks from Game Developers (2010) by CountSessine on Monday August 03, 2015 @09:59PM (#10001212)
You can call any constraint imposed by the language a type and that may be true in the abstract sense, but what counts when talking about types in a language is what the language's own type system has to say on the matter

What counts isn't so much what the specification calls a 'type' but rather how the compiler does type reduction - and with all of the compilers I've worked with, argument decorators like 'in' & 'out' are typically handled during type reduction.

depending on how the compiler chooses to pass the values. Note that even 'in out' parameters may be passed by value through a 'pass by copy-in copy-out' mechanism, so whether a parameter is passed by value or reference is largely handled behind the scenes, so the type system doesn't include that information. If it did, Ada would be even more verbose and unwieldy than its reputation suggests, as type enforcement is much more strict in Ada.

Very interesting! I know very little about Ada - other than that it has generally been considered as a safer alternative to C for applications-programming in the aerospace software world.

At the same time, I can say that without the ability to determine the how of how the compiler will pass arguments - by value, by copy, by reverse copy, by reference - I wouldn't consider Ada to be an alternative to C in the systems-programming domain, any more than I would consider Haskell or Javascript to be systems-programming languages. Your original claim, in your words, was that 'const' in C and C++ is broken. C, or any other systems-programming language, simply has more constraints on what const could possibly be. The Ada approach to handling const would simply never work in C with C's implementation guarantees. To pseudo-quote a great man, Dennis Ritchie,

If you want magical argument passing, sometimes resulting in silent and unexpected argument copying, you know where to get it.

Re:More Dirty Coding Tricks from Game Developers (2010) by golergka on Sunday August 02, 2015 @06:57PM (#9992831)
Can you please provide some examples where this really becomes a problem, so I can better understand what you mean?
Re:More Dirty Coding Tricks from Game Developers (2010) by jblow on Sunday August 02, 2015 @07:09PM (#9992874)
Everybody who has tried to use const in even medium-sized C++ codebases is familiar with the behavior discussed here. It's not about specific examples, it is about what happens when you have a lot of code.
Re:More Dirty Coding Tricks from Game Developers (2010) by fsloth on Monday August 03, 2015 @12:33AM (#9993818)
Hmm, I'm not sure if codebase with millions of lines is 'medium' or 'large' but from my experience const is great even there. Of course, modifying existing code to become const correct in interfaces where previously it was not can cascade to a point where a majority of the code needs a rewrite, so I can see situations where adding const to an old interface can cause lots of grief.

But from my experience const really helps in enforcing directed graph constraints on logic and data flow which is great - and forces code to be easier to reason about.

Re:More Dirty Coding Tricks from Game Developers (2010) by Negitivefrags on Sunday August 02, 2015 @08:03PM (#9993042)
I'm someone with a codebase where we practice const correctness and we haven't had a problem with it. We were being const correct from the start so we don't have the problems associated with trying to change that midstream.

Assuming you do it from the start you shouldn't be running in to issues.

Re:More Dirty Coding Tricks from Game Developers (2010) by mark-r on Sunday August 02, 2015 @10:41PM (#9993441)
Exactly right. But the example was of combining two code bases, one of which tried to maintain const correctness and one which had utter disregard for it. If you don't believe in const correctness in the first place, the work of making your code compatible can seem intractable.
Re:More Dirty Coding Tricks from Game Developers (2010) by golergka on Sunday August 02, 2015 @07:19PM (#9992908)
Can you please provide some examples, so I can better understand what you mean?
Re:More Dirty Coding Tricks from Game Developers (2010) by agumonkey on Sunday August 02, 2015 @09:38PM (#9993255)
I'm no C nor Ada expert, but I think he means in C `const` is a data type modifier, whereas in Ada it's a function modifier, making the concerns orthogonal. I'm never happy when I see warning about `const` being lifted by some function in C. I think that's what parent is referring to.
Re:More Dirty Coding Tricks from Game Developers (2010) by trashcan on Sunday August 02, 2015 @07:33PM (#9992946)
If you make a function that accepts an unsigned int, and then you try to pass in a const unsigned int, you will need to either typecast it, make a new function, or change the function to only accept const unsigned ints.

Although it's been a long time since I coded in C/C++, correct me if I'm wrong.

Re:More Dirty Coding Tricks from Game Developers (2010) by StephanTLavavej on Sunday August 02, 2015 @08:00PM (#9993034)
You're incorrect, for C89 through C++17. I'd recommend not making statements about languages you've forgotten.

In the C++ Working Paper, the Standardese is N4527 5.2.2 [expr.call]/4 "When a function is called, each parameter (8.3.5) shall be initialized (8.5, 12.8, 12.1) with its corresponding argument." followed by 8.5 [dcl.init] where /17.8 has a nice example:

"Note: An expression of type "cv1 T" can initialize an object of type "cv2 T" independently of the cv-qualifiers cv1 and cv2. int a; const int b = a; int c = b;"

(A "cv-qualifier" is const or volatile; they behave similarly in many contexts, hence the collective terminology for convenience.)

Re:More Dirty Coding Tricks from Game Developers (2010) by trashcan on Monday August 03, 2015 @12:22PM (#9997307)
I stand corrected, thank you.
Re:More Dirty Coding Tricks from Game Developers (2010) by Joky on Sunday August 02, 2015 @07:48PM (#9993000)
That sounds completely wrong, unless the function takes a reference to the unsigned int.
Re:More Dirty Coding Tricks from Game Developers (2010) by angersock on Sunday August 02, 2015 @07:35PM (#9992952)
Const, in theory, is a fine idea. As implemented in C++ though, it's unwieldy. There's at least three (if memory serves) places you can put it in a member function declaration (not including params).

What's more, it can "infect" any other code that touches it, in turn requiring casting or weird const additions. For a simple rant, check the first few paragraphs here:

http://www.vaxpower.org/~isildur/const.html

Re:More Dirty Coding Tricks from Game Developers (2010) by to3m on Sunday August 02, 2015 @08:08PM (#9993054)
There's also two places you can put "int" in a function declaration, but nobody ever seems to complain about that ;)

I'm not even sure I understand the rant, though I've been a fan of const for years so it's probably automatic by now. So, say you have a class with a const member, and you have to pass it in to a function? Well, that's a bit unusual - const members are pretty rare in my experience. But the underlying problem sounds like: you have a const object, and you want to pass it into a function. There are three possibilities, I suppose:

1. The function takes const T & or const T * , because it doesn't change that argument. So no problem.

2. The function takes T, because it doesn't change that argument (and the object is small and/or the programmer doesn't care about the copying - irrelevant issues here). So no problem.

3. The function takes T & or T * , because it changes that argument. Compilation fails! But - no problem! Because this is what you want. You passed what's supposedly a const object into a function that expected to be able to change it. Obviously compilation has to fail.

So maybe the problem is people declaring parameters as T & or T * , when they meant const T & or const T * ?

I bet if C++ had const by default, this problem would never arise. We'd be striding, right now, arm in arm, towards our glorious const-filled destiny, singing a song about it as we went.

Re:More Dirty Coding Tricks from Game Developers (2010) by angersock on Sunday August 02, 2015 @08:25PM (#9993090)
As I recall isn't there also "const T const &"?
Re:More Dirty Coding Tricks from Game Developers (2010) by to3m on Sunday August 02, 2015 @08:31PM (#9993107)
No, but you can have that with pointers, since the constness of the pointer itself (i.e., whether you can change the address) is separate from the object it points to (i.e., whether it might point into ROM or not). So you can have T * (variable RAM address), T * const (fixed RAM address), const T * (variable ROM/RAM address), and const T * const (fixed ROM/RAM address).

(References, by contrast, can never be reseated. So const T &const doesn't make sense. But... I didn't try this right now to double check, so if it works - though I think it doesn't - don't blame me. Or, if you do, at least allow me to plead extenuating circumstances, in the form of C++.)

Re:More Dirty Coding Tricks from Game Developers (2010) by angersock on Sunday August 02, 2015 @08:54PM (#9993165)
That seems right, I must've swapped that behavior with that of pointers in my head.
Re:More Dirty Coding Tricks from Game Developers (2010) by krapp on Sunday August 02, 2015 @07:57PM (#9993020)
What the author there is calling "infecting" and "mangling" seems to be const doing exactly what it's intended to do.

You can't just declare something a constant then cast it out of being constant later? Of course not, that's the entire point!

Re:More Dirty Coding Tricks from Game Developers (2010) by angersock on Sunday August 02, 2015 @08:08PM (#9993053)
No, see, that's the thing. It's annoying when you want to--and I apologize because it's been several years since I had to deal with this nonsense--copy elements between logically compatible containers but ones whose types are differing in layers of constness. Or if you to, say, move a reference all the way down into a pointer (or vice versa) to interop with C or other legacy code.

Or any of several other things, including some truly odd possibilities using operator and function overloading.

It's just really gross as implemented.

Re:More Dirty Coding Tricks from Game Developers (2010) by CountSessine on Sunday August 02, 2015 @08:32PM (#9993110)
copy elements between logically compatible containers but ones whose types are differing in layers of constness. Or if you to, say, move a reference all the way down into a pointer (or vice versa) to interop with C or other legacy code. Or any of several other things, including some truly odd possibilities using operator and function overloading.

And this is 'const''s fault? Others have asked - can you provide an example? Because what you're describing sounds like it's going to be a hot mess, const or no const.

I don't really think that const can make bad data representation any worse than it already is.

Re:More Dirty Coding Tricks from Game Developers (2010) by cmma on Sunday August 02, 2015 @11:03PM (#9993503)
It sounds like you wanted to do something like this:

    std::vector<char*> vec1(...);
    std::vector<char const*> vec2(...);
    std::copy(vec1.begin(), vec1.end(), vec2.begin()); // works (1)
    std::copy(vec2.begin(), vec2.end(), vec1.begin()); // fails (2)
If this compiled, the second example would invoke undefined behavior and crash if you attempted to write to an element that pointed to read-only memory (e.g., a string literal).

Container element types are almost never declared const unless their values are truly immutable (in this case the pointer is mutable, but the underlying memory is not, which is kind of strange).

Re:More Dirty Coding Tricks from Game Developers (2010) by cLeEOGPw on Monday August 03, 2015 @03:13AM (#9994231)
I think he just meant that: void foo(std::vector<char const* > &vec2) { ... }

    ...
    
    std::vector<char*> vec1(...);
    foo(vec1); // fails
    
The idea is that you should be allowed to pass non-const vector to const function who accepts same vector (const or not const) with const variables. Because the function foo is like saying "give me vector, I will not modify it's elements", and with current C++ standard this is not allowed.
Re:More Dirty Coding Tricks from Game Developers (2010) by cmma on Monday August 03, 2015 @07:52AM (#9995078)
In that case, the question should be, why am I attempting to convert one concrete type to another concrete type?

If you're writing a program, you should use the same type, std::vector<char* >, everywhere.

If you're writing a library, the API should avoid including container details in function parameters, and const and non-const T should be allowed.

    template<typename Container>
    void foo1(Container const& c);

    template<typename Iterator>
    void foo2(Iterator first);

    template<typename Iterator>
    void foo3(Iterator first, Iterator last);

    template<typename Iterator>
    void foo4(Iterator first, std::size_t num);

    template<typename T>
    void foo5(std::vector<T> const& vec);

    void foo6(char const* const* first, std::size_t num);
foo6 is a pretty good alternative here, imo:

    std::vector<char*> vec(...);
    foo6(&vec.front(), vec.size());
It would be cool if the compiler could figure templated type conversion out, but the crux of the issue is, as I understand it, that T<A> and T<A const> are not necessarily implemented the same way.

Also note that std::vector<std::string const> won't compile -- it wouldn't be copy-assignable -- so these issues mostly seem to arise specifically when dealing with C strings and/or C compatibility. And reinterpret_cast is amazingly helpful for porting from C.

Re:More Dirty Coding Tricks from Game Developers (2010) by to3m on Monday August 03, 2015 @09:03AM (#9995409)
Even if you ignore the way that the types of template instantiations are (for good or for ill) unrelated, these two types are not compatible. Say this particular conversion were permitted. You have your function. (String literals are const char * .)

    void blah(vector<const char * > &xs) {
        xs.push_back("blah");
    }
And you have the code calling it:

    vector<char * > xs;
    blah(xs);
And that would not be valid. The rationale for the conversion rules for pointers to pointers is based on a similar sort of problem. (In fact I think it's exactly the same problem, at any level, but that only just occurred to me, so perhaps not.)

(This isn't to say there aren't other similar sorts of conversion that would be safe, and that the language perhaps should support, just that this isn't one of the valid ones.)

Re:More Dirty Coding Tricks from Game Developers (2010) by golergka on Monday August 03, 2015 @03:38AM (#9994283)
But that's exactly what is const is created for — preventing you from doing that. Why would you want to break the safeguards somebody has deliberately put in place?
Re:More Dirty Coding Tricks from Game Developers (2010) by Gibbon1 on Monday August 03, 2015 @01:03AM (#9993918)
You are arguing with the Java People(tm), you cannot win this.

Also: http://yosefk.com/c++fqa/const.html

Re:More Dirty Coding Tricks from Game Developers (2010) by Joky on Sunday August 02, 2015 @07:47PM (#9992997)
Looks like someone who does not even understand C++ in the first place...
Re:More Dirty Coding Tricks from Game Developers (2010) by jschwartzi on Monday August 03, 2015 @02:03AM (#9994079)
If you're complaining about const functions, as in "int foo(void) const;," it helps to think of it as declaring that the implicit "this" pointer being passed into the function as its first argument is being cast to type "FooType const * " rather than "FooType * ." The reason it has to go at the end of the function declaration is that member functions always have an implicit first argument unless they are static. This is also why you can't declare free functions as const functions. They don't have a "this" pointer with associated fields to manipulate.
Re:More Dirty Coding Tricks from Game Developers (2010) by lisivka on Sunday August 02, 2015 @10:46PM (#9993456)
> but in C-family languages, 'const' modifies type, making objects that benefit from the compiler hints 'const' implies type-incompatible with objects that do not.

It was fixed years ago. Now const behaves properly in modern C compilers.

Re:More Dirty Coding Tricks from Game Developers (2010) by TwoBit on Monday August 03, 2015 @03:51AM (#9994320)
Dude you are clueless. I hope you aren't in the position of making technical decisions for any major C/C++ projects.
Re:More Dirty Coding Tricks from Game Developers (2010) by chimeracoder on Sunday August 02, 2015 @06:20PM (#9992711)
> only that 'const' in C-family languages has significant drawbacks

AFAIK this is pretty much limited to C and C++. Many (and I am willing to venture most, or at least the most-used) C-family languages that aren't C/C++ don't suffer this issue. Go and Javascript, for example, both use "const" in a way that doesn't modify the type of the underlying object.

Re:More Dirty Coding Tricks from Game Developers (2010) by golergka on Sunday August 02, 2015 @07:20PM (#9992911)
I think that the scope of this discussion is limited to C/C++. If a programmer doesn't like immutability as a broad concept, he is clearly an incompetent imbecile (and I'm trying to write that as polite as possible, given the severity of the issue).
Re:More Dirty Coding Tricks from Game Developers (2010) by bitwize on Sunday August 02, 2015 @07:16PM (#9992900)
"C-family languages" here means C, C++, Objective-C and D -- not any of the "look-like-C-but-have-completely-different-semantics" languages, or Go which is probably closer to proposed C replacement Alef than to C itself.