- Just some code - 7 Updates
- auto return type - 13 Updates
Juha Nieminen <nospam@thanks.invalid>: Jun 28 05:12AM > I didn't see Boltar's comment because he's in my kill file. > And you're pretty close now, again. > Just a heads up. You are going to killfile me because I'm quoting Bjarne Stroustrup? |
David Brown <david.brown@hesbynett.no>: Jun 28 10:39AM +0200 On 27/06/18 22:54, Alf P. Steinbach wrote: >> cases it is common enough - for the sort of usage you have here, it /is/ >> obscure. > How can a single ?: be obscure? It is a matter of how you use it - it is not the ?: operator itself that is hard. "(a < b) ? b : a" is fine. Your monstrosity is not. > Beginners learn it, very early on, and you say some experienced > programmers you've encountered find it challenging? Beginners learn the syntax for ?:, and then a fair proportion promptly forget about it and don't use it in normal code. However, I don't claim many programmers would find something like the "maximum" ?: example to be difficult. I am saying that the code /you/ wrote, with it's unusual syntax, its use of poorly-understood lifetime rules, and unhelpful layout is obscure, hard to understand, and easy to get wrong. Good code is /clear/. It is clear what the code does, and what the code does not do. The layout should reflect the logic of the code. As to what experienced programmers would think about it - just read the replies you have got in this thread. There are plenty of experienced C++ programmers here - none of them think this is a good way to write code, several have asked what it does, and others have simply not bothered to even try to figure it out. The most positive response you got was from me - that it is an interesting experiment, but not something for real code. > I find that claim hard to believe. I am not sure what your normal programming environment is - maybe you write your code alone. You have a very odd style, and are perhaps a poor judge of what other people find comfortable in their coding. In any coding review I have seen, your typical c.l.c++ code would be rejected outright - reviewers would assume it is obvious where the problems lie. This does not mean your code is wrong - or even that there is a problem with your style. It means it is significantly different from normal styles - enough to be difficult and error-prone for many people to interpret, and enough to be seen as different merely for the sake of being different or appearing clever. Personally, I think it is good sometimes to see such variation, and it can help us all learn - but I would hate to have to /work/ with your code. To balance this, it is clear that all programmers have a style and a view of "normal programming styles" that is heavily influenced by the type of work they do. That applies to me as well as anyone else. > evident, one expects such an expression to just compute a boolean value. > But > 1. it isn't /always/ bad to do that with boolean expressions, and There are a few idioms that rely on non-execution of parts of expression, like "p && foo(*p)". As a C or C++ programmer, you need to be familiar with these sorts of things to understand other people's code. That does not mean it is a good idea to /write/ them. And coding standards that are concerned with quality code, ban them. Here are a couple of rules from MISRA (yes, I know MISRA has its faults): Rule 12.3: The comma operator should not be used. Rule 13.5: The right hand operand of a logical && or || operator shall not contain persistent side effects. This allows things like "x = p && cos(p);", but not "p && printf(*p)". The point is that if someone reads quickly over the code and assumes that the right-hand operand is evaluated in some cases when it is not, it does not affect the logic of the code. Having said that, there can certainly be places where this kind of thing /can/ be appropriate. Deep within library code, you sometimes need code constructs that are unusual, complicated, or take a long time to understand. There is plenty in the implementation of the C++ standard library that is beyond the comprehension of most C++ programmers. > 2. a choice expression isn't like a boolean expression. It is in this sense. > operations that indicate success/failure via boolean returns: > // A. OK for me > const bool success = a() and b() and c() and d() and e(); Functions called "a", "b", etc., are not okay for me in real code - they would have longer names. So this would have to be spread across many lines - not okay. And real code would likely have parameters, and probably some code between the function calls. You are mistaking a hypothetical example with real code. > Again, compare that to > // OK for me > const bool success = a() and b() and c() and d() and e(); There are many other ways to do this: bool success = true; if (success) success &= a(); if (success) success &= b(); if (success) success &= c(); if (success) success &= d(); if (success) success &= e(); or: bool doAll() { if (!a()) return false; if (!b()) return false; if (!c()) return false; if (!d()) return false; if (!e()) return false; return true; } const bool success = doAll(); or: bool success = false; do { if (!a()) break; if (!b()) break; if (!c()) break; if (!d()) break; if (!e()) break; success = true; } while (false); > never allow short-circuit expressions that have side effects." appears > to mean that the coding standards that you regard as decent, require the > fantastic ugliness and awkwardness of (B) or (C) above. No, it merely means you can imagine beauty in unrealistic examples, but can't imagine good ways to implement real code. > Regarding (2), that a choice expression isn't like a boolean expression, > choice expressions are IME much more commonly used for side effects than > boolean expressions are, especially where a result value is used. And it would be, IME, an even worse idea to rely on side-effects and lack thereof in a conditional expression compared to a logical one. (If the gcc extension of statement expressions were to be included in standard C and C++, it would allow you to express some of these things neatly and clearly.) >> would be a /good/ way to write it. > Yes, considering all possibilities is often useful. > If for nothing else, one might learn something from the exercise. :) That is what we are doing here! >> give new ideas. Writing it in actual serious code is "smart-arse", >> which is no longer a complement. > I don't get what's fancy or "smart" about it. Ah, so you haven't learned enough yet :-) >> coding practice. > But what is it that's Greek to you, or that you suspect would be Greek > to most others, in the code? I mean like making "a Π b" be an intersection operator for sets. > and `goto` a common cleanup. > We use it because it's easier to understand and analyze, to prove > correctness of, due to the simple guarantees. Yes, of course - it is better to write code with lower risks of bugs than to write code that makes it easier to find the bugs. |
PoorOldAlFSaysMrBoltar@sadsack.com: Jun 28 09:22AM On Wed, 27 Jun 2018 21:45:47 +0200 >On 27.06.2018 15:41, MrBoltarToYou@galactic.com wrote: >> snip >Your third identify to be killfiled by me. It really makes little odds, I write my posts in vi and editing the From: line takes seconds. You might end up with a very big kill file. Assuming you actually use one and its not all just bluster. |
Manfred <noname@invalid.add>: Jun 28 01:59PM +0200 On 6/28/2018 10:39 AM, David Brown wrote: > if (success) success &= c(); > if (success) success &= d(); > if (success) success &= e(); Since &= is a bitwise operator, I'd rewrite this as: bool success = true; success = success && a(); success = success && b(); success = success && c(); success = success && d(); success = success && e(); But still I'd prefer Alf's expression, possibly split across multiple lines: const bool success = a() and b() and c() and d() and e(); Which incidentally keeps the const qualifier (which is something I value) |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 28 04:53PM +0200 On 28.06.2018 10:39, David Brown wrote: >> How can a single ?: be obscure? > It is a matter of how you use it - it is not the ?: operator itself that > is hard. "(a < b) ? b : a" is fine. Your monstrosity is not. Well, let's investigate at what point you, or the programmers you imagine, lose comprehension. 1. (s == "blah"? 1 : 2) 2. (s == "blah"? DerivedA{} : DerivedB{}) 3. (s == "blah? A{}.x : B{}.x) Has the conditional turned into a somewhat incomprehensible monstrosity already in 2, or is it the use of a data member, as in 3, that makes their eyes glaze over? I hadn't ever dreamed that current programmers have such difficulties. But I'm learning. And maybe we can nail this more precisely. ;-) > [snip] Cheers!, - Alf |
Bart <bc@freeuk.com>: Jun 28 07:03PM +0100 On 28/06/2018 15:53, Alf P. Steinbach wrote: > their eyes glaze over? > I hadn't ever dreamed that current programmers have such difficulties. > But I'm learning. And maybe we can nail this more precisely. ;-) I think this is the expression involved: (args[1] == "--faux-text"? With_faux_text{}._ : With_stream_detection{}._), app::run(); When I first glanced at this, I assumed it was in this form: (A ? B : C, D); With the D, as I thought, belonging to the C as I assumed that this was one ?: term only, not a ?: term then something else. Actually it's like this: (A ? B : C), D; That is, it evaluates B or C then executes D. At least, you do use parentheses around the ?: which is rare in C code. That your version is confusing might be something to do with it using 18 punctuation tokens, 22 punctation characters, 5 underlines, 3 hyphens, and long indentifier names that look more like comments. Now, ?: is used when you want to evaluate either x or y, and need to immediately use the result of that within an expression. If you don't need to use the actual value, just the side-effects, then you shouldn't use ?:, as you would just being using it to avoid writing a proper if-else statement. The same argument applies to the comma operator; you use it when you really need to evaluate one expression inside another, and not just to be able to write: X, Y; instead of: {X; Y;} If you apply those guidelines, then your example becomes: if (args[1] == "--faux-text") With_faux_text{}._; else With_stream_detection{}._); app::run(); Now you have form and indentation to help you see the structure. This could with ?: and comma too: (args[1] == "--faux-text" ? With_faux_text{}._ : : With_stream_detection{}._), app::run(); but it's not as good as just writing it properly. -- bart |
David Brown <david.brown@hesbynett.no>: Jun 28 10:10PM +0200 On 28/06/18 16:53, Alf P. Steinbach wrote: > their eyes glaze over? > I hadn't ever dreamed that current programmers have such difficulties. > But I'm learning. And maybe we can nail this more precisely. ;-) I think you'll have a lot of difficulty trying to get a precise point here - this is not a binary issue. The "maximum" example is easy, your original code is hard, and in between there is a sliding scale. It takes experience and a good understanding of other programmers to be able to tell if code is /too/ hard - and it will depend massively on the details of the code, the type of problem you are solving, and of course the programmers who are looking at the code. There is no black and white answer here - sorry. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 28 12:56AM +0100 On 27 Jun 2018 20:29:34 GMT > auto f(); > is hardly helpful. So should we avoid the auto return type > for functions which are part of an API for this reason? I think this is a bit of a side issue. My view is that you should instead avoid C++14 deduced return types where you actually know what the return type is, except in the case of short lambda expressions, as a matter of good form and making your code intelligible. This is apart from the documentation difficulties to which you refer. Where you don't necessarily know what the return type is, this was rather more self-documenting with C++11. With C++11 when deducing return types you had to have a trailing return type specified using a decltype expression (or std::result_of) except in the case of single statement lambda expressions (I think, it's going back a bit now). Doxygen does correctly document that form for you. There is nothing to stop you doing that with C++14 also, but this sort-of offends the DRY principle since it is duplicative. I have only mainly used auto with C++14 deduced return types in cases, say in template code, where you do not actually know what the return type is in advance. This is often coupled with the use of decltype on the function having that deduced return type[1], because the function is used for compile time metaprogramming and is never actually executed at all. Usually such functions with deduced return types are not part of the public API anyway. Where they are, I think the documentation should explain the position. Chris [1] This is decltype applied to the function application itself, in order to generate a type. It is not the same as using decltype in a C++11 style auto return type function declaration. |
Sam <sam@email-scan.com>: Jun 27 05:14PM -0400 Stefan Ram writes: > auto f(); > is hardly helpful. So should we avoid the auto return type > for functions which are part of an API for this reason? Avoiding a very useful, new language feature only because a documentation tool can't deal with it doesn't seem like a good reason to me. With the increased complexity of C++, only an actual C++ compiler can fully understand C++ code. This is not the only part of modern C++ that doxygen doesn't quite pick up. I find doxygen very useful, and I use it a lot. I do not take into consideration doxygen's limitations when writing code. I only review doxygen's output after the fact; and make whatever manual fixes and tweaks to doxygen's output that can be reasonably done. |
Juha Nieminen <nospam@thanks.invalid>: Jun 28 05:20AM > ought to define an interface (that's the I) but auto depends on the > implementation details. With something having an official API it should > be vice versa, implementation should depend on the interface. Note that using 'auto' in an API might sometimes be justified. More particularly as a synonym for "none-of-your-business type". I'm not joking. The most prominent example of this would be the actual type of a lambda. It's quite literally "none of your business". The programmer shouldn't concern himself about what the actual type of a lambda is, hence it's always used as 'auto'. The actual underlying type is unspecified, and up to the compiler, and code using lambda should never try to use that type explicitly. |
David Brown <david.brown@hesbynett.no>: Jun 28 10:48AM +0200 On 27/06/18 22:29, Stefan Ram wrote: > auto f(); > is hardly helpful. So should we avoid the auto return type > for functions which are part of an API for this reason? No, you should avoid having the auto return type in an API because it is a daft thing to have in an API. An API should be specific, and say /exactly/ what it returns. (In cases where that is impossible, such as in some template functions, you need to question your coding structure and API design before resorting to auto.) "auto" is extremely convenient for local functions - static functions, anonymous namespaces, private methods, etc. It is not something you would want in an API. That applies to functions, variables, consts, etc. |
boltar@cylonHQ.com: Jun 28 09:40AM On Wed, 27 Jun 2018 17:14:59 -0400 >With the increased complexity of C++, only an actual C++ compiler can fully >understand C++ code. This is not the only part of modern C++ that doxygen >doesn't quite pick up. IMO the C++ syntax has now jumped the shark, its far to complex and rivals Perl in its hideousnous. Originally it was commented that uglies such as "virtual func() = 0" instead of "pure virtual func()" were because extra keywords may break older programs that use them as names elsewhere. Then we had new keywords such as override, final, explicit etc added anyway making that argument moot. Then things got work and IMO the syntax reached its nadir with the "[=/&]() -> <return type> { }" horror of lambda functions. We have std::function. Why the hell didn't they simply introduce std::lambda with a similar syntax? eg: std::lambda<int((<local scoped vars>,(parameters)> { } Or just do what other languages do and use the same syntax as primary functions eg: func(int mylambda(a,b,c) { }) or similar? |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 28 03:20PM +0100 On Thu, 28 Jun 2018 09:40:42 +0000 (UTC) > Perl in its hideousnous. Originally it was commented that uglies such as > "virtual func() = 0" instead of "pure virtual func()" were because extra > keywords may break older programs that use them as names elsewhere. A pure function means something completely different. That would be a very poor choice of words, quite apart from needing a new keyword. > Then > we had new keywords such as override, final, explicit etc added anyway making > that argument moot. The argument is never moot. Presumably it was felt that the advantages of having override, final and explicit as keywords outweighed the potential for breakage, which would have been very small. > We have std::function. Why the hell didn't they simply introduce std::lambda > with a similar syntax? > eg: std::lambda<int((<local scoped vars>,(parameters)> { } A comma separating the captured variables from parameters, when parameters are already separated by commas? Or are you inventing a new meaning for parentheses (it is not clear because yours are unbalanced). This syntax is hopeless. I prefer what we have. > Or just do what other languages do and use the same syntax as primary functions > eg: > func(int mylambda(a,b,c) { }) or similar? Because C++ language rules require you to find some way of identifying the captured variables and whether the capture is to be by reference or by value. To try to introduce automatic lexical closures as in some other languages would have been a significant alteration to C++ and wouldn't have worked. Languages which do have that generally work on the basis that numbers and characters (so called "immediate" values) are copied by value and any other object is copied by reference. I think you are too easily offended by language syntax. Try another language - there are plenty to choose from. |
boltar@cylonHQ.com: Jun 28 02:34PM On Thu, 28 Jun 2018 15:20:20 +0100 >> "virtual func() = 0" instead of "pure virtual func()" were because extra >> keywords may break older programs that use them as names elsewhere. >A pure function means something completely different. That would be a It does? Please enlighten us because in C++ the "= 0" on the end definately means pure virtual. Perhaps you're getting confused with another language. >The argument is never moot. Presumably it was felt that the advantages >of having override, final and explicit as keywords outweighed the >potential for breakage, which would have been very small. Ditto "pure". >> eg: std::lambda<int((<local scoped vars>,(parameters)> { } >A comma separating the captured variables from parameters, when >parameters are already separated by commas? Or are you inventing My mistake, I meant to write ";" as used in for(). >a new meaning for parentheses (it is not clear because yours are >unbalanced). This syntax is hopeless. I prefer what we have. Presumably you think the std::function syntax is hopeless too then. >I think you are too easily offended by language syntax. Try another I'm offended by hacks, which is what C++ seems to be descending into. >language - there are plenty to choose from. Most are flavour of the month with little real traction and any language take a long time to become proficient in anyway. I have better things to do with my time than start from scratch. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 28 03:58PM +0100 On Thu, 28 Jun 2018 14:34:30 +0000 (UTC) > >A pure function means something completely different. That would be a > It does? Please enlighten us because in C++ the "= 0" on the end definately > means pure virtual. Perhaps you're getting confused with another language. Look it up, and give yourself a broader background. If 'pure' were to be used as a keyword, it would be to mark that a function is without side effects, not to indicate that it is a virtual function without implementation. Various languages have a 'pure' keyword, such as D; I would not especially support its introduction in C++ but it should be left alone for that use in case in the future others decide otherwise as it may possibly have optimization benefits; it should not be expended to give effect to your proposal. > >of having override, final and explicit as keywords outweighed the > >potential for breakage, which would have been very small. > Ditto "pure". No - see above. Your proposition that having 'overide, final and explicit' as keywords means a free for all for any other half-baked keyword anyone on a newsgroup thinks should be used, because it is now "moot", is ridiculous. It is even more ridiculous when 'pure' already has a well accepted and different meaning. > >a new meaning for parentheses (it is not clear because yours are > >unbalanced). This syntax is hopeless. I prefer what we have. > Presumably you think the std::function syntax is hopeless too then. You are missing the point. It does not make closures, and the syntax of std::function does not provide for it to do so. If you want to have a closure with std::function you have to construct it specifically with a lambda expression, std::bind or the like. In fact, you have deliberately snipped the part of my post which previously explained this to you. > Most are flavour of the month with little real traction and any language take a > long time to become proficient in anyway. I have better things to do with my > time than start from scratch. Broadening your knowledge would help you avoid the temptation to think that you know it all when it is apparent that you do not. |
boltar@cylonHQ.com: Jun 28 03:06PM On Thu, 28 Jun 2018 15:58:45 +0100 >be used as a keyword, it would be to mark that a function is without >side effects, not to indicate that it is a virtual function without >implementation. Various languages have a 'pure' keyword, such as D; I In C++ that is the definition of pure. This discussion is about C++ not the general definition of pure virtuals as you see it. >> Ditto "pure". >No - see above. Your proposition that having 'overide, final and Yes. >"moot", is ridiculous. It is even more ridiculous when 'pure' already >has a well accepted and different meaning. Not in C++. >Broadening your knowledge would help you avoid the temptation to think >that you know it all when it is apparent that you do not. Spare me your feeble attempts at being patronising, they're falling flat. I suggest you get your own clue. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 28 04:25PM +0100 On Thu, 28 Jun 2018 15:06:27 +0000 (UTC) > >implementation. Various languages have a 'pure' keyword, such as D; I > In C++ that is the definition of pure. This discussion is about C++ not > the general definition of pure virtuals as you see it. Pure functions are rarely virtual. Anyone with minimal knowledge of computer science knows what a pure function is. > >that you know it all when it is apparent that you do not. > Spare me your feeble attempts at being patronising, they're falling flat. > I suggest you get your own clue. I don't need to be patronizing. You seem clueless, and you do it all for yourself. I genuinely was suggesting that you need to widen your experience in order to help deal with that. |
boltar@cylonHQ.com: Jun 28 03:34PM On Thu, 28 Jun 2018 16:25:23 +0100 >> the general definition of pure virtuals as you see it. >Pure functions are rarely virtual. Anyone with minimal knowledge of >computer science knows what a pure function is. We're not talking about the mathematical definition of pure, we're talking about the c++ definition of pure virtuals which mean something else entirely. Either you're being pedantic for the sake of it or you're just another aspie unable to follow normal discussion. >I don't need to be patronizing. You seem clueless, and you do it all >for yourself. I genuinely was suggesting that you need to widen your >experience in order to help deal with that. Do carry on, I'll get the popcorn! Your attempts at this are highly amusing :) |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 28 04:58PM +0100 On Thu, 28 Jun 2018 15:34:15 +0000 (UTC) > about the c++ definition of pure virtuals which mean something else entirely. > Either you're being pedantic for the sake of it or you're just another > aspie unable to follow normal discussion. If I were, that would be a totally inappropriate remark to make. Ad hominem remarks of that kind would just be an indication that you have lost the argument. So you seem not only to be lacking understanding about C++, but to be unpleasant and lacking understanding about C++. Anyway, you carry on with your fixation with pure virtual functions. Better informed people would want to reserve any 'pure' keyword to denote pure functions. |
legalize+jeeves@mail.xmission.com (Richard): Jun 28 04:15PM [Please do not mail me a copy of your followup] Sam <sam@email-scan.com> spake the secret code >With the increased complexity of C++, only an actual C++ compiler can fully >understand C++ code. This is not the only part of modern C++ that doxygen >doesn't quite pick up. Use DoxyPress instead; it uses clang to parse. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Terminals Wiki <http://terminals-wiki.org> The Computer Graphics Museum <http://computergraphicsmuseum.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
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