- Auto-incrementing or auto-decrementing values at compile-time - 7 Updates
- Why do some people hate namespace prefixes? - 14 Updates
- for ... else blocks - 4 Updates
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Apr 18 03:51PM -0400 I have a need fairly often to return distinct values for a return value. I don't particularly care what the values are, but they just need to be distinct and unique so that if they are returned later I can identify the exact cause of the error, where it failed. Something like this: int my_function(void) { if (!test_condition1) return -1; // Indicate it failed at this test // Arbitrary code if (!test_condition2) return -2; // Indicate it failed at this test // Arbitrary code if (!test_condition3) return -3; // Indicate it failed at this test // If we get here, we're good } Is there an existing way in C/C++ to automatically create some value that would allow me to add a new test and have it inject the new value? Ideally, I'd like for the compiler abilities to be sticky, meaning once you put in the token/whatever to identify you need a locally scoped automatically incrementing or decrementing value, that it bakes it into source code during the compile. Something like coding it this way initially: int my_function(void) { if (!test_condition1) return #autodec; // Indicate it failed at this test if (!test_condition2) return #autodec; // Indicate it failed at this test if (!test_condition3) return #autodec; // Indicate it failed at this test // If we get here, we're good } And during compilation it automatically translates it to this for, baking in the number: int my_function(void) { if (!test_condition1) return #autodec[-1]; // Indicate it failed at this test if (!test_condition2) return #autodec_[-2]; // Indicate it failed at this test if (!test_condition3) return #autodec_[-3]; // Indicate it failed at this test // If we get here, we're good } This would allow new code to be added later without a hard-value, and it would automatically adjust to the value inside the scope: int my_function(void) { ==> if (!test_condition0) ==> return #autodec; // Indicate it failed at this test if (!test_condition1) return #autodec[-1]; // Indicate it failed at this test if (!test_condition2) return #autodec_[-2]; // Indicate it failed at this test if (!test_condition3) return #autodec_[-3]; // Indicate it failed at this test // If we get here, we're good } It would change to this during compile, and write the source file back out: if (!test_condition0) return #autodec[-4]; // Indicate it failed at this test I can see doing this in an external tool, but is there some way to do it in C/C++? And if not, does anyone have any idea for a good syntax on how to do it? -- Rick C. Hodgin |
scott@slp53.sl.home (Scott Lurndal): Apr 18 08:07PM >This would allow new code to be added later without a hard-value, and >it would automatically adjust to the value inside the scope: There are two sides to every function call - how do the callers of that function know, a priori, which return code matches which (pre)condition failure; particularly when subsequently code gets inserted into the existing set such that successive autogenerated return codes are shifted by one? Just use a #define, static const uint32_t or enum and update them as needed. |
Ian Collins <ian-news@hotmail.com>: Apr 19 08:18AM +1200 On 19/04/2019 07:51, Rick C. Hodgin wrote: > Is there an existing way in C/C++ to automatically create some value > that would allow me to add a new test and have it inject the new > value? An enum. -- Ian. |
Bart <bc@freeuk.com>: Apr 18 09:25PM +0100 On 18/04/2019 20:51, Rick C. Hodgin wrote: > meaning once you put in the token/whatever to identify you need a > locally scoped automatically incrementing or decrementing value, that > it bakes it into source code during the compile. Not really sure what you're getting at. But this function: int test(int n) { switch (n) { enum {base=__LINE__}; case 1: return base-__LINE__; case 2: return base-__LINE__; case 3: return base-__LINE__; } return 0; } Returns -3, -5, -7 when called with n = 1,2,3. A new case would return a different error (ie. negative value), with no enums to maintain (assuming it's on a different line). Alternatively just return -__LINENO__ for an absolute line number to pinpoint where it went wrong in the function. |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Apr 18 09:37PM +0100 > I don't particularly care what the values are, but they just need to be > distinct and unique so that if they are returned later I can identify > the exact cause of the error, where it failed. <cut> > return #autodec; // Indicate it failed at this test > // If we get here, we're good > } This ties the correctness of every calling function into the order in which these tests are written. I think it should be added to your language ASAP. <cut> -- Ben. |
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Apr 18 04:42PM -0400 On 4/18/2019 4:07 PM, Scott Lurndal wrote: > There are two sides to every function call - how do the callers of that > function know, a priori, which return code matches which (pre)condition > failure; The functions pretty much always return 0 or a positive value if there were no errors. It's contextual. how_long_is_this_text() will return a negative value if you don't pass in a valid parameter, or 0 or a larger value if there is content there, etc. > particularly when subsequently code gets inserted into the existing set > such that successive autogenerated return codes are shifted by one? I don't have any autogenerated code in most projects. Some, but not many. > Just use a #define, static const uint32_t or enum and update them as needed. I write enough new code that it's becoming tedious to keep track of all the unique values. I will probably write an external tool and add a pre-build processing step during compilation. -- Rick C. Hodgin |
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Apr 18 04:45PM -0400 On 4/18/2019 4:37 PM, Ben Bacarisse wrote: >> } > This ties the correctness of every calling function into the order in > which these tests are written. You missed the part where the idea I'm looking for bakes the values first encountered with the naked #autodec into solid values which are later identified as #autodec[-1] ... #autodec[-Nn], which allows later #autodec portions to be added and they'll automatically insert the next value in that location. > I think it should be added to your language ASAP. You're such a hateful person to me, Ben. You said previously in a private email that you were going to try to refrain from responding to my posts. Please try harder. Your failures are unbecoming. -- Rick C. Hodgin |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 18 07:29AM +0200 > "std" was a rather uninspired choice as a namespace name, in contrast with > other languages that have well thought out divisions of namespaces, C++ > chose to put almost everything into one big garbage dump. ... These languages - like Java - have a much larger standard-library. And in the case of Java there is also the package-level of member -access which enforces a finer granular naming of the packages. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 18 07:34AM +0200 > in that library have the prefix "png_". Do you go your way to create > aliases for those names (eg. using macros of whatever) that have that > prefix removed? No, because this is inconvenient. But if there would be png::-prefixes this would be convenient. |
"Fred.Zwarts" <F.Zwarts@KVI.nl>: Apr 18 09:07AM +0200 "Juha Nieminen" schreef in bericht news:q97lu2$egu$1@adenine.netfront.net... >have to write a prefix like for example "png_", but it does bother >you to have to write a prefix like for example "std::"? >I'm honestly curious to know. I have not yet encountered such a situation. I don't like macros, I like the scoping rules of 'using'. (If I use 'using' in a header file, I never use it at the global :: namespace level, only in my own namespaces.) I do not know of an easy replacement of 'using' in the example you mention, for variables, functions, classes, etc. I assume that libpng is written in C, where no namespaces are available. If there would be a simple replacement for 'using' I might consider to use it. But only if it would be simple enough for the reader of the code to understand in a blink of an eye the meaning of it. The complexity of removing prefixes in your example bothers me more than the prefixes themselves. The difference with the std:: prefix is, that there is a very simple and well known method to remove it, designed especially for this case. |
wyniijj@gmail.com: Apr 18 12:26AM -0700 Juha Nieminen於 2019年4月17日星期三 UTC+8下午3時06分59秒寫道: > I bet that if they didn't know that writing namespace prefixes is > optional, that you can bypass it with a `using` expression, they > would not protest having to write it. It's because of, me-thinks, the way people remember/process words. The advantage(or disadvantage)of prefix is that the object is more uniquely named. Unlike namespace, every time I see 'string' I have to look for, even analyse programs to figure-out the right meaning that name is associated to, from file to file. Ex: Mars::wind, Mars::rock Earth::wind, Earth::rock When I see 'wind', 'rock', how am I supposed to think with these words? Mars_wind, Earth_rock would be more clearer. |
"Fred.Zwarts" <F.Zwarts@KVI.nl>: Apr 18 10:41AM +0200 "Jorgen Grahn" schreef in bericht news:slrnqbe9ob.4jo.grahn+nntp@frailea.sa.invalid... >It's not, not necessarily. I may want to use the name "string" >locally, and don't expect such a name to conflict with the standard >library. Not to mention names like find(). I don't think it is wise to use such a widely used name as 'string' locally. The other extreme is that someone may want to use 'std' locally. Then it would be even more safe to always use ::std:: as a prefix. Some people do. |
Bart <bc@freeuk.com>: Apr 18 10:44AM +0100 > Earth::wind, Earth::rock > When I see 'wind', 'rock', how am I supposed to think with these words? > Mars_wind, Earth_rock would be more clearer. On Earth, how many times do people talk about Earth-rocks or Earth-wind to distinguish them from not only Martian rocks and wind, but from any other planet? How annoying would it be to have to do that all the time? (And just to make those terms absolutely unambiguous, would we also have to prefix them with the the location of this solar system within this galaxy?) It is sufficient to use 'rocks' and 'wind' for 99.99% of the time, and only use the qualifiers when you are actually talking about extra-terrestrial versions. |
wyniijj@gmail.com: Apr 18 06:44AM -0700 Bart於 2019年4月18日星期四 UTC+8下午5時44分50秒寫道: > On Earth, how many times do people talk about Earth-rocks or Earth-wind > to distinguish them from not only Martian rocks and wind, but from any > other planet? What on 'Earth' we are actually talking about and physically live in are an imaginary programming world. > (And just to make those terms absolutely unambiguous, would we also have > to prefix them with the the location of this solar system within this > galaxy?) Ambiguity are more of the problem than annoyance. We should try to avoid name collision as possible, all the times. > It is sufficient to use 'rocks' and 'wind' for 99.99% of the time, and > only use the qualifiers when you are actually talking about > extra-terrestrial versions. I will try to eliminate that 0.01% hard-to-find 'bug' |
"Öö Tiib" <ootiib@hot.ee>: Apr 18 06:51AM -0700 On Thursday, 18 April 2019 11:41:47 UTC+3, F.Zwarts wrote: > I don't think it is wise to use such a widely used name as 'string' locally. > The other extreme is that someone may want to use 'std' locally. Then it > would be even more safe to always use ::std:: as a prefix. Some people do. Why you are using that "string" in complex expressions? Can you bring example? I use string mostly in super simple contexts like: using PhoneNumber = std::string; Meaning of it is that in first sketch std::string can be enough; but likely there will be a class PhoneNumber later. We may need operations like PhoneNumber::countryCode() and we may need a PetName not to be assignable to PhoneNumber. Same is true with every kind of text values. These have type that in long run can have more operations and constraints than "basic sequence of chars". So why to type "std::string" in complex expressions? |
Manfred <noname@add.invalid>: Apr 18 03:57PM +0200 On 4/18/2019 11:44 AM, Bart wrote: > to distinguish them from not only Martian rocks and wind, but from any > other planet? > How annoying would it be to have to do that all the time? The translated geography of "On Earth" would be "within std", i.e. inside standard-library code, not application code. |
Juha Nieminen <nospam@thanks.invalid>: Apr 18 02:09PM > for variables, functions, classes, etc. > I assume that libpng is written in C, where no namespaces are available. If > there would be a simple replacement for 'using' I might consider to use it. Why would you want to? Why would you want to remove the "png_" prefix from all the names in the library? That would only make your code harder to read because you can't see anymore where you are calling the libpng library functions and where you are calling something else. |
Juha Nieminen <nospam@thanks.invalid>: Apr 18 02:12PM > It is sufficient to use 'rocks' and 'wind' for 99.99% of the time, and > only use the qualifiers when you are actually talking about > extra-terrestrial versions. Suppose a program is using the Boost library, and you see a stray "shared_ptr" without a prefix. Which version is it using? (This is from an actual real-life example, not just an artificially invented one.) |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 18 04:21PM +0200 > all the names in the library? That would only make your code harder to read > because you can't see anymore where you are calling the libpng library > functions and where you are calling something else. If there would be namespaces with libpng and the types / fuctions within this namespace would be meaningful and not ambigous when stripped, this could be convenient. With std:: the types and functins are well known to the deveopers so there isn't any confusion when std:: is stripped. |
Vir Campestris <vir.campestris@invalid.invalid>: Apr 18 09:36PM +0100 On 18/04/2019 15:09, Juha Nieminen wrote: > all the names in the library? That would only make your code harder to read > because you can't see anymore where you are calling the libpng library > functions and where you are calling something else. There are those who wish to remove the std:: prefix from all the names in STL. That's not really different to removing the png_ prefix from all the names in the PNG library. I asked this question on the C++ group at work. Early indications are that people want to keep the std:: prefixes in place. I'll try to report back... I think there are more people on that than regularly post here. Andy |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 18 10:39PM +0200 On 18.04.2019 16:12, Juha Nieminen wrote: > "shared_ptr" without a prefix. Which version is it using? > (This is from an actual real-life example, not just an artificially > invented one.) First note that you don't need to know. `std::shared_ptr` is an adaption of `boost::shared_ptr`, so you already know all about it even if you don't know details of Boost. Also if you're going to maintain that code, * use the smart pointer that the original developers did, unless you're going to refactor it, in which case you're in for a larger effort anyway. --- But let's say the example was, instead, something like `something::Image` versus `something_else::Image` versus `boost::gil::Image`, where the two first have nothing to do with photographic images. Ordinarily you get acquainted with the relevant types as you dive into the code. But if one just, unexpectedly, encounters an unqualified "Image", then one checks what that means in this code, once. The easiest way is just visual inspection, move eyeballs up with line of sight in roughly the direction of the nearest `using` declaration. If that's out of sight then I find it easier to hover the mouse over the word than to scroll. Cheers & hth., - Alf |
David Brown <david.brown@hesbynett.no>: Apr 18 12:21PM +0200 On 17/04/2019 18:44, Bart wrote: > (This processes command-line options and filenames for a C compiler, but > the same pattern is used in several programs.) > This bit doesn't need to be fast, and it doesn't need to be clever. Since it doesn't need to be fast, and doesn't need to be clever, what's wrong with existing C solutions - using a boolean flag, splitting things out into a separate function (you can give it a name, rather than using a lambda), or using a goto ? If your language already has a "for/else" statement, then it's fair enough to use it, of course. |
Bart <bc@freeuk.com>: Apr 18 06:54PM +0100 On 18/04/2019 11:21, David Brown wrote: > a lambda), or using a goto ? > If your language already has a "for/else" statement, then it's fair > enough to use it, of course. Well, this is the point really. If a feature is reliably available, then you just use it because it's convenient. Instead of inventing a solution or rewriting a pattern you've used 100s of times before. Same argument with the subject of multi-level loop breaks. If writing C, then every so often you have to stop and work around the problem of C having only single-level breaks. (Or zero-level breaks if you happen to be inside 'switch'.) (Last time I used a multi-level break: about 15 minutes ago. I wasn't writing C. It's just there. What I could also have done with actually was 'while-else' that I haven't got. So something to ponder adding.) |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Apr 18 08:36PM +0100 > ... If writing C, then every so often you have to stop and work around > the problem of C having only single-level breaks. This is a case where what you call a work-around, I call an improvement. I like to reason about code, and the label helps a lot. I often ask, particularly after loops, "what is the state of the program at this point?" and the presence of a label is a big red flag telling me I have to take partial execution into account. It's not a huge advantage, since multi-level breaks are rare and likely to be flagged by a big comment, but the label is in just the right place for me to know I have to think about gotos. -- Ben. |
Bart <bc@freeuk.com>: Apr 18 09:15PM +0100 On 18/04/2019 20:36, Ben Bacarisse wrote: > since multi-level breaks are rare and likely to be flagged by a big > comment, but the label is in just the right place for me to know I have > to think about gotos. In my codebase (only compiled code not scripting), about 2.5% of all 'breaks' are multi-level ones (and break is used very commonly in my code to terminate endless loops), and 2% of all 'for' loops are 'for-else'. It doesn't sound much, but DB mentioned once that only 1.5% of his C for-loops were anything other simple iteration via a variable. Yet C loops still allow all those other possibilities, things that can make code harder to reason about, not easier. |
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