- I think references should have been const by default - 12 Updates
| David Brown <david.brown@hesbynett.no>: Oct 23 11:54AM +0200 On 22/10/2021 17:14, Bart wrote: > With mine, it displays: > int > const int It turns out - who would have guessed? - that gcc is correct. The gcc developers these days tend to be very careful and strict about this kind of thing. As Keith says, the controlling expression undergoes "lvalue conversion" (this is in 6.5.1.1p2, if you want to look it up). C18 helpfully adds a footnote that did not exist in C11, saying "An lvalue conversion drops type qualifiers". (I think the standard could benefit from more of such explanatory footnotes.) I think it is odd, however, that you can have qualified types in the generic association list, since they can't ever match anything (AFAICS). |
| David Brown <david.brown@hesbynett.no>: Oct 23 12:21PM +0200 On 22/10/2021 16:48, Bart wrote: >> restricts you, thus making code clearer, safer, more maintainable, and >> perhaps sometimes more efficient. > There are better ways of doing it. There are certainly /different/ ways of doing things. There are lots of different programming languages, with their different strengths and weaknesses. > In C, it is just adds a lot of > clutter that effects readability and can hide real problems. What an odd idea. If you don't like "const", don't use it in your programming. Others find it useful to aid readability and avoid problems. > Neither does the syntax make it that obvious which bit of the type is > refered to, as in: > const int * const * x; If you find this kind of thing confusing, use "typedef". It exists to improve readability (amongst other benefits). > a const pointer to a struct which contains non-const pointers. The > 'const' only protects that top level; it does not stop you writing > nested non-const data. You mean, people who don't really understand what they are doing and write code that confuses themselves, get mixed up? And how is C different from any other language in that respect? I appreciate that you personally prefer a different ordering when writing types, and that you are not alone in that. Fine. C has a different ordering, and people usually manage perfectly well. The difference between "const int * x", "int * const x" and "const int * const x" is one of these things newbies to C often find hard, and it turns up in every FAQ and tutorial on the language. If /you/ still find it hard, read a FAQ. > In my example, x can still be written to! (x=0 is allowed; but *x=0 and > **x=0 are not.) Yes - x is not const. |
| Bart <bc@freeuk.com>: Oct 23 11:22AM +0100 On 23/10/2021 10:54, David Brown wrote: > explanatory footnotes.) > I think it is odd, however, that you can have qualified types in the > generic association list, since they can't ever match anything (AFAICS). They can be used in examples like this: #include <stdio.h> #define strtypeof(t) _Generic(t,\ const int*: "pointer to const int",\ int*: "pointer to int",\ default: "other") int main(void) { int * p; const int * q; puts(strtypeof(p)); puts(strtypeof(q)); } All compilers that support _Generic show: pointer to int pointer to const int This suggests a way to maintain those top level qualifiers, by wrapping a pointer around a type. But it would be an ungainly workaround (and the fact that typeof() also drops those qualifiers would might make it impractical). |
| David Brown <david.brown@hesbynett.no>: Oct 23 12:35PM +0200 On 23/10/2021 12:22, Bart wrote: > puts(strtypeof(p)); > puts(strtypeof(q)); > } Yes - but those are not qualified types. Using your preferred ordering, a "pointer to int" and "pointer to const int" are different types. > a pointer around a type. But it would be an ungainly workaround (and the > fact that typeof() also drops those qualifiers would might make it > impractical). Why are you inventing an ugly workaround for a non-existent problem? _Generic in C looks at the unqualified type of an expression - there isn't a problem. It turns out your compiler has a bug due to a slight misunderstanding of _Generic. I'm glad you've found it, and can correct it (assuming you want to be closer to following the standards). But no one is looking for a "workaround" here. (Especially not /here/, in c.l.c++ !) |
| Bart <bc@freeuk.com>: Oct 23 12:06PM +0100 On 23/10/2021 11:21, David Brown wrote: > What an odd idea. > If you don't like "const", don't use it in your programming. Others > find it useful to aid readability and avoid problems. I was thinking more about other people's code. Mine doesn't use const at all. >> const int * const * x; > If you find this kind of thing confusing, use "typedef". It exists to > improve readability (amongst other benefits). So, even /more/ clutter?! I's also like to see a typedefed version of my example that is not harder to understand. > You mean, people who don't really understand what they are doing and > write code that confuses themselves, get mixed up? And how is C > different from any other language in that respect? Yes, everybody. You have a dynamic tree data structure for example, using non-const references within its nodes to allow it to be updated. How do you write a function that takes a reference to that tree, but is not allowed to update it? This is what someone might expect of an immutable parameter. This is not to say that I know how to achieve this; I don't (but I haven't researched it much either). The nearest I can do is pass a deep copy of such a tree, to protect the original, but that is hardly efficient. I just see C's const as a waste of time. I'm starting to use readonly data in a few places without my languages, but where it's handled sensibly. What I don't do is introduce such a polarising type attribute at every level of a data structure, one that poisons every other type it comes into contact with, such that it becomes challenging to do perfectly innocuous things. |
| Ben Bacarisse <ben.usenet@bsb.me.uk>: Oct 23 01:23PM +0100 > I think it is odd, however, that you can have qualified types in the > generic association list, since they can't ever match anything > (AFAICS). I was curious so I tried this: #include <stdio.h> struct S { const int i; } s; struct S f(void) { return s; } int main(void) { const char *t = _Generic(f().i, int: "int", const int: "const int"); puts(t); } f().i is not a lvalue and has a const-qualified type. gcc prints "int", but clang prints "const int". I think clang is right here. (So much for "they all copy gcc"!) -- Ben. |
| Bart <bc@freeuk.com>: Oct 23 01:57PM +0100 On 23/10/2021 13:23, Ben Bacarisse wrote: > f().i is not a lvalue and has a const-qualified type. gcc prints "int", > but clang prints "const int". I think clang is right here. (So much > for "they all copy gcc"!) You need to file a bug report to Clang's developers so that they can fix that oversight! But, why do think Clang is wrong? The type has a top-level const qualifier. I don't get why this is only removed for an lvalue (where you'd think that a const attribute is more critical). |
| David Brown <david.brown@hesbynett.no>: Oct 23 06:45PM +0200 On 23/10/2021 13:06, Bart wrote: >> find it useful to aid readability and avoid problems. > I was thinking more about other people's code. Mine doesn't use const at > all. Perhaps if you used more of C's common features yourself, you'd be less confused about them and less inclined to think they are "clutter" or hinder readability. (If you only want to use C as an output language from your transpilers, and thus only use a subset of the language, then that's absolutely fine - but it makes you a poor judge of what features are useful to people working with human-written C code rather than machine-generated C code.) >> improve readability (amongst other benefits). > So, even /more/ clutter?! I's also like to see a typedefed version of my > example that is not harder to understand. typedef const int constant_integer; typedef constant_integer * pointer_to_constant_integer; typedef const pointer_to_constant_integer constant_pointer_to_constant_integer; typedef constant_pointer_to_constant_integer * pointer_to_constant_pointer_to_constant_integer; pointer_to_constant_pointer_to_constant_integer x; That's the order you prefer, is it not? (I'm not suggesting it's a good way to write it, I'm merely showing you how it could be done with a choice of names that might suit your liking.) Maybe you want it more compact: typedef const int * p_cint; typedef const p_cint * p_cp_cint; p_cp_cint x; In real code, of course, it would usually make more sense to think about what your types actually are and how they will be used, and then use type names that fit. > How do you write a function that takes a reference to that tree, but is > not allowed to update it? > This is what someone might expect of an immutable parameter. There are occasions when it is more convenient to cast away const, or where it is hard to maintain full const correctness. "const" does not absolve the programmer of having to think. But it does make a lot of code clearer and easier to understand. > level of a data structure, one that poisons every other type it comes > into contact with, such that it becomes challenging to do perfectly > innocuous things. Nobody does that with "const". I guess it is just yet another of C's features that you don't quite understand, and prefer to hate irrationally than learn. |
| Bart <bc@freeuk.com>: Oct 23 06:58PM +0100 On 23/10/2021 17:45, David Brown wrote: > typedef const int * p_cint; > typedef const p_cint * p_cp_cint; > p_cp_cint x; Well, I was right, the alternatives are worse. If you are interested in the actual type, or the 'shape' of that type, devoid of qualifiers, then you don't want all that. You want to know the type is 'int**'. > where it is hard to maintain full const correctness. "const" does not > absolve the programmer of having to think. But it does make a lot of > code clearer and easier to understand. Somebody writes an informal library but doesn't bother to mark with 'const' those functions that take char* that don't happen to modify the string: void f1(char*); void f2(char*); void f3(char*); Now someone who has a mania for 'const' wants to use it: const char* s="ABC"; f1(s); However, it doesn't work. They will know from the specs that f1 doesn't write into the string, but the compiler doesn't know that. Now, it starts to get messy. Either casts have to be inserted, or the library needs to be heavily revised. Then that library may import another which is also missing consts. And so const-poisoning infects the whole code-base. At some point, it will also stop you doing things legally, and you have to start using casts. Now, you are starting to fight the language. Was it Pascal or Ada that first had those in/out parameter attributes? I can write this [in my syntax]: proc f1(ichar s) = {} # anything goes proc f2(ichar in s) = {} # s is input to the function proc f3(ichar out s) = {} # s is output from the function I don't do anything with these at the minute (I think 'out' and 'inout', not shown, are just aliases for '&') but they can do a lot just as annotations. At some point an implementation can enforce them and ensure that an 'in' data structure is not modified in the function, even one that has mutable components. The programmer doesn't need to micro-manage every level of the type structure, or have to think about exactly how foolproof those 'const' attributes are. It should be like a write-protect switch on the whole caboodle. (At least, within the bounds of what the language can help with. A data structure may contain references to external data, such as files, disks, images, which can all be modifible, or they can be altered via another path to the original data. But C's const doesn't prevent that either.) |
| Ben Bacarisse <ben.usenet@bsb.me.uk>: Oct 23 09:02PM +0100 > fix that oversight! > But, why do think Clang is wrong? The type has a top-level const > qualifier. I said I think clang is right (because the expression f().i is not an lvalue). > I don't get why this is only removed for an lvalue (where you'd think > that a const attribute is more critical). lvalue conversion converts an lvalue to the value stored. It makes no sense for the result to have any qualifiers -- they are anything but critical for pure values. -- Ben. |
| Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Oct 23 09:30PM +0100 On Fri, 22 Oct 2021 04:41:47 -0000 (UTC) > So yes, 'const' can actually make the program more efficient (especially > in C++, where it guarantees to the compiler that it can assume the > contents won't change). Since this thread is entitled "I think references should have been const by default", it may be worth mentioning that holding a const reference to an object does not mean that the compiler "can assume the contents won't change". It guarantees that, in the absence of a const cast, non-mutable non-static data won't be modified through the reference. If the object concerned is a lvalue it says nothing about what might be done to the object's non-mutable data through its variable name (assuming that is non-const) or by some other non-const reference. It also says nothing about the mutability of the object's static data (if any). I say this in case it is used to put forward the incorrect notion that "const" means "thread safe", which I have occasionally seen propagated by the ill-informed. |
| Keith Thompson <Keith.S.Thompson+u@gmail.com>: Oct 23 03:07PM -0700 > But, why do think Clang is wrong? The type has a top-level const qualifier. > I don't get why this is only removed for an lvalue (where you'd think > that a const attribute is more critical). The removal of type qualifiers is part of lvalue conversion. No lvalue, no lvalue conversion. I can see that it would make sense for the expression `f().i` to have type int rather than const int, but the standard doesn't say so. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips void Void(void) { Void(); } /* The recursive call of the void */ |
| You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment