- Practical examples of coroutines being useful? - 2 Updates
- ++ and — - 14 Updates
- Dear Standard Library, Leave the global namespace alone. - 8 Updates
- (PDF) Clinical Scenarios in Surgery - Decision Making and Operative Technique by Dimick - 1 Update
| Juha Nieminen <nospam@thanks.invalid>: Jun 28 01:56PM One of the strangest and perhaps most surprising (and even controversial) new features of C++20 are coroutines. This post is not about bashing them, criticizing them, questioning the motivation for adding them to the already complex language, or anything like that. Let's put all that aside for a moment, and just focus on what they can actually be useful for. Practical examples. I had never heard of "coroutines" before, and in fact it took me quite a while to understand what exactly they are, and what they are used for. They are often described as kind of emulating cooperative multitasking (similarly to how multitasking worked in Windows 3.x and MacOS prior to X.) I would, however (and from what I understand), describe them more like a way to more easily store the state of a function (or group of functions) so that the function can be exited at any point that it wants, and then execution resumed later from that point (when the rest of the code tells it to resume execution.) (Well, I suppose that's exactly what "cooperative multitasking" means, but I think describing it as I did is much clearer than using that term.) Of course doing this was already possible even before C++20, but it required a lot more manual labor, a lot more coding. The coroutines help automatize the process and make it much easier. So where is this actually useful? I can think of two examples. Are there more? Example 1: You are writing a function that decompresses some compressed input format. The decompressed data should be written to a buffer of a given size. Whenever the buffer gets full, this decompressor function should return it to the calling code for it to consume it. After the calling code has consumed it, the decompression should continue from where it left. Since compression formats are complicated there may be literally dozens of places in the decompression algorithm where the buffer may get full, in very varied situations, sometimes even inside deeply nested loops, coroutines make this process a lot easier because the code can "yield" at any point, anywhere (even inside deeply nested loops), and then continue from that point as if nothing has happened (other than the buffer having been emptied). Example 2: A class/module that parses command-line arguments. Since the arguments may appear in many different forms, the parser is done so that it will be called with individual command-line parameters (which may end in the null character, or a whitespace character, or something else). In other words for each individual parameter the calling code calls the parser giving it that parameter. However, not all command-line parameters are singular, as in consisting of only one "word". A parameter may be followed by one or more strings (such as file names, etc.) The calling code doesn't know if a particular parameter is just data for the previous parameter or not, it just feeds them one by one to the parser. Thus, when the parser encounters a parameter that expects further parameters, it needs to remember its state between calls. (It needs to remember which particular command-line parameter it's currently parsing, and any additional parameters given to it already.) (This, of course, can be done even with C++98, but with coroutines this "storing the current state of the parser" becomes much easier.) |
| Bonita Montero <Bonita.Montero@gmail.com>: Jun 28 04:47PM +0200 If you don't like coroutines, don't use them. |
| Ben Bacarisse <ben.usenet@bsb.me.uk>: Jun 28 01:14AM +0100 >> verb), and I don't think it does in mathematics either. And in C and >> C++, incrementing means adding one. > Not really. It really does. It's right there in the definition. > to the same machine code. But that machine code will almost certainly > be "add 4 to the address held in ptr". In fact what you mean is "go to > the next value in the sequence". What happens to the representation of the pointer when we add one to it should not prevent you from believing that you are adding 1. You are adding 1. > resolution of 1mg. However the fact we are using metric units is > merely conventional. It has no scientific significance. As is our > choice of 1mg as the spacing between the tests. So it's "accidental". Ah, scare quotes. I agree it's "accidental" but not that it's accidental. > on, up to ten men, digging a hole, and time them. Now the choice of > one is not "accidental". It's fundamental that we can only have a > whole number of workers. But you said "Adding one means "increase by a constant value which accidentally happens to be unity". I see neither an accident nor an "accident" here. Adding one means increasing by unity. That seems to me to be fundamental. >> "increment by". > Exactly. ++ should mean "take the next member of an ordered set". Which it > does in C++. Eh? It means add one in C++: "The value of the operand object is modified (3.1) by adding 1 to it". What is the next member after 1.0 of the ordered set of double values? What is ++x when x is 1.0? > In C++ "++" can't always be replaced by "+=1". In C it can. Eh (again)? Both standards give that equivalence so as to delegate all the details about types and conversion to the descriptions of addition and assignment. -- Ben. |
| Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jun 27 06:42PM -0700 On Tuesday, 28 June 2022 at 00:02:50 UTC+1, Keith Thompson wrote: > > in the sequence". > Which you do by adding 1. In pointer arithmetic, adding 1 has a well > defined meaning, which is not advancing to the next memory address. In pointer arithmetic, adding one does not mean adding one to the address. So it's "adding one", but only if, in this context, we accept that "adding one" means "add four" (or however many bytes an integer occupies). ptr++ means "go to the next integer in the sequence and take its address". You can of course also say it's "adding one" because of C's rules for pointer arithmetic. But it's not "really adding one". Take this. int x; int* iptr = &x; unsigned char* cptr = iptr; if (iptr == cptr) printf("pointers the same\n"); iptr++; cptr++; if (iptr == cptr) printf("pointers the same\n"); Now iptr and cptr are equal, we add the same value to them and then they are not equal. This isn't "wrong" because we're not working with the normal rules for arithmetic. But we're using the word "add" in a special way. So we can say "we're not really adding one", using the normal meaning of the word. |
| Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jun 27 06:52PM -0700 On Tuesday, 28 June 2022 at 01:15:14 UTC+1, Ben Bacarisse wrote: > happens to be unity". > I see neither an accident nor an "accident" here. Adding one means > increasing by unity. That seems to me to be fundamental. If we've got two workers and add another, we have increased by unity. If we've got two grams of sugar and we add another gram, we've done something rather different. The symbol "1" appears in both cases if you write it out. But it doesn't mean the same thing. In one case it expresses an underlying, fundamental property of the thing it represents. In the other case it doesn't. It expresses an accidental property of the sugar. |
| Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jun 27 07:27PM -0700 >> Which you do by adding 1. In pointer arithmetic, adding 1 has a well >> defined meaning, which is not advancing to the next memory address. > In pointer arithmetic, adding one does not mean adding one to the address. Yes, it does -- because that's how C and C++ define the operation of adding a pointer and an integer. > So it's "adding one", but only if, in this context, we accept that "adding one" > means "add four" (or however many bytes an integer occupies). No, adding an integer value N to a pointer value does not mean adding N bytes (unless sizeof *ptr == 1). > ptr++ means "go to the next integer in the sequence and take its address". Given that ptr is of type int*, yes, more or less. (I'd phrase it differently.) ptr = ptr + 1 means exactly the same thing. > You can of course also say it's "adding one" because of C's rules for > pointer arithmetic. But it's not "really adding one". Yes, it's really adding one. > equal. This isn't "wrong" because we're not working with the normal rules for > arithmetic. But we're using the word "add" in a special way. So we can say "we're > not really adding one", using the normal meaning of the word. We're using "add" in the way defined by the language. That is the normal meaning. Please stop trying to confuse the issue by applying other meanings to terms that are already well defined. Yes, we know that some of these terms can have different meanings in other contexts. You're insisting that those other meanings are somehow more "normal" than the meanings defined by the language. That's silly. -- 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 */ |
| Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jun 27 08:37PM -0700 On Tuesday, 28 June 2022 at 03:28:10 UTC+1, Keith Thompson wrote: > Yes, we know that some of these terms can have different meanings in > other contexts. You're insisting that those other meanings are somehow > more "normal" than the meanings defined by the language. That's silly. It would have been more consistent for C to have defined ptr += sizeof(*ptr); as the way of moving a pointer along to the next position. However it's such a common requirement that this wasn't done, and instead the concept of "scaled arithmetic" was developed. When you change the rules of arithmetic like this, inevitably you break some of the relationships that hold in arithmetic over the set of the real numbers. In this case a = x; b = x; therefore a + c = b + c; no longer necessarily holds. So "a + c" means something different to what is normally understood by these symbols. What is meant is sufficiently close to the operation of addition over the real numbers to make it reasonable to use the same word, as long as you make clear that you are using the word :add" in a special way. |
| Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jun 27 11:07PM -0700 > It would have been more consistent for C to have defined > ptr += sizeof(*ptr); > as the way of moving a pointer along to the next position. No, it really wouldn't. Pointers are not numbers. It's useful to define a few limited arithmetic operators on them: pointer + integer -> pointer pointer - integer -> pointer pointer - pointer -> integer Defining ptr+1 to yield a useless and invalid pointer would have been silly. Do you expect pointer+pointer or integer-pointer to have some consistent meaning? > b = x; > therefore a + c = b + c; > no longer necessarily holds. Sure it does, as long as the types are consistent. Adding 1 to an int* pointer is a *different operation* than adding 1 to a char*. > over the real numbers to make it reasonable to use the same word, as > long as you make clear that you are using the word :add" in a special > way. It's a lot easier to understand pointer arithmitec the way it's actually defined than to start with some inconsistent mental model and adjust it to fit reality. -- 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 */ |
| Juha Nieminen <nospam@thanks.invalid>: Jun 28 06:40AM > pointer - pointer -> integer > Defining ptr+1 to yield a useless and invalid pointer would have been > silly. One can think of "ptr+1" as being just syntactic sugar for "&ptr[1]". (Technically it might not be "just syntactic sugar", but one can think of it as such.) |
| Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jun 28 02:32AM -0700 On Tuesday, 28 June 2022 at 07:41:06 UTC+1, Juha Nieminen wrote: > One can think of "ptr+1" as being just syntactic sugar for "&ptr[1]". > (Technically it might not be "just syntactic sugar", but one can > think of it as such.) That's another reason for scaled pointer arithmetic. So that you can convert between ptr[2] and *(ptr + 2). I'm not saying that the decision to use scaled pointer arithmetic was wrong. I am saying that ptr += 1 is not "really" adding one to the pointer, if it is not to a single byte type. "Really" you are adding the size of the item the pointer points to. You can say "a pointer is not a number", and that's true in the important exceptional case of old x86 segment::offset pointers. But these never really worked well in C in any case. Compilers introduced the "far" keyword to help deal with them. My sister's address is 15. But in fact she lives in the thirteenth house in the street. All rules for numbers don't necessarily apply for house address numbers. But they are still called numbers. |
| "Öö Tiib" <ootiib@hot.ee>: Jun 28 03:05AM -0700 On Tuesday, 28 June 2022 at 12:32:34 UTC+3, Malcolm McLean wrote: > > think of it as such.) > That's another reason for scaled pointer arithmetic. So that you can convert > between ptr[2] and *(ptr + 2). It is other way around. The operator [] is defined in terms of pointer arithmetic so 2[ptr] is *(2 + ptr) and so required to work. We can't have circular definitions in specification. > I am saying that ptr += 1 is not "really" adding one to the pointer, if it is not to > a single byte type. "Really" you are adding the size of the item the pointer points > to. IOW you see yourself that making it in any other way would be silly. Pointer is internally address but that is not exposed in its interface. > You can say "a pointer is not a number", and that's true in the important exceptional > case of old x86 segment::offset pointers. But these never really worked well in > C in any case. Compilers introduced the "far" keyword to help deal with them. You need to use reinterpret_cast to get the integer value of that address out of pointer, or to turn it into byte address ... and then you need to know what platform you are at and what you are doing. |
| Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jun 28 03:15AM -0700 On Tuesday, 28 June 2022 at 11:05:51 UTC+1, Öö Tiib wrote: > It is other way around. The operator [] is defined in terms of pointer arithmetic > so 2[ptr] is *(2 + ptr) and so required to work. We can't have circular definitions > in specification. I don't know exactly what Denis Ritchie was thinking. But I suspect he decided early on that [] would be the subscript operator, and that incrementing the subscript by one would move to the next item in the array. The last was a no-brainer. Then you've got the question of how ptr[i] relates to *(ptr + i). Did he decide that arrays would be 0-based, then decide that pointer arithmetic would be scaled? Or did he decide that *(ptr + i) would mean ptr[i], and then accept, maybe reluctantly, that that entailed 0-based arrays? I don't know. |
| David Brown <david.brown@hesbynett.no>: Jun 28 03:07PM +0200 On 28/06/2022 11:32, Malcolm McLean wrote: > You can say "a pointer is not a number", and that's true in the important exceptional > case of old x86 segment::offset pointers. But these never really worked well in > C in any case. Compilers introduced the "far" keyword to help deal with them. You are wrong. A pointer is /not/ a number. It is /not/ an address. If you find that confusing, then it is no wonder you are writing such a stream of muddled posts. As a general definition, a "pointer" is a way to access data indirectly. In C, it is basically "an address with type information". (I say basically, because it can also represent information about what may or may not be accessible as fully defined behaviour, and of course weird implementations can have other data in a pointer.) In C++, that applies to "raw" pointers - other kinds of pointers may have extra information. If "p" is a pointer, p++ adds 1 to the /pointer/. It does not necessarily add 1 to the address stored by the pointer - we very rarely care what happens under the hood. If "p" and "q" are two pointers, and "n" is an integer, then it is always the case in C that "p + n == q + n", as you would expect. That is because the expression makes no sense in the language if "p" and "q" point to incompatible types, and the compiler should reject the code with an error if they are not compatible. It is important to understand the difference between what a high-level concept like "pointer" represents, and how it might happen to be implemented in a particular case - even if the implementation is obvious and close to universal. |
| David Brown <david.brown@hesbynett.no>: Jun 28 03:17PM +0200 On 27/06/2022 23:32, Malcolm McLean wrote: >> verb), and I don't think it does in mathematics either. And in C and >> C++, incrementing means adding one. > Not really. As Ben and Keith have said, it is in the definition in the C standards. (In C++, is always possible to have different effects on operators of your own types - but the same definition applies in C++ for the built-in integer, floating point and raw pointer types.) To quote from C11 : (6.5.2.4) """ The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The postfix -- operator is analogous to the postfix ++ operator, except that the value of the operand is decremented (that is, the value 1 of the appropriate type is subtracted from it). """ (6.5.3.1) """ The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is equivalent to (E+=1). See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers. The prefix -- operator is analogous to the prefix ++ operator, except that the value of the operand is decremented. """ |
| Ben Bacarisse <ben.usenet@bsb.me.uk>: Jun 28 02:55PM +0100 > If we've got two workers and add another, we have increased by unity. > If we've got two grams of sugar and we add another gram, we've done > something rather different. You can't do either in C++. In C++ you manipulate numerical quantities, and unity is 1 when talking about numerical values. In C++ I'd write workers += 1; grams_of_sugar += 1; I have added 1 in both cases and there is nothing accidental about that. It was done (presumably) because that is what the program design needs at this point. > doesn't mean the same thing. In one case it expresses an underlying, > fundamental property of the thing it represents. In the other case it > doesn't. It expresses an accidental property of the sugar. I know what you are getting at, but in C++ adding unity means adding one. The fact that we designed the program so that adding one was the right thing to do at that point was not an accident though they may have been some choice in the matter. The fact that some quantities are dimensionless does not justify saying that in the other cases adding one (in a program) is an accident. I hope you can see I know what you are getting at. It's the words I don't like. It gives rise to statements that appear daft to me. I don't mind "accidental" because the scare quotes tell me you don't mean a literal accident. -- Ben. |
| Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jun 28 07:22AM -0700 On Tuesday, 28 June 2022 at 14:08:00 UTC+1, David Brown wrote: > If you find that confusing, then it is no wonder you are writing such a > stream of muddled posts. > As a general definition, a "pointer" is a way to access data indirectly. A pointer is a way to access data indirectly. But so is a reference. So is a key. But references and keys are not pointers. In C and C++, it must be possible to take the address past the pointer. Even in the case of a pointer to a scalar. So a pointer does have to be an "address". Usually, a machine address of course. In exceptional implementations you might want to argue about what constitutes an "address" and what doesn't. But you must be able to "go to the next address", so it's got to have number-like properties. It can't be any system of indirection. |
| Siri Cruise <chine.bleu@yahoo.com>: Jun 27 04:58PM -0700 In article <756f4d86-7d99-4047-a5ee-25705ecf265en@googlegroups.com>, > If I try to compile the following with the GNU compiler (g++): If worse comes to worse, you can always use cpp and persnickety placements of #defines and #includes to get around these problems. #define static auto #include "idiot's stupid variable declarations" #undef static #define static static Not ideal, but you can make anything work. If you do have to do this nonsense, be sure to add comments why. And if even worse comes to cesspit worse. m4 is widely available and can be coerced with pinhead's hooks and chains to do what cpp cannot. -- :-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @ 'I desire mercy, not sacrifice.' /|\ Discordia: not just a religion but also a parody. This post / \ I am an Andrea Chen sockpuppet. insults Islam. Mohammed |
| Juha Nieminen <nospam@thanks.invalid>: Jun 28 06:51AM > Given that the language of the standard says that it is unspecified > whether values from the c prefixed headers (like cstddef) are declared > in the global scope I would say this is not a bug. AFAIK it's a compromise by the standard because they don't want to overburden the standard library implementations, or something. But I think it's a bad compromise. It's making the life of the standard library implementors easier at the cost of making the life of C++ programmers harder. If you #include <cstddef> you cannot assume that the names are in the global namespace but you have to take into account that they could be. Good luck remembering every single name in all the <c...> header files. On top of that, IIRC you can't assume <stdlib.h> exists, so no luck in trying to make sure that those names *are* in the global namespace. (Although I think C++23 "undeprecates" those headers, so if you wait for it to become widely supported you can make sure.) |
| "Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Jun 28 10:19AM +0200 On 28 Jun 2022 08:51, Juha Nieminen wrote: > account that they could be. Good luck remembering every single > name in all the <c...> header files. > On top of that, IIRC you can't assume <stdlib.h> exists, Uh, where did you get that idea? The ".h" headers were formally deprecated in 1998, the first standard, because the committee unwisely, I'd say retardedly, assumed that the intent of the clean "c..." headers would be fully supported and adopted. That didn't happen, and will now never happen, since the committee backed down a little from their high academic stance in 2011. Likewise, it will never happen that the ".h" headers will disappear. C++'s success is entirely founded on C compatibility, on leveraging C libraries. That will not change. You can count on that much more than you could count on core language features like `throw` specifications and `export`-ed templates. > so no luck > in trying to make sure that those names *are* in the global namespace. For C++11 names from the C library just include the relevant ".h" header, very simple. > (Although I think C++23 "undeprecates" those headers, so if you wait > for it to become widely supported you can make sure.) A simple remedy is to always include both of pair, "c..." and ".h". That provides full guarantees about where the C++11 and earlier names from the C library are defined, namely in both namespace `std` and the global namespace. Guarantees that one can RELY on. Unfortunately the committee didn't entirely give up their academic pipe dream, and in C++14, C++17 and no doubt also in C++20, new names such as `std::byte` and C11 esoteric math functions, were introduced in "c..." headers only, with explicit exceptions that these names should not be provided by ".h" headers. Sabotaging things just to score points for a f...ing academic ideal. Politics everywhere, it's frustrating to have the C++ standardization committee prioritize internal political goals to that degree (one member even argued that Bjarne is to blame for all the recent bad decisions, I think his words were "Bjarne is the problem"). - Alf |
| Paavo Helde <eesnimi@osa.pri.ee>: Jun 28 12:33PM +0300 27.06.2022 17:37 Frederick Virchanza Gotham kirjutas: > If I try to compile the following with the GNU compiler (g++): > #include <cstddef> namespace MyGreatProject { > class size_t { > }; } // namespace Problem solved. |
| "Öö Tiib" <ootiib@hot.ee>: Jun 28 02:49AM -0700 > libraries. That will not change. You can count on that much more than > you could count on core language features like `throw` specifications > and `export`-ed templates. It wasn't retarded but carefully lobbied by likes of MicroSoft to get rid of competitors like Watcom and Borland. Maybe some academics were fooled but there never was hope. C++ headers are never defining interface of module. So two modules written in C++ but compiled with different version of compiler or different compiling options were never designed to be possible to link together without using C headers as mediator. Nothing to talk of other programming languages. So even if there are some libraries written in C++ these either are open source or pretend to be C libraries for to be useful. |
| Juha Nieminen <nospam@thanks.invalid>: Jun 28 01:25PM >> On top of that, IIRC you can't assume <stdlib.h> exists, > Uh, where did you get that idea? I expressed it a bit poorly. The <*.h> headers being deprecated means that it's not guaranteed that they will exist in a future version of the standard. So while yes, you can be sure that they exist eg. in C++11, you can't be sure they will exist in some hypothetical future C++35 (and thus your code may break if compiled in that mode). OTOH the committee apparently relented with C++23 and will "undeprecate" those headers, so you can use them without the fear of them suddenly disappearing... |
| Juha Nieminen <nospam@thanks.invalid>: Jun 28 01:27PM >> }; > } // namespace > Problem solved. Way to write confusing code inside that namespace... |
| David Brown <david.brown@hesbynett.no>: Jun 28 03:27PM +0200 On 28/06/2022 10:19, Alf P. Steinbach wrote: > the C++ standardization committee prioritize internal political goals to > that degree (one member even argued that Bjarne is to blame for all the > recent bad decisions, I think his words were "Bjarne is the problem"). In all real compiler and library implementations of C++, the same toolchain is both a C and a C++ compiler, and the library and headers are shared where possible. But sometimes you just have a C compiler without C++ - to the greatest possible extent, the C library and headers of an implementation are a subset of the C++ library and headers. That means the C++ committee do not mess with the contents of <math.h> or <stdlib.h> except when it is unavoidable - it saves implementers littering the files with "#ifdef __cplusplus ..." sections. So when new maths functions were introduced, there were two options - either the C committee also wanted them and they could go in <math.h> (and therefore also <cmath>), or the C folks did not want them and the C++ gang had to put them in their own header. It would, IMHO, have made more sense to have a new C++ specific header with the new functions rather than adding them to <cmath>, but I haven't bothered to follow the discussions and reasoning behind the decision. |
| hester holt <hesterholt6@gmail.com>: Jun 27 09:37PM -0700 This is the PDF eBook version for Clinical Scenarios in Surgery - Decision Making and Operative Technique by Dimick (Download link for cheap price) https://booksca.ca/library/ebook-clinical-scenarios-in-surgery-decision-making-and-operative-technique-by-dimick/ |
| 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. |