Hacker News new | past | comments | ask | show | jobs | submit login

What's the best way to deal with "transitive const-ness", i.e. utility functions that operate on pointers and where the return type should technically get const from the argument?

(strchr is the most obvious, but in general most search/lookup type functions are like this...)

Add to clarify: the current prototype for strchr is

  char *strchr(const char *s, int c);
Which just drops the "const", so you might end up writing to read-only memory without any warning. Ideally there'd be something like:

  maybe_const_out char *strchr(maybe_const_in char *s, int c);
So the return value gets const from the input argument. Maybe this can be done with _Generic? That kinda seems like the "cannonball at sparrows" approach though :/ (Also you'd need to change the official strchr() definition...)



Speaking as someone who is not in the committee but has observed trends since 2003 or so, I would say that solving this problem is way beyond the scope of evolutions that will make it in C2a or even the next one.

There are plenty of programing languages that distinguish strongly between mutable and immutable references, and that have the parametric polymorphism to let functions that can use both kinds return the same thing you passed to them, though. C will simply just never be one of them.


Many uses of strchr do write via a pointer derived from a non-const declaration. When we introduced const qualifier it was noted that they were actually declaring read-only access, not unchangeability. The alternative was tried experimentally and the consequent "const poisoning" got in the way.


I believe C is doing the right thing. Const as immutability is a kludge to force the language to operate at the level of data structure/API design, something that it cannot do properly.


Have you ever used a high-level statically-typed language, e.g. haskell?


The straight-forward approach is just two functions, one with `const` and one without (You can make one of them `static inline` around the other and do some casting to avoid implementing the same thing twice).

With that, selecting the correct function via `_Generic` should be possible (`_Generic` is a bit fiddly, but matching on `const char * ` and `char * ` should work just fine for this), and for the most part this is actually an/the intended use case for `_Generic` - it's basically the same as the type-generic math functions, more or less.


The committee has reviewed a proposal (document N2360) to for const-correct string functions.

But making function signatures const-correct solves only a small part of the problem. A new API can only be used in new code, and casts can remove the constness from pointers leaving open the possibility that poorly written code will inadvertently change the const object. An attempt to change a global variable declared const will in all likelihood crash, but changing a local const can cause much more subtle bugs.

In my view, a more complete solution must include improving the detection of these types bugs in compilers and other static and even dynamic analyzers even without requiring code changes. It's not any more difficult to do that detecting out of bounds accesses. (In full generality it cannot be done just by relying on const; some other annotation is necessary to specify that a function that takes a const pointer doesn't cast the constness away and modify the object regardless.)


One proposal solved this by doing exactly that:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2068.pdf


How about allowing `return` to be used as a qualifier within a function or prototype's argument which, if present, would adjust the qualifiers of the function's return value to match those of the argument, e.g. adding "const" or removing "volatile" as appropriate?

This, if one did:

    char *strchr2(char return *restrict src, char target)
    {
      while(*src)
      {
        if (*src == target) return src;
        src++;
      }
    }
then one version of the function could support both const and non-const usage. BTW, I'd also like to see "register" and "return register" be usable as a qualifiers for pointer-type function parameters which would promise that the passed in pointer wouldn't "escape", or else that it could only escape through the return value (so a compiler that could see everything done with the return value wouldn't have to worry about the argument escaping).


strchr() is one of several C library functions that have this issue.

C++ solved this by overloading strchr():

    const char *strchr(const char *s, int c);
    char *strchr(*char *s, int c);
C of course doesn't have overloading.

One solution could have been to define two functions with different names, perhaps "strchr" and "strcchr". The time to do that would have been 1989, when the original ANSI C standard was published.

I suppose a future C standard could leave strchr() as it is (necessary to avoid breaking existing code) and add two new functions.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: