Muttley@dastardlyhq.com: Apr 20 08:27AM On Wed, 19 Apr 2023 16:13:36 -0500 >"std::optional was added in C++17 to provide a new standard way of >expressing disappointments and more, and it has been extended in C++23 >with a new interface inspired by functional programming." Sorry, std::optional is totally pointless. All it does is save manually creating a pair/tuple at the point of return. Any function that requires returning a large amount of data will almost certainly do it via a parameter reference anyway and simply return a boolean value as success/failure so std::optionals entire use case is functions that return simple values where a success/failure boolean is required too. |
Paavo Helde <eesnimi@osa.pri.ee>: Apr 20 11:56AM +0300 > Any function that requires > returning a large amount of data will almost certainly do it via a parameter > reference anyway Why would that be? Returning data as (a part of) the function return value is cleaner and potentially faster. Non-const reference parameters just complicate things, both for human readers and for the optimizer. |
Muttley@dastardlyhq.com: Apr 20 09:36AM On Thu, 20 Apr 2023 11:56:32 +0300 >> reference anyway >Why would that be? Returning data as (a part of) the function return >value is cleaner and potentially faster. Non-const reference parameters So copying an array with 1 billion entries into a function then copying it out again is more efficient than simply updating the reference is it? >just complicate things, both for human readers and for the optimizer. Umm, no. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 12:36PM +0200 Am 19.04.2023 um 23:13 schrieb Lynn McGuire: > "Functional exception-less error handling with C++23's optional and > expected" by Sy Brand > https://devblogs.microsoft.com/cppblog/cpp23s-optional-and-expected/ Nice, this "expected" variant class. I think that's taken from Rust which also returns result/error-"pairs". If you want to communicate your error directly to the caller that's more convenient than excep- tions. But for hard errors which go throuh multiple call-levels (e.e. bad_alloc or system_error) exceptions are faster when nothing happens. I think many developers returned their own error-variant so far so it's good that this gets it own standard to make code more readabel. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 12:41PM +0200 Am 20.04.2023 um 12:36 schrieb Bonita Montero: > bad_alloc or system_error) exceptions are faster when nothing happens. > I think many developers returned their own error-variant so far so > it's good that this gets it own standard to make code more readabel. I just checked the size of expected<int, int> and it's 8, so expected actually isn't a variant, what makes access more efficient. |
Paavo Helde <eesnimi@osa.pri.ee>: Apr 20 02:20PM +0300 >> value is cleaner and potentially faster. Non-const reference parameters > So copying an array with 1 billion entries into a function then copying it > out again is more efficient than simply updating the reference is it? Ever heard about RVO and move semantics? Welcome to the modern ages! |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 03:18PM +0200 Am 20.04.2023 um 12:41 schrieb Bonita Montero: >> it's good that this gets it own standard to make code more readabel. > I just checked the size of expected<int, int> and it's 8, so expected > actually isn't a variant, what makes access more efficient. No, it's a union with VC++: union { _Ty _Value; _Err _Unexpected; }; bool _Has_value; |
David Brown <david.brown@hesbynett.no>: Apr 20 04:59PM +0200 > reference anyway and simply return a boolean value as success/failure so > std::optionals entire use case is functions that return simple values where > a success/failure boolean is required too. Perhaps you got that idea from working with old C compilers and old C code, where programmers were allergic to creating structs and would rather use an ugly and error-prone mix of pointer parameters instead of returning the function's results in the natural way - as the return value. When a function (C or C++) returns a struct that is too big to fit in registers, it is implemented by the calling function passing a hidden pointer parameter for the return value - there's no need to do it manually. C++ RVO guarantees you avoid extra coping in many cases. If the data is big enough that you don't want it in your local frame, you'll likely be using some kind of ownership class to handle the resource and heap management in a clean RAII manner. std::optional<> is extremely convenient. It is mostly just a wrapper for making a struct of a boolean and the contained type, but it is a very handy wrapper for that purpose. Many programming languages have some kind of "Optional" or "Maybe" type, because they are very useful in practice. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 05:26PM +0200 > Sorry, std::optional is totally pointless. ... It seems that everything that overwhelms you is pointless technology. My code regularly sounds like Swahili to you. If you have a native type you can reserve a value for "not a valid value", such as with floating point values where there is a NaN. But that's no longer possible with more complex objects. There an optional<> is optimal, because it knows an invalid state. The nice thing about it is that the optional object does not even have to be instantiated or destroyed later, which may save runtime. An optional<> can also contain heavyweight objects that only have to be created if it is really necessary. This is a common code pattern that, thanks to optional<>, does not have to be reworked manually every time. |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Apr 20 04:39PM +0100 >>value is cleaner and potentially faster. Non-const reference parameters > So copying an array with 1 billion entries into a function then copying it > out again is more efficient than simply updating the reference is it? Bait and switch. A function that should modify an array needs to do so via a reference (or pointer). This has nothing to do with what std::optional is for, nor with the "trick" of passing in a reference to receive a large value that might otherwise be returned by the function. A typical use might be a function that computed the inverse of a matrix. There may be no inverse, so std::optional is a reasonable type to return. In the past, the value might well have been "returned" via reference parameter. -- Ben. |
Muttley@dastardlyhq.com: Apr 20 03:55PM On Thu, 20 Apr 2023 14:20:12 +0300 >> So copying an array with 1 billion entries into a function then copying it >> out again is more efficient than simply updating the reference is it? >Ever heard about RVO and move semantics? Welcome to the modern ages! 1) Create and update local array, move 1 billion elements on return. or 2) Update reference array directly. Which do you think is more efficient? Welcome to proper programming! |
Muttley@dastardlyhq.com: Apr 20 03:58PM On Thu, 20 Apr 2023 16:59:59 +0200 >> std::optionals entire use case is functions that return simple values where >> a success/failure boolean is required too. >Perhaps you got that idea from working with old C compilers and old C Nope. >std::optional<> is extremely convenient. It is mostly just a wrapper Its an ugly mess. value()/value_or(), exception handling required, seriously? Thanks, but I'll stick with a simple bool return value. |
Muttley@dastardlyhq.com: Apr 20 03:58PM On Thu, 20 Apr 2023 17:26:23 +0200 >Am 20.04.2023 um 10:27 schrieb Muttley@dastardlyhq.com: >> Sorry, std::optional is totally pointless. ... >It seems that everything that overwhelms you is pointless technology. Unlike you I write code to do a job, not with an obfuscated fashion show. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 06:01PM +0200 >>> Sorry, std::optional is totally pointless. ... >> It seems that everything that overwhelms you is pointless technology. > Unlike you I write code to do a job, not with an obfuscated fashion show. This "obfuscation" saves work. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 06:03PM +0200 > Its an ugly mess. value()/value_or(), exception handling required, seriously? > Thanks, but I'll stick with a simple bool return value. The type of error may be relevant to a user. |
Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>: Apr 20 03:06AM -0700 I realised today that you can create a lambda object outside of the function in which the lambda is defined: auto Func(int a) { auto mylambda = [](void)->int { return 27u; }; return *decltype(&mylambda)(nullptr); } typedef decltype(Func()) LambdaType; int main(void) { LambdaType mylambda; mylambda(); } And on GodBolt: https://godbolt.org/z/js57TcT1K Did the Standard Committee intend for this to be impossible? |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 12:17PM +0200 Am 20.04.2023 um 12:06 schrieb Frederick Virchanza Gotham: > auto mylambda = [](void)->int { return 27u; }; > return *decltype(&mylambda)(nullptr); > } What's the meaning of returning a null-pointered Lambda ? |
Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>: Apr 20 03:31AM -0700 On Thursday, April 20, 2023 at 11:16:11 AM UTC+1, Bonita Montero wrote: > What's the meaning of returning a null-pointered Lambda ? Sometimes we write a function not for what the function actually does, but simply just to get a type from it. I have no intention of using the return value from an invocation of that function. Bonita surely you've seen this before where people write functions simply just to use 'decltype' on them later. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 02:56PM +0200 Am 20.04.2023 um 12:31 schrieb Frederick Virchanza Gotham: > On Thursday, April 20, 2023 at 11:16:11 AM UTC+1, Bonita Montero wrote: >> What's the meaning of returning a null-pointered Lambda ? > Sometimes we write a function not for what the function actually does, but simply just to get a type from it. You coudn't default-construct the lambda from outside, so you coudn't refer to that type and the pointer does't make sense. |
Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>: Apr 20 05:59AM -0700 On Thursday, April 20, 2023 at 1:54:16 PM UTC+1, Bonita Montero wrote: > You coudn't default-construct the lambda from outside, so you > coudn't refer to that type and the pointer does't make sense. I can and I did: https://godbolt.org/z/dcvrE138s |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 03:17PM +0200 Am 20.04.2023 um 14:59 schrieb Frederick Virchanza Gotham: >> You coudn't default-construct the lambda from outside, so you >> coudn't refer to that type and the pointer does't make sense. > I can and I did: https://godbolt.org/z/dcvrE138s Try it when it is relevant: when you have a lambda with a capture. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 06:49AM +0200 I was interested what's the cost of incrementally growing a vector<> vs. having a pre-grown vector that only has []-assingments: #include <iostream> #include <vector> #include <chrono> using namespace std; using namespace chrono; int main() { vector<char> vc( 1u << 30 ); // prevent dyanmic commit vc.resize( 0 ); auto timed = [&]<typename Fn>( char const *header, Fn fn ) { auto start = high_resolution_clock::now(); size_t n = vc.capacity(); for( size_t i = 0; i != n; ++i ) fn( i ); double s = duration_cast<nanoseconds>( high_resolution_clock::now() - start ).count() / 1.0e9; cout << header << s << endl; }; timed( "incremental: ", [&]( size_t i ) { vc.emplace_back( (char)i ); } ); timed( "immediate: ", [&]( size_t i ) { vc[i] = (char)i; } ); } On my Windows-PC with MSVC (AMD 3990X) having a pre-grown vector is about +11% faster. On my Linux-PC (G4400) both timings are faster and having a pre-grown vector is +173% faster. I didn't expect such results. |
Paavo Helde <eesnimi@osa.pri.ee>: Apr 20 12:03PM +0300 20.04.2023 07:49 Bonita Montero kirjutas: > about +11% faster. On my Linux-PC (G4400) both timings are faster > and having a pre-grown vector is +173% faster. I didn't expect such > results. You are leaving the vector building ("pre-growing") step out of the "immediate" timing. Of course it is faster. |
Bonita Montero <Bonita.Montero@gmail.com>: Apr 20 11:41AM +0200 Am 20.04.2023 um 11:03 schrieb Paavo Helde: >> results. > You are leaving the vector building ("pre-growing") step out of the > "immediate" timing. Of course it is faster. No, the vector has still its old size. The thing that I wanted to benchmark is the difference of between a vector which grows to its own capacity (first timing) vs. a pre-grown vector (second timing). On Linux the performance-difference is significant. |
Muttley@dastardlyhq.com: Apr 20 08:23AM On Wed, 19 Apr 2023 12:52:08 -0700 >of it from of the internet? I was amazed at the errors in here. The Bard >needs to be trained. Nobody is paying me to do it. God damn, the errors >are abundant. I don't know about you but I'm quite glad the language models still generate rubbish code. They day they start generating efficient working code based on a simple request we're all out of a job. |
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