Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #118826 > unrolled thread
| Started by | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| First post | 2024-04-22 19:11 -0700 |
| Last post | 2024-04-25 14:08 -0700 |
| Articles | 15 — 5 participants |
Back to article view | Back to comp.lang.c++
Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-22 19:11 -0700
Re: Q: how to make an object that throws Sam <sam@email-scan.com> - 2024-04-22 22:32 -0400
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-22 21:51 -0700
Re: Q: how to make an object that throws Sam <sam@email-scan.com> - 2024-04-23 07:26 -0400
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-23 08:39 -0700
Re: Q: how to make an object that throws Sam <sam@email-scan.com> - 2024-04-23 22:08 -0400
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-23 20:07 -0700
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-23 22:10 -0700
Re: Q: how to make an object that throws Zhengyi Fu <i@fuzy.me> - 2024-04-23 11:08 +0800
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-22 21:52 -0700
Re: Q: how to make an object that throws wij <wyniijj5@gmail.com> - 2024-04-25 02:56 +0800
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-24 12:02 -0700
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-24 13:56 -0700
Re: Q: how to make an object that throws Ross Finlayson <ross.a.finlayson@gmail.com> - 2024-04-27 08:09 -0700
Re: Q: how to make an object that throws Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-04-25 14:08 -0700
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-22 19:11 -0700 |
| Subject | Q: how to make an object that throws |
| Message-ID | <n6Ocnf_tkL8shbr7nZ2dnZfqn_qdnZ2d@giganews.com> |
Hello I hope I might consult your expertise, I'm wondering about a use-case where for a given library object, to provide an instance of same type, that on any access, throws an exception. The idea is that there's an idea in a different language where the runtime throws a null_pointer_dereference exception when dereferencing a null pointer, yet in C++ it's signal segfault. So, what I wonder about is how to make an object in C++, of a given standard library type, and any arbitrary type, that on any access, throws. I suppose I might static_cast an object yet I wonder how to make it so then that any access to it throws. As you might imagine it's a use-case for exceptions as part of flow-of-control, that in the other language just is null yet in C++ would be for "an object of all types", that throws on any access.
[toc] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2024-04-22 22:32 -0400 |
| Message-ID | <cone.1713839569.577249.2570.1004@monster.email-scan.com> |
| In reply to | #118826 |
Ross Finlayson writes: > Hello I hope I might consult your expertise, I'm wondering about > a use-case where for a given library object, to provide an instance > of same type, that on any access, throws an exception. What does "any access" mean? Please be specific.
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-22 21:51 -0700 |
| Message-ID | <ZIKdnZ34YN_Wo7r7nZ2dnZfqnPqdnZ2d@giganews.com> |
| In reply to | #118828 |
On 04/22/2024 07:32 PM, Sam wrote:
> Ross Finlayson writes:
>
>> Hello I hope I might consult your expertise, I'm wondering about
>> a use-case where for a given library object, to provide an instance
>> of same type, that on any access, throws an exception.
>
> What does "any access" mean? Please be specific.
>
As if it were null, whatever would raise a segfault,
is the idea of "any access", then I wish I better
explain the differences among pointers, references, and
class returns from functions, looking at C++ 11,
and trying to understand some of the newer syntactic
sugar with regards to declarations.
std::vector<int> values() {
return static_cast<std::vector<int>> nullptr; // no
}
The idea is that some code can compute partial results,
or to the effect of launching asynchronous requests
void rr1(const std::string& s) {
std::list<std::string> l1 = rr2(s);
int i1 = rr3(s);
int i2 = rr4(s);
int siz = l1.size(); // throw
int i3 = rr5(i1, i2, l1.size());
}
so the idea is the re-routine runs through statements
as long as the inputs are satisfied, then these
rr1, 2, 3, 4, 5 throw if their arguments are the
null_throwing type, and any library code access
on the null_throwing type also throws.
Then the idea is that as a task, rr1 gets invoked,
that basically it's a future
std::future<int> rr1(const std::string& s) {
std::future<std::list<std::string>> l1 = rr2(s);
std::future<int> i1 = rr3(s);
std::future<int> i2 = rr4(s);
int siz = l1.size(); // throw
std::future<int> i3 = rr5(i1, i2, l1.size());
}
that the "re-routine" throws while its side affect
is that it launches (initiates) the asynchronous
call, that the callback (completion) populates a
partial results for the task that invokes this,
and adds another task to invoke the same re-routine
with the same arguments, which sets thread-local
(thread_local storage) in the task caller, the
retried asynchronous results, then rr the re-routine
is run over and over until it completes, using
exceptions as flow-of-control for "quit until satisfied".
It's an idea for writing co-routines in the language
as synchronous the routine, so what I'm hoping is to
figure out how to write routines as if they were
synchronous and blocking, what make for some convention
that as re-routines they can be implemented with
asynchronous callbacks, that the task queue, sets
them up with a "monad" a memoization as it goes along.
Then what I hope is to make something like nullptr
that can be cast to result an rvalue for any lvalue,
that on access dereference as a nullptr, would throw.
This way then the re-routine sort of automatically
primes its asynchronous results in whatever results
getting to the invoked re-routines, "satisfied" or
"satisfying" inputs, so that they're initiated
with completion handlers to populate the monad
and push the next re-run or the re-routine to
the task queue, which flows in the otherwise
flow-of-control in the language exactly the same
each time until it itself actually completes
and calls back to the originating (initiating)
callback (completion handler).
It's an idea to write asynchronous code as
the same as blocking code then run cooperative
multithreading as re-routines that never block
(yet may throw).
(It's been a while, I need to learn C++ 11
and even parts of C++ 03 and figure to target
C++ 11 for this kind of idea. There's that
std::future appears to be sub-classable and
will throw a future_error yet I'd hope that
what happens is that the resulting lvalue
just sits until it's accessed or as if
treated as a null pointer like nullptr,
then throws a given 'flow-of-control' exception.)
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2024-04-23 07:26 -0400 |
| Message-ID | <cone.1713871619.641020.31152.1004@monster.email-scan.com> |
| In reply to | #118831 |
Ross Finlayson writes:
> On 04/22/2024 07:32 PM, Sam wrote:
>> Ross Finlayson writes:
>>
>>> Hello I hope I might consult your expertise, I'm wondering about
>>> a use-case where for a given library object, to provide an instance
>>> of same type, that on any access, throws an exception.
>>
>> What does "any access" mean? Please be specific.
>>
>
> As if it were null, whatever would raise a segfault,
> is the idea of "any access", then I wish I better
Again, you need to explain what "whatever" means.
Are you looking for a class with deleted copy/move constructors or
assignment operators?
Are you looking for a class with an overloaded * or -> operator that throws
an exception?
/What/ are you looking for?
> explain the differences among pointers, references, and
> class returns from functions, looking at C++ 11,
> and trying to understand some of the newer syntactic
> sugar with regards to declarations.
Perhaps it would be more productive to invest a little bit more time
studying C++11, and learning the different parts of C++, what they are, and
how they work, before attempting to ask a meaningful question.
The term "any access" is utterly meaningless and context-free, in C++ terms.
Nobody really understands what exactly you're asking.
>
>
> std::vector<int> values() {
> return static_cast<std::vector<int>> nullptr; // no
> }
No self-respecting C++ compiler will compile this. This is syntactically
invalid.
> The idea is that some code can compute partial results,
> or to the effect of launching asynchronous requests
>
> void rr1(const std::string& s) {
>
> std::list<std::string> l1 = rr2(s);
>
> int i1 = rr3(s);
> int i2 = rr4(s);
>
> int siz = l1.size(); // throw
>
> int i3 = rr5(i1, i2, l1.size());
>
> }
What is "rr2"? What is "rr3"? What is "rr4"? What is "rr5"?
> so the idea is the re-routine runs through statements
> as long as the inputs are satisfied, then these
What "inputs"? What does "satisfied" mean?
> rr1, 2, 3, 4, 5 throw if their arguments are the
> null_throwing type, and any library code access
What does "null_throwing" mean?
C++ is very complicated. When discussing C++ it is very important to be
explicit and use consistent terms that are well-defined in C++.
[deletia]
> It's an idea for writing co-routines in the language
You will do yourself a huge, huge favor, by forgetting everything about co-
routines.
co-routines are a solution in search of a problem.
The only reason co-routines exist in C++ is because real execution threads
absolutely suck raw eggs in Microsoft Windows, and Microsoft hijacked the
standardization process to infect C++ with this co-routines bullshit just so
that MS-Windows would finally have a multi-threading implementation model
that does not suck.
> This way then the re-routine sort of automatically
> primes its asynchronous results in whatever results
> getting to the invoked re-routines, "satisfied" or
> "satisfying" inputs, so that they're initiated
> with completion handlers to populate the monad
> and push the next re-run or the re-routine to
> the task queue, which flows in the otherwise
> flow-of-control in the language exactly the same
> each time until it itself actually completes
> and calls back to the originating (initiating)
> callback (completion handler).
Go ask Microsoft. They invented all this bullshit. They can deal with it,
by themselves.
> (It's been a while, I need to learn C++ 11
co-routines are not C++11.
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-23 08:39 -0700 |
| Message-ID | <WbOcnbgzN9y9S7r7nZ2dnZfqn_udnZ2d@giganews.com> |
| In reply to | #118834 |
On 04/23/2024 04:26 AM, Sam wrote:
> Ross Finlayson writes:
>
>> On 04/22/2024 07:32 PM, Sam wrote:
>>> Ross Finlayson writes:
>>>
>>>> Hello I hope I might consult your expertise, I'm wondering about
>>>> a use-case where for a given library object, to provide an instance
>>>> of same type, that on any access, throws an exception.
>>>
>>> What does "any access" mean? Please be specific.
>>>
>>
>> As if it were null, whatever would raise a segfault,
>> is the idea of "any access", then I wish I better
>
> Again, you need to explain what "whatever" means.
>
> Are you looking for a class with deleted copy/move constructors or
> assignment operators?
>
> Are you looking for a class with an overloaded * or -> operator that
> throws an exception?
>
> /What/ are you looking for?
>
>> explain the differences among pointers, references, and
>> class returns from functions, looking at C++ 11,
>> and trying to understand some of the newer syntactic
>> sugar with regards to declarations.
>
> Perhaps it would be more productive to invest a little bit more time
> studying C++11, and learning the different parts of C++, what they are,
> and how they work, before attempting to ask a meaningful question.
>
> The term "any access" is utterly meaningless and context-free, in C++
> terms. Nobody really understands what exactly you're asking.
>
>>
>>
>> std::vector<int> values() {
>> return static_cast<std::vector<int>> nullptr; // no
>> }
>
> No self-respecting C++ compiler will compile this. This is syntactically
> invalid.
>
>> The idea is that some code can compute partial results,
>> or to the effect of launching asynchronous requests
>>
>> void rr1(const std::string& s) {
>>
>> std::list<std::string> l1 = rr2(s);
>>
>> int i1 = rr3(s);
>> int i2 = rr4(s);
>>
>> int siz = l1.size(); // throw
>>
>> int i3 = rr5(i1, i2, l1.size());
>>
>> }
>
> What is "rr2"? What is "rr3"? What is "rr4"? What is "rr5"?
>
>> so the idea is the re-routine runs through statements
>> as long as the inputs are satisfied, then these
>
> What "inputs"? What does "satisfied" mean?
>
>> rr1, 2, 3, 4, 5 throw if their arguments are the
>> null_throwing type, and any library code access
>
> What does "null_throwing" mean?
>
> C++ is very complicated. When discussing C++ it is very important to be
> explicit and use consistent terms that are well-defined in C++.
>
> [deletia]
>
>> It's an idea for writing co-routines in the language
>
> You will do yourself a huge, huge favor, by forgetting everything about
> co-routines.
>
> co-routines are a solution in search of a problem.
>
> The only reason co-routines exist in C++ is because real execution
> threads absolutely suck raw eggs in Microsoft Windows, and Microsoft
> hijacked the standardization process to infect C++ with this co-routines
> bullshit just so that MS-Windows would finally have a multi-threading
> implementation model that does not suck.
>
>> This way then the re-routine sort of automatically
>> primes its asynchronous results in whatever results
>> getting to the invoked re-routines, "satisfied" or
>> "satisfying" inputs, so that they're initiated
>> with completion handlers to populate the monad
>> and push the next re-run or the re-routine to
>> the task queue, which flows in the otherwise
>> flow-of-control in the language exactly the same
>> each time until it itself actually completes
>> and calls back to the originating (initiating)
>> callback (completion handler).
>
> Go ask Microsoft. They invented all this bullshit. They can deal with
> it, by themselves.
>
>> (It's been a while, I need to learn C++ 11
>
> co-routines are not C++11.
>
Hey Sam, thanks for writing.
The, "re-routines", are not, "co-routines". They're a model
of cooperative multithreading, which sort of by definition
are a co-routine yet not a co-routine in the runtime with
language support, semantics of defined behavior.
Instead it's an approach to callbacks, and a monadic approach,
with the idea that the originator/initiator of the overall
asynchronous re-routine, actually expects the invocations of
the tasks to fail (to "quit"), with the side-effect that their
asynchronous dependencies (the results, the values of the callbacks)
are initiated, what on their becoming available, also add the
task of the re-routine back to the originator/initiator/executor
of the re-routine, that the invocation of the task after its
dependencies, the arguments are fulfilled and satisfying, for
each of the sub-routines also re-routines, or any library code,
then it gets all done as a model of cooperative multithreading,
while the routine is written with no syntax of the asynchronous
at all, and can be implemented either blocking as a routine or
non-blocking as a re-routine, with the same code of the routine.
The idea is that this sort of approach to cooperative multithreading
needs thread_local storage specifier, and, basically aspects to
instrument the routine with its semantics of memoizing its results
in the partial monad of the sub-routines' results in the re-launches,
that the re-routine invokes all its asynchronous dependencies going
along, those returning their memoized results if available else
these null-throwing placeholders while launching themselves,
that it results non-blocking routines in re-routines,
with nothing at all about the semantics of asynchrony or callback,
because in the aspect its implicit, in the language,
in the defined behavior of the language and runtime.
So, right, it's not runtime or library coroutines or in the language
anything at all with the semantics of asynchrony, the idea is
re-routines that can be sort of implemented in regards to there
being virtual functions for these aspects, and thread_local storage,
and threads, for a pattern (anti-pattern) of non-blocking re-routines.
So, I suppose that would require C++ 11 for threads and thread_local,
while, otherwise it would be a usual simple sort of portability layer.
(Or as with regards to some conventions about ifdef and ifndef in
the language of m4 with regards to "portability", from basically
that writing network code for POSIX and Windows involves one.)
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2024-04-23 22:08 -0400 |
| Message-ID | <cone.1713924500.272635.96311.1004@monster.email-scan.com> |
| In reply to | #118842 |
Ross Finlayson writes: > The idea is that this sort of approach to cooperative multithreading > needs thread_local storage specifier, and, basically aspects to > instrument the routine with its semantics of memoizing its results > in the partial monad of the sub-routines' results in the re-launches, > that the re-routine invokes all its asynchronous dependencies going > along, those returning their memoized results if available else > these null-throwing placeholders while launching themselves, > that it results non-blocking routines in re-routines, > with nothing at all about the semantics of asynchrony or callback, > because in the aspect its implicit, in the language, > in the defined behavior of the language and runtime. > > So, right, it's not runtime or library coroutines or in the language > anything at all with the semantics of asynchrony, the idea is > re-routines that can be sort of implemented in regards to there > being virtual functions for these aspects, and thread_local storage, > and threads, for a pattern (anti-pattern) of non-blocking re-routines. > > So, I suppose that would require C++ 11 for threads and thread_local, > while, otherwise it would be a usual simple sort of portability layer. That's a little bit above my pay grade. I am focused on the narrow question of "how to make an object that throws", upon "access". I'm very confident that there is a C++ answer to this question, as soon as "access" gets defined concisely, using C++ terms and terminology.
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-23 20:07 -0700 |
| Message-ID | <QMmcnc7jD_z76rX7nZ2dnZfqn_ednZ2d@giganews.com> |
| In reply to | #118848 |
On 04/23/2024 07:08 PM, Sam wrote: > Ross Finlayson writes: > >> The idea is that this sort of approach to cooperative multithreading >> needs thread_local storage specifier, and, basically aspects to >> instrument the routine with its semantics of memoizing its results >> in the partial monad of the sub-routines' results in the re-launches, >> that the re-routine invokes all its asynchronous dependencies going >> along, those returning their memoized results if available else >> these null-throwing placeholders while launching themselves, >> that it results non-blocking routines in re-routines, >> with nothing at all about the semantics of asynchrony or callback, >> because in the aspect its implicit, in the language, >> in the defined behavior of the language and runtime. >> >> So, right, it's not runtime or library coroutines or in the language >> anything at all with the semantics of asynchrony, the idea is >> re-routines that can be sort of implemented in regards to there >> being virtual functions for these aspects, and thread_local storage, >> and threads, for a pattern (anti-pattern) of non-blocking re-routines. >> >> So, I suppose that would require C++ 11 for threads and thread_local, >> while, otherwise it would be a usual simple sort of portability layer. > > That's a little bit above my pay grade. I am focused on the narrow > question of "how to make an object that throws", upon "access". I'm very > confident that there is a C++ answer to this question, as soon as > "access" gets defined concisely, using C++ terms and terminology. > Zhengyi Fu pointed out that gcc has an option that for non-deferred signals that are trapped that they can be made to throw a std::exception in a non-portable manner, while, gcc is very widely implemented so it's pretty portable, -fnon-call-exceptions. Then, there's a notion that on Windows, there's ye olde Structured Exception Handling, which it is said can catch what would be segfault in the way that it is that it somehow employs setjmp/longjmp or rather as how SEH works, to make it so that dereferencing null would throw an exception instead of raising segfault. (Dereferencing/dereference-ing.) I would just hope to wonder and know that stack-unwinding or the usual defined behavior or throwing a std::exception or the behavior of throw was alright this way. What it seems is the signal handler just has synthesized a throw right there, as with regards to a bit of stack-magic where of course, "there is no magic, there is only logic", then that SEH accomplishes a same sort of thing. (Not sure how to have SEH handler throw a std::exception.) So, maybe there's, "a way", here still looking for, "a way, defined in the language". Hey thanks bud, I also am not quite sure otherwise how to go about "making an object, assignable to any lvalue according to a cast to its type, that when accessed, throws, unwinding the stack in normal defined behavior". It's appreciated that you are welcome to reject errancy, so, thanks. I would rather be told wrong than wrongly think right. So, we are still looking for a right sort of way, to make an object, as an rvalue assignable to any lvalue, that when "accessed", meaning any interaction at all that doesn't just treat it like an assignment, and thinking that assignment is only pointer or value assignment: that it throws. (Rather than causing a hardware fault and patching up that it's alright.)
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-23 22:10 -0700 |
| Message-ID | <oiidnX7J2LfLCbX7nZ2dnZfqnPednZ2d@giganews.com> |
| In reply to | #118849 |
On 04/23/2024 08:07 PM, Ross Finlayson wrote: > On 04/23/2024 07:08 PM, Sam wrote: >> Ross Finlayson writes: >> >>> The idea is that this sort of approach to cooperative multithreading >>> needs thread_local storage specifier, and, basically aspects to >>> instrument the routine with its semantics of memoizing its results >>> in the partial monad of the sub-routines' results in the re-launches, >>> that the re-routine invokes all its asynchronous dependencies going >>> along, those returning their memoized results if available else >>> these null-throwing placeholders while launching themselves, >>> that it results non-blocking routines in re-routines, >>> with nothing at all about the semantics of asynchrony or callback, >>> because in the aspect its implicit, in the language, >>> in the defined behavior of the language and runtime. >>> >>> So, right, it's not runtime or library coroutines or in the language >>> anything at all with the semantics of asynchrony, the idea is >>> re-routines that can be sort of implemented in regards to there >>> being virtual functions for these aspects, and thread_local storage, >>> and threads, for a pattern (anti-pattern) of non-blocking re-routines. >>> >>> So, I suppose that would require C++ 11 for threads and thread_local, >>> while, otherwise it would be a usual simple sort of portability layer. >> >> That's a little bit above my pay grade. I am focused on the narrow >> question of "how to make an object that throws", upon "access". I'm very >> confident that there is a C++ answer to this question, as soon as >> "access" gets defined concisely, using C++ terms and terminology. >> > > Zhengyi Fu pointed out that gcc has an option that for non-deferred > signals that are trapped that they can be made to throw a std::exception > in a non-portable manner, while, gcc is very widely implemented so it's > pretty portable, -fnon-call-exceptions. > > Then, there's a notion that on Windows, there's ye olde Structured > Exception Handling, which it is said can catch what would be segfault in > the way that it is that it somehow employs setjmp/longjmp or rather > as how SEH works, to make it so that dereferencing null would > throw an exception instead of raising segfault. > > (Dereferencing/dereference-ing.) > > I would just hope to wonder and know that stack-unwinding or > the usual defined behavior or throwing a std::exception or > the behavior of throw was alright this way. What it seems > is the signal handler just has synthesized a throw right there, > as with regards to a bit of stack-magic where of course, > "there is no magic, there is only logic", then that SEH > accomplishes a same sort of thing. (Not sure how to > have SEH handler throw a std::exception.) > > So, maybe there's, "a way", here still looking for, > "a way, defined in the language". > > > Hey thanks bud, I also am not quite sure otherwise how to go > about "making an object, assignable to any lvalue according > to a cast to its type, that when accessed, throws, > unwinding the stack in normal defined behavior". > > It's appreciated that you are welcome to reject errancy, so, thanks. > I would rather be told wrong than wrongly think right. > > > So, we are still looking for a right sort of way, to > make an object, as an rvalue assignable to any lvalue, > that when "accessed", meaning any interaction at all > that doesn't just treat it like an assignment, and thinking > that assignment is only pointer or value assignment: > that it throws. > > (Rather than causing a hardware fault and patching up > that it's alright.) > > It looks like it would get all involved with the copy and move semantics of overloading '=', then I'm wondering if that besides user-defined types of copy and move semantics then there's something like this "library solution" its "helper classes" what with regards to those being having semantics how they deal with objects according to those, of these C++ 11 lvalue and rvalue references then separating what's "assignment" from what's "access". There's a type trait it's said called remove_reference, then though as regards to the declaration what results that these "re-routines" their method would sort of result being ignorant what's otherwise the intended implementation of efficient copy and move semantics, resulting assignment is sort of naive, then still there's what about how to determine what is "access" of any sort otherwise, and throwing on it. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html https://en.cppreference.com/w/cpp/types/remove_reference Then I'd sort of wonder whether template definition would result convincing the compiler that a returned rvalue, whether or not it was an lvalue, then with respect to that getting assigned transitively, would lose that as soon as it was an lvalue, here just trying to figure out an object, cast-able to any type, that wouldn't throw on usual copy and move assignments, yet would throw on any otherwise access. There's std::decay associated with std::bind, https://en.cppreference.com/w/cpp/types/decay that I wonder how it would perform, "type conversions", resulting an object of some type. https://en.cppreference.com/w/cpp/language/implicit_conversion https://en.cppreference.com/w/cpp/language/value_category https://en.cppreference.com/w/cpp/language/value_category#History (There's a link to a paper from the author of the C++ book about the terminology of these value categories terminology.pdf .) Wow, value categories are widely expanded in C++ 11. "The assignment operator (operator=) has special properties: see copy assignment and move assignment for details. " - https://en.cppreference.com/w/cpp/language/operators I suppose in this kind of example, it's just that "re-routines return std::future", a sort of least accommodation of asynchronous routine. Yet, then the first get()/wait(), in this example would throw, to quit the re-routine as it would be re-alunched when get()/wait() would actually be fulfilled, while I want entire iterations to just invoke as if nothing was wrong or missing, so that all the asynchronous requests get queued off as in sort of automatically in parallel. See, I want to write the routines, as usual, plain, synchronous code, in the domain types and the library types, or standard, and agnostic of asynchrony. Then, std::future has that it can be extended and had returned whatever implements std::future, yet get() which calls wait() would have to return something that can be assigned or an rvalue of some sort that's "MoveConstructible", of the library type when it is, then to throw after the requests are iterated, so that they are all pending and on the way. Then, it seems sort of intractable to make for all the relevant library types to return "an assignable rvalue", "that throws on anything besides copy/move assignment", and that otherwise the re-routines would just be all in domain types that have it that they have sub-types each defined that happen to behave this way, a bit of boilerplate. The goal is "routines written in usual, plain, synchronous code that also have implementations that are functionally asynchronous, re-routines". Then if there's a way to make it so that values can be assigned, and transitively, then that those both have a way to determine whether they're fake and "null-throwing", and also throw when they're accessed by anything that isn't assignment, is a sort of anti-pattern on the expectations of objects of a type, to solve a sort of anti-pattern on the definition of routine that is synchronous. Hey thanks. Figuring to just "return 0 and catch segfault", is not-want, while there is a great perceived good thing in "routine written as purely declarative and procedural, synchronous", with, "re-routines according to the same flow-of-control, make the asynchronous requests while returning un-usable objects". In "the other language" I'm a lot less worried about it because assignment passes nulls along and that's how it is. If I was just dealing with pointers then assignment passes nulls along and that's how it is. The modern way of copy and move semantics vis-a-vis, return value optimization, and that's always sort of bother me also, yet, having "in-place" allocators and these things sort of not on the library types and they have these ones, has that I'm looking for way to make it so that library types have a constant value of their type that passes along according to move and copy semantics, that throws on anything else, a sort of "lazy throws quit". So, where "null is an unusable object, though, you can pass it along in assignment", has that copy/move expect well-formed objects to copy/move, for some "experimental::unusable<T>" that is a copyable/movable, otherwise unusable object otherwise meeting T. Or, you know, "write re-routines in pointers" and "catch segfault". Hey thanks, warm regards.
[toc] | [prev] | [next] | [standalone]
| From | Zhengyi Fu <i@fuzy.me> |
|---|---|
| Date | 2024-04-23 11:08 +0800 |
| Message-ID | <87wmoon5d3.fsf@fuzy.me> |
| In reply to | #118826 |
Ross Finlayson <ross.a.finlayson@gmail.com> writes:
> Hello I hope I might consult your expertise, I'm wondering about
> a use-case where for a given library object, to provide an instance
> of same type, that on any access, throws an exception.
>
> The idea is that there's an idea in a different language where
> the runtime throws a null_pointer_dereference exception
> when dereferencing a null pointer, yet in C++ it's signal segfault.
>
> So, what I wonder about is how to make an object in C++,
> of a given standard library type, and any arbitrary type,
> that on any access, throws.
>
> I suppose I might static_cast an object yet I wonder how
> to make it so then that any access to it throws.
>
> As you might imagine it's a use-case for exceptions
> as part of flow-of-control, that in the other language
> just is null yet in C++ would be for "an object of all types",
> that throws on any access.
>
I believe there is no portable way to implement this.
However, if you are running GCC on supported platforms, you can try
the `-fnon-call-exceptions` option.
--8<---------------cut here---------------start------------->8---
// main.cpp
#include <sys/types.h>
#include <signal.h>
#include <iostream>
#include <exception>
extern "C" void handle_signal(int signum) {
throw std::runtime_error("Invalid access");
}
int main()
{
struct sigaction act;
act.sa_handler = &handle_signal;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_NODEFER;
sigaction(SIGSEGV, &act, nullptr);
int *object = NULL;
try {
// write
*object = 100;
} catch (std::exception& exc) {
std::cerr << "Caught exception: " << exc.what() << '\n';
}
try {
// read
int value = *object;
std::cout << "value = " << value << '\n';
} catch (std::exception& exc) {
std::cerr << "Caught exception: " << exc.what() << '\n';
}
}
--8<---------------cut here---------------end--------------->8---
Compile the source file with
g++ -fnon-call-exceptions -o test main.cpp
Run ./test, it outputs
Caught exception: Invalid access
Caught exception: Invalid access
--
Zhengyi Fu
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-22 21:52 -0700 |
| Message-ID | <ZIKdnZz4YN8Po7r7nZ2dnZfqnPoAAAAA@giganews.com> |
| In reply to | #118829 |
On 04/22/2024 08:08 PM, Zhengyi Fu wrote:
> Ross Finlayson <ross.a.finlayson@gmail.com> writes:
>
>> Hello I hope I might consult your expertise, I'm wondering about
>> a use-case where for a given library object, to provide an instance
>> of same type, that on any access, throws an exception.
>>
>> The idea is that there's an idea in a different language where
>> the runtime throws a null_pointer_dereference exception
>> when dereferencing a null pointer, yet in C++ it's signal segfault.
>>
>> So, what I wonder about is how to make an object in C++,
>> of a given standard library type, and any arbitrary type,
>> that on any access, throws.
>>
>> I suppose I might static_cast an object yet I wonder how
>> to make it so then that any access to it throws.
>>
>> As you might imagine it's a use-case for exceptions
>> as part of flow-of-control, that in the other language
>> just is null yet in C++ would be for "an object of all types",
>> that throws on any access.
>>
>
> I believe there is no portable way to implement this.
>
> However, if you are running GCC on supported platforms, you can try
> the `-fnon-call-exceptions` option.
>
> --8<---------------cut here---------------start------------->8---
> // main.cpp
> #include <sys/types.h>
> #include <signal.h>
> #include <iostream>
> #include <exception>
>
> extern "C" void handle_signal(int signum) {
> throw std::runtime_error("Invalid access");
> }
>
> int main()
> {
> struct sigaction act;
> act.sa_handler = &handle_signal;
> sigemptyset(&act.sa_mask);
> act.sa_flags = SA_NODEFER;
> sigaction(SIGSEGV, &act, nullptr);
>
> int *object = NULL;
>
> try {
> // write
> *object = 100;
> } catch (std::exception& exc) {
> std::cerr << "Caught exception: " << exc.what() << '\n';
> }
>
> try {
> // read
> int value = *object;
> std::cout << "value = " << value << '\n';
> } catch (std::exception& exc) {
> std::cerr << "Caught exception: " << exc.what() << '\n';
> }
> }
> --8<---------------cut here---------------end--------------->8---
>
> Compile the source file with
>
> g++ -fnon-call-exceptions -o test main.cpp
>
> Run ./test, it outputs
>
> Caught exception: Invalid access
> Caught exception: Invalid access
>
Hey, that's great. Hey, thanks, that's kind
of good to know.
[toc] | [prev] | [next] | [standalone]
| From | wij <wyniijj5@gmail.com> |
|---|---|
| Date | 2024-04-25 02:56 +0800 |
| Message-ID | <d9a8168224d6e2ed50cc57e25ca044139ff6f3da.camel@gmail.com> |
| In reply to | #118829 |
On Tue, 2024-04-23 at 11:08 +0800, Zhengyi Fu wrote:
> Ross Finlayson <ross.a.finlayson@gmail.com> writes:
>
> > Hello I hope I might consult your expertise, I'm wondering about
> > a use-case where for a given library object, to provide an instance
> > of same type, that on any access, throws an exception.
> >
> > The idea is that there's an idea in a different language where
> > the runtime throws a null_pointer_dereference exception
> > when dereferencing a null pointer, yet in C++ it's signal segfault.
> >
> > So, what I wonder about is how to make an object in C++,
> > of a given standard library type, and any arbitrary type,
> > that on any access, throws.
> >
> > I suppose I might static_cast an object yet I wonder how
> > to make it so then that any access to it throws.
> >
> > As you might imagine it's a use-case for exceptions
> > as part of flow-of-control, that in the other language
> > just is null yet in C++ would be for "an object of all types",
> > that throws on any access.
> >
>
> I believe there is no portable way to implement this.
>
> However, if you are running GCC on supported platforms, you can try
> the `-fnon-call-exceptions` option.
>
> --8<---------------cut here---------------start------------->8---
> // main.cpp
> #include <sys/types.h>
> #include <signal.h>
> #include <iostream>
> #include <exception>
>
> extern "C" void handle_signal(int signum) {
> throw std::runtime_error("Invalid access");
> }
>
> int main()
> {
> struct sigaction act;
> act.sa_handler = &handle_signal;
> sigemptyset(&act.sa_mask);
> act.sa_flags = SA_NODEFER;
> sigaction(SIGSEGV, &act, nullptr);
>
> int *object = NULL;
>
> try {
> // write
> *object = 100;
> } catch (std::exception& exc) {
> std::cerr << "Caught exception: " << exc.what() << '\n';
> }
>
> try {
> // read
> int value = *object;
> std::cout << "value = " << value << '\n';
> } catch (std::exception& exc) {
> std::cerr << "Caught exception: " << exc.what() << '\n';
> }
> }
> --8<---------------cut here---------------end--------------->8---
>
> Compile the source file with
>
> g++ -fnon-call-exceptions -o test main.cpp
>
> Run ./test, it outputs
>
> Caught exception: Invalid access
> Caught exception: Invalid access
>
Convert to program using libwy C++ library:
(Thanks, learned something.)
//--------- t.cpp
#include <Wy.stdio.h>
#include <Wy.signal.h>
using namespace Wy;
static void handle_signal(int signum) {
cerr << "handle_signal(" << signum << ")" WY_ENDL;
WY_THROW( Errno(EFAULT) );
}
int main() {
Errno r;
if((r=sigaction(SIGSEGV, SigAct(handle_signal,SigSet(),SA_NODEFER)))!=Ok) {
WY_THROW(r);
}
int *object = NULL;
try {
// write
*object = 100;
}
catch (Errno& e) {
cerr << "Caught exception: " << wrd(e) << WY_ENDL;
}
try {
// read
int value = *object;
cout << "value = " << value << WY_ENDL;
}
catch (Errno& e) {
cerr << "Caught exception: " << wrd(e) << WY_ENDL;
}
};
//------------------------------
[]$ g++ -fnon-call-exceptions t.cpp -lwy
[]$ ./a.out
handle_signal(11)
Caught exception: Bad address, t.cpp(53)
handle_signal(11)
Caught exception: Bad address, t.cpp(53)
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-24 12:02 -0700 |
| Message-ID | <6MqdnSF2kuCuyrT7nZ2dnZfqn_GdnZ2d@giganews.com> |
| In reply to | #118871 |
On 04/24/2024 11:56 AM, wij wrote:
> On Tue, 2024-04-23 at 11:08 +0800, Zhengyi Fu wrote:
>> Ross Finlayson <ross.a.finlayson@gmail.com> writes:
>>
>>> Hello I hope I might consult your expertise, I'm wondering about
>>> a use-case where for a given library object, to provide an instance
>>> of same type, that on any access, throws an exception.
>>>
>>> The idea is that there's an idea in a different language where
>>> the runtime throws a null_pointer_dereference exception
>>> when dereferencing a null pointer, yet in C++ it's signal segfault.
>>>
>>> So, what I wonder about is how to make an object in C++,
>>> of a given standard library type, and any arbitrary type,
>>> that on any access, throws.
>>>
>>> I suppose I might static_cast an object yet I wonder how
>>> to make it so then that any access to it throws.
>>>
>>> As you might imagine it's a use-case for exceptions
>>> as part of flow-of-control, that in the other language
>>> just is null yet in C++ would be for "an object of all types",
>>> that throws on any access.
>>>
>>
>> I believe there is no portable way to implement this.
>>
>> However, if you are running GCC on supported platforms, you can try
>> the `-fnon-call-exceptions` option.
>>
>> --8<---------------cut here---------------start------------->8---
>> // main.cpp
>> #include <sys/types.h>
>> #include <signal.h>
>> #include <iostream>
>> #include <exception>
>>
>> extern "C" void handle_signal(int signum) {
>> throw std::runtime_error("Invalid access");
>> }
>>
>> int main()
>> {
>> struct sigaction act;
>> act.sa_handler = &handle_signal;
>> sigemptyset(&act.sa_mask);
>> act.sa_flags = SA_NODEFER;
>> sigaction(SIGSEGV, &act, nullptr);
>>
>> int *object = NULL;
>>
>> try {
>> // write
>> *object = 100;
>> } catch (std::exception& exc) {
>> std::cerr << "Caught exception: " << exc.what() << '\n';
>> }
>>
>> try {
>> // read
>> int value = *object;
>> std::cout << "value = " << value << '\n';
>> } catch (std::exception& exc) {
>> std::cerr << "Caught exception: " << exc.what() << '\n';
>> }
>> }
>> --8<---------------cut here---------------end--------------->8---
>>
>> Compile the source file with
>>
>> g++ -fnon-call-exceptions -o test main.cpp
>>
>> Run ./test, it outputs
>>
>> Caught exception: Invalid access
>> Caught exception: Invalid access
>>
>
> Convert to program using libwy C++ library:
> (Thanks, learned something.)
>
> //--------- t.cpp
> #include <Wy.stdio.h>
> #include <Wy.signal.h>
>
> using namespace Wy;
>
> static void handle_signal(int signum) {
> cerr << "handle_signal(" << signum << ")" WY_ENDL;
> WY_THROW( Errno(EFAULT) );
> }
>
> int main() {
> Errno r;
>
> if((r=sigaction(SIGSEGV, SigAct(handle_signal,SigSet(),SA_NODEFER)))!=Ok) {
> WY_THROW(r);
> }
>
> int *object = NULL;
>
> try {
> // write
> *object = 100;
> }
> catch (Errno& e) {
> cerr << "Caught exception: " << wrd(e) << WY_ENDL;
> }
>
> try {
> // read
> int value = *object;
> cout << "value = " << value << WY_ENDL;
> }
> catch (Errno& e) {
> cerr << "Caught exception: " << wrd(e) << WY_ENDL;
> }
>
> };
>
> //------------------------------
> []$ g++ -fnon-call-exceptions t.cpp -lwy
> []$ ./a.out
> handle_signal(11)
> Caught exception: Bad address, t.cpp(53)
> handle_signal(11)
> Caught exception: Bad address, t.cpp(53)
>
>
>
It seems the current these days is "not exceptions", that
instead the drift is toward "Result<T, E>" or "std::expected<T, E>"
as for a sort of poor-man's covariant return types, combined
with a sort of type-enforced error handling as good old error
codes vis-a-vis usual old notions of reserved ranges in integer
return codes. (... Cluttering everything everywhere with
handler code.)
What with C++ "removing exception specifications" it's sort
of figured they won't be back, and all that remains is throw
and nothrow, renamed noexcept. (... Cluttering the line.)
Covariant return types is a usual sort of thing not present
in usual languages. Dealing with "variant" and "union"
and these type things, as representing "objects" of the
usual sorts of language of the data in, "data", or rather
associative arrays usually but really a union or variant
type, which is a union type with a variant type tag,
or "nested object data", it's not an usual idea for
something like "the routine returns an instance of T"
and "the routine throws an exception which may
contain an instance of E" vis-a-vis "the routine returns
an expected<T, E> which has either/or T, E, hope-ful-ly".
So yeah though exception-specification really makes
for an entire complement of things about the types
of the signatures, expected state before/after and
how it's expected to be broken and how it's expected
to be recoverable and howso it would unwind the stack,
from where-ever in the entire stack an error arises,
it seems just dropping exception-specification in C++ 20,
results a reduced expressitivity of the specification of the
intent, and, the intent of the specification.
"Oh, well you just change everything back to
checking the status code everywhere." "Oh, so,
what happens when some routine results a fault?"
"Die." "Well that seems a bit extreme...,
I'm expecting these exceptions."
Just seems they figure to declutter the exception-specification
to clutter all the signature argument and return types as expected
and just usually die unexpectedly. I don't get it. I mean, I get it,
yet, the exception-specification really expresses the intent
and what it can handle, and anywhere in the stack what must be.
Then, unrecoverable errors or the "on the way to the exit",
it sort of helps usually "let me log you on your way out".
For plain, neat, usual, un-cluttered happy-case synchronous routine.
(And type-safe covariant return, fault, and exception handling.)
I mean if it's just like "fork C++, one with exception-specifications,
and a base hierarchy or recoverable and unrecoverable exceptions,
if I was dieing I'd want to get the tag of the flaming bus that hit me".
I.e., "panic", is not an option.
Let's see, what does Eiffel think about it.
https://www.eiffel.org/doc/solutions/Exception_Mechanism
Eiffel is like Ruby and has exceptions and "raise/rescue" like "try/catch".
(... And for "finally".)
https://en.wikipedia.org/wiki/Eiffel_(programming_language)
"Exception handling in Eiffel is based on the
principles of design by contract. For example,
an exception occurs when a routine's caller
fails to satisfy a precondition, or when a
routine cannot ensure a promised postcondition."
-
https://en.wikipedia.org/wiki/Eiffel_(programming_language)#Exception_handling
Then, I'd just aver the re-routines don't throw exceptions for
flow-of-control, as rather they just indicate a pending unsatisfied
postcondition which is retryable.
...With exceptions, and when to fail, for example when the time is expired.
... All non-blockingly.
https://en.wikibooks.org/wiki/Ada_Programming/Exceptions
"When an exception occurs, the normal flow of execution is abandoned
and the exception is handed up the call sequence until a matching
handler is found."
Ada throws exceptions ..., these things say exceptions are the
way of making "robustness" after something like RAII makes "correctness".
When "panic and die" isn't correct, ....
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-24 13:56 -0700 |
| Message-ID | <EyydneQoZr6e77T7nZ2dnZfqnPWdnZ2d@giganews.com> |
| In reply to | #118829 |
On 04/24/2024 12:26 PM, Stefan Ram wrote:
> Zhengyi Fu <i@fuzy.me> wrote or quoted:
>> int *object = NULL;
>
> This seems to be what's helping the OP, but when you consider
> that the subject line is "how to make an object that throws",
> you'd actually have to say that the thrower here is not an
> object, but rather the /absence of an object/.
>
> This of course has to do with how objects are specified.
>
> In C++, an expression can stand directly for an object, so
> an assignment copies that object. In other languages, objects
> are always implicitly specified by references/pointers, and
> an assignment copies that reference/pointer. This can make it
> appear sometimes as if a reference/pointer is an object.
>
One thing I wonder, is, that if move semantics "may"
result that the rvalue is un-usable, or copying the
member pointers from the temporary to the object
in the scope to be destructed when the scope concludes,
making unusable the temporary by nulling its member pointers,
then I wonder if that's allowed and whether it "must",
so make un-usable the rvalue, and whether, also, that
copy and move semantics on un-usable objects, result,
the same nulled-out member-pointer, un-usable objects,
though being assigned transitively alright.
Then I read there's a current specification incoming to
the language that would prevent objects from being
copied/moved from nulled-out member-pointer
un-usable objects, so it's not something reliable when
the guarantee would otherwise be "pass along this
object its reference or reference reference or pointer
or scalar built-in value, assignment" while "as an un-usable
nulled-out member-pointer object any access is expected
to segfault".
I.e., I wonder if I can return a dummy by constructing an
empty, invoking a move off it to null-out its member-pointers,
then return that from the routine so that then its assignment
as from its value category, resulting a sort of "exploding dummy".
I.e., what's in mind is a sort of "experimental::unusable<T>" that is
sort of like "std::identity<T>" or as an instance of T, that doesn't
fault on assignment, but faults on otherwise access on its
members, or member-pointers.
What I figure is that the re-routine is a pattern for cooperative
multithreading, with usual and plain synchronous definition of
flow-of-control, and in types and in the language, that is always a
task, that the originator/initiator of the re-routine, puts on a task
queue TQ the re-routine, then that the re-routine, "falls through",
executing, that the re-routines it calls, either get a usable object and
return an unusable return value, or as what they block and compute, or
get an unusable object and throw "quit".
The idea is that the very first time a re-routine is called with a
usable object, it kicks off its asynchronous invocation, while in the
thread_local that it has in the mixin class of re-routine, in the
"monad" of the accumulating usable return values, it stashes what it
constructs as an "unusable" object. So, there are sub-routines as
plain routine, and sub-routines as blocking or non-blocking
implementors, all the same code the same routine.
The callback of the asynchronous call, with a handle to the monad and
the invoker's path in the monad, and to the TQ, populates the monad (the
accumulating results) and (re-)submits the re-routine to the TQ, which
repeats or complete. When complete, if it is an original re-routine,
invokes the callback of the originating task, or if it is a
sub-re-routine, it adds the invoking re-routine, back to the TQ, which
now again "falls through" yet getting the usable object from the monad,
instead of the unusable object, and continues.
void rr0(int i1) {
string s1 = rr1(i1);
string s2 = rr2(i1);
string s3 = rr3(i1);
string s4 = rr4(s1, s2, s3);
}
I sort of figure that rr 1, 2, 3, "fall through", where i1 is usable,
make their asynchronous requests, and return "unusable" s 1 2 3.
Then, rr4 gets any unusable s 1 2 3 and throws quit, the re-routine
exits (throws, never blocking). The originating task queue TQ forgets
all about it. (Though, one figures that its timeouts are in the queue
behind it.)
So, at some point, rr 1, 2, 3 asynchronous requests, return and their
callback populates rr 1, 2, 3's monad, which is a member of the original
re-routine, so that now rr 1, 2, 3 have their return values (or,
exceptions) in the monad. The callback also throws the sub-re-routines'
super-re-routine, which happens to be the originating routine, back on
the TQ. When a consumer picks it off the TQ, it runs through again.
void rr0(int i1) {
string s1 = rr1(i1);
string s2 = rr2(i1);
string s3 = rr3(i1);
string s4 = rr4(s1, s2, s3);
return s4;
}
It starts all over again and runs through again, though now one or more
of s 1 2 3 are usable and in the monad thread_local, sp rr4 checks its
inputs and either throws quit or not, and if it doesn't, then it returns
an (unusable) sf4, having made its asynchronous request, the callback of
which will populate its monad and re-submit it's caller to the Task Queue.
Eventually then rr0 completes, or, throws anything besides a "quit",
"postcondition_pending". The originator takes that and calls back the
original callback initially constructed with the re-routine specification.
So, it expects something somewhere to accept a callback, then that the
idea is that the callbacks are non-blocking, and, the re-routines are
non-blocking, so whatever makes the originating calls, must have its own
thread(s), and whatever fulfills the asynchronous requests, must have
its own thread(s). Then all the re-routines get one thread, in as to
whether "re-routines are re-entrant". (It's figured that when a
re-routine concludes then its monad is marked a particular unusable
"concluded".)
So, what I hope to figure out for C++, is, a sort of
experimental::unusable<T>, that's MoveConstructible and
CopyConstructible, for the library objects, the standard objects, so
that the re-routine, can have any sort of other code in it, library
code, with the expectation that the contents of collections are always
in the same order, with regards to that the first time a sub-re-routine
is invoked with usable arguments, then its result from its monad will
always be as of those.
void rr0(int i1) {
// any library code
string s1 = rr1(i1);
string s2 = rr2(i1);
string s3 = rr3(i1);
// any library code
string s4 = rr4(s1, s2, s3);
// any library code
return s4;
}
Then, I understand that the library code will be run each time the
re-routine is re-run, and don't much care, if it's non-blocking, or when
it gets an unusable object that it throws quit.
If the library code is actually pretty heavyweight, then the idea is to
put it into a sub-re-routine, then it will just be run once otherwise
acting just like a usual sub-re-routine.
void rr0(int i1) {
string s1 = rr1(i1);
string s2 = rr2(i1);
string s3 = rr3(i1);
string s4 = rr4(s1, s2, s3);
return s4;
}
void rr1(int i1) {
idiomatic_boxed<double> d1 = rr1a(i1);
idiomatic_boxed<double> d2 = rr1b(i1);
idiomatic_boxed<double> d3 = rr1c(i1);
idiomatic_boxed<double> d4 = rr1d(i1);
return rr1s(d1, d2,d3, d4);
}
See, I sort of expect that this way, it looks just like a blocking,
synchronous routine, and for example could be implemented thusly, for a
thread that expects to just run and block its way through.
Also, the re-routine can run sub-re-routines for various values, they
get stored in the monad basically by serial order because according to
the same flow-of-control they always get invoked for the first time in
the same order, finding their spot in the monad to populate their return
value, while finding their depth and serial order in the monad where to
call back out homeward to the origin of the original re-routine.
So, I'm looking for in C++ "an object that throws", that is
CopyConstructible and MoveConstructible for any type, yet is otherwise
unusable, and can be determined unusable either by invoking anything on
it and throwing, or some mixin to detect it's unusable, some
"experimental:unusable<T>".
[toc] | [prev] | [next] | [standalone]
| From | Ross Finlayson <ross.a.finlayson@gmail.com> |
|---|---|
| Date | 2024-04-27 08:09 -0700 |
| Message-ID | <XJmcnXG6M66riLD7nZ2dnZfqnPqdnZ2d@giganews.com> |
| In reply to | #118877 |
On 04/24/2024 01:56 PM, Ross Finlayson wrote:
> On 04/24/2024 12:26 PM, Stefan Ram wrote:
>> Zhengyi Fu <i@fuzy.me> wrote or quoted:
>>> int *object = NULL;
>>
>> This seems to be what's helping the OP, but when you consider
>> that the subject line is "how to make an object that throws",
>> you'd actually have to say that the thrower here is not an
>> object, but rather the /absence of an object/.
>>
>> This of course has to do with how objects are specified.
>>
>> In C++, an expression can stand directly for an object, so
>> an assignment copies that object. In other languages, objects
>> are always implicitly specified by references/pointers, and
>> an assignment copies that reference/pointer. This can make it
>> appear sometimes as if a reference/pointer is an object.
>>
>
>
> One thing I wonder, is, that if move semantics "may"
> result that the rvalue is un-usable, or copying the
> member pointers from the temporary to the object
> in the scope to be destructed when the scope concludes,
> making unusable the temporary by nulling its member pointers,
> then I wonder if that's allowed and whether it "must",
> so make un-usable the rvalue, and whether, also, that
> copy and move semantics on un-usable objects, result,
> the same nulled-out member-pointer, un-usable objects,
> though being assigned transitively alright.
>
> Then I read there's a current specification incoming to
> the language that would prevent objects from being
> copied/moved from nulled-out member-pointer
> un-usable objects, so it's not something reliable when
> the guarantee would otherwise be "pass along this
> object its reference or reference reference or pointer
> or scalar built-in value, assignment" while "as an un-usable
> nulled-out member-pointer object any access is expected
> to segfault".
>
> I.e., I wonder if I can return a dummy by constructing an
> empty, invoking a move off it to null-out its member-pointers,
> then return that from the routine so that then its assignment
> as from its value category, resulting a sort of "exploding dummy".
>
> I.e., what's in mind is a sort of "experimental::unusable<T>" that is
> sort of like "std::identity<T>" or as an instance of T, that doesn't
> fault on assignment, but faults on otherwise access on its
> members, or member-pointers.
>
>
> What I figure is that the re-routine is a pattern for cooperative
> multithreading, with usual and plain synchronous definition of
> flow-of-control, and in types and in the language, that is always a
> task, that the originator/initiator of the re-routine, puts on a task
> queue TQ the re-routine, then that the re-routine, "falls through",
> executing, that the re-routines it calls, either get a usable object and
> return an unusable return value, or as what they block and compute, or
> get an unusable object and throw "quit".
>
> The idea is that the very first time a re-routine is called with a
> usable object, it kicks off its asynchronous invocation, while in the
> thread_local that it has in the mixin class of re-routine, in the
> "monad" of the accumulating usable return values, it stashes what it
> constructs as an "unusable" object. So, there are sub-routines as
> plain routine, and sub-routines as blocking or non-blocking
> implementors, all the same code the same routine.
>
> The callback of the asynchronous call, with a handle to the monad and
> the invoker's path in the monad, and to the TQ, populates the monad (the
> accumulating results) and (re-)submits the re-routine to the TQ, which
> repeats or complete. When complete, if it is an original re-routine,
> invokes the callback of the originating task, or if it is a
> sub-re-routine, it adds the invoking re-routine, back to the TQ, which
> now again "falls through" yet getting the usable object from the monad,
> instead of the unusable object, and continues.
>
> void rr0(int i1) {
> string s1 = rr1(i1);
> string s2 = rr2(i1);
> string s3 = rr3(i1);
>
> string s4 = rr4(s1, s2, s3);
> }
>
> I sort of figure that rr 1, 2, 3, "fall through", where i1 is usable,
> make their asynchronous requests, and return "unusable" s 1 2 3.
>
> Then, rr4 gets any unusable s 1 2 3 and throws quit, the re-routine
> exits (throws, never blocking). The originating task queue TQ forgets
> all about it. (Though, one figures that its timeouts are in the queue
> behind it.)
>
> So, at some point, rr 1, 2, 3 asynchronous requests, return and their
> callback populates rr 1, 2, 3's monad, which is a member of the original
> re-routine, so that now rr 1, 2, 3 have their return values (or,
> exceptions) in the monad. The callback also throws the sub-re-routines'
> super-re-routine, which happens to be the originating routine, back on
> the TQ. When a consumer picks it off the TQ, it runs through again.
>
> void rr0(int i1) {
> string s1 = rr1(i1);
> string s2 = rr2(i1);
> string s3 = rr3(i1);
>
> string s4 = rr4(s1, s2, s3);
>
> return s4;
> }
>
>
> It starts all over again and runs through again, though now one or more
> of s 1 2 3 are usable and in the monad thread_local, sp rr4 checks its
> inputs and either throws quit or not, and if it doesn't, then it returns
> an (unusable) sf4, having made its asynchronous request, the callback of
> which will populate its monad and re-submit it's caller to the Task Queue.
>
> Eventually then rr0 completes, or, throws anything besides a "quit",
> "postcondition_pending". The originator takes that and calls back the
> original callback initially constructed with the re-routine specification.
>
> So, it expects something somewhere to accept a callback, then that the
> idea is that the callbacks are non-blocking, and, the re-routines are
> non-blocking, so whatever makes the originating calls, must have its own
> thread(s), and whatever fulfills the asynchronous requests, must have
> its own thread(s). Then all the re-routines get one thread, in as to
> whether "re-routines are re-entrant". (It's figured that when a
> re-routine concludes then its monad is marked a particular unusable
> "concluded".)
>
>
> So, what I hope to figure out for C++, is, a sort of
> experimental::unusable<T>, that's MoveConstructible and
> CopyConstructible, for the library objects, the standard objects, so
> that the re-routine, can have any sort of other code in it, library
> code, with the expectation that the contents of collections are always
> in the same order, with regards to that the first time a sub-re-routine
> is invoked with usable arguments, then its result from its monad will
> always be as of those.
>
> void rr0(int i1) {
>
> // any library code
>
> string s1 = rr1(i1);
> string s2 = rr2(i1);
> string s3 = rr3(i1);
>
> // any library code
>
> string s4 = rr4(s1, s2, s3);
>
> // any library code
>
> return s4;
> }
>
> Then, I understand that the library code will be run each time the
> re-routine is re-run, and don't much care, if it's non-blocking, or when
> it gets an unusable object that it throws quit.
>
> If the library code is actually pretty heavyweight, then the idea is to
> put it into a sub-re-routine, then it will just be run once otherwise
> acting just like a usual sub-re-routine.
>
> void rr0(int i1) {
> string s1 = rr1(i1);
> string s2 = rr2(i1);
> string s3 = rr3(i1);
>
> string s4 = rr4(s1, s2, s3);
>
> return s4;
> }
>
> void rr1(int i1) {
> idiomatic_boxed<double> d1 = rr1a(i1);
> idiomatic_boxed<double> d2 = rr1b(i1);
> idiomatic_boxed<double> d3 = rr1c(i1);
> idiomatic_boxed<double> d4 = rr1d(i1);
>
> return rr1s(d1, d2,d3, d4);
> }
>
> See, I sort of expect that this way, it looks just like a blocking,
> synchronous routine, and for example could be implemented thusly, for a
> thread that expects to just run and block its way through.
>
> Also, the re-routine can run sub-re-routines for various values, they
> get stored in the monad basically by serial order because according to
> the same flow-of-control they always get invoked for the first time in
> the same order, finding their spot in the monad to populate their return
> value, while finding their depth and serial order in the monad where to
> call back out homeward to the origin of the original re-routine.
>
> So, I'm looking for in C++ "an object that throws", that is
> CopyConstructible and MoveConstructible for any type, yet is otherwise
> unusable, and can be determined unusable either by invoking anything on
> it and throwing, or some mixin to detect it's unusable, some
> "experimental:unusable<T>".
>
>
>
>
I looked around a bit and the standard library has nothrow on
everything. That must be a great idea as it's defined behavior that
C++ objects are not un-usable.
So it seems the way that re-routine would have
std::future in all its return signatures. It both expresses
the action, and is not nothrow.
Then I figure the implementation of std::future of that
as rule-of-three + CopyConstructible + MoveConstructible
that as with regards to std::allocator and std::pmr::allocator,
it would result the semantics of std::future then as what
may throw, with well-defined stack-unwinding and module
boundaries of the sort of throw-less boundaries.
using std::future;
future<void> rr0 (int i1) {
future<string> s1 = rr1(i0);
future<string> s2 = rr2(i0);
future<string> s3 = rr3(i0);
return rr4(s1.get(), s2.get(), s3.get()).get();
}
where I'd hoped it would look like
void rr0 (int i1) {
string s1 = rr1(i0);
string s2 = rr2(i0);
string s3 = rr3(i0);
return rr4(s1, s2, s3);
}
with the idea that s 1 2 3 are queued off in parallel asynchronously
then that the re-routine rr0 populates a thread_local call-sequence
monad that the re-routines populate it as they get invoked with a static
exception and as their results come back from asynchronous execution
with the results or the exception, then that the std::future's get
implemented as from the thread_local monad that gets built in a serial
way because the flow-of-control's path is always the same and values are
always the same by logical value and any collection is ordered so
there's always a given offset where a re-routine adds to the monad, that
re-routines are as via callbacks implicitly everywhere, either results
that populate the re-routine and re-run its invoker, or returns that
re-run its re-routine caller, the original/originated re-routine
return making a callback <T, E> where "running a re-routine is itself
an asynchronous task", these being tasks. (The idea of any collection
that's not ordered is that it goes in its own re-routine, for example
built from parallel algorithms, however by library code, as what results
an un-ordered collection, or howsoever.)
About the idea of catching segfault and adding frame points and adding
the -f-non-call-exceptions or as with regards to how on Windows it's
already a thing and with regards to this kind of thing, that may be a
good idea if only to catch core dumps on the way out, or at least it's
good to know.
Thanks all, as "make an object that throws" is "you can make an object
that throws if it doesn't not throw", or as with regards to "there's no
experimental:unusable<T>".
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2024-04-25 14:08 -0700 |
| Message-ID | <86bk5xw3o5.fsf@linuxsc.com> |
| In reply to | #118829 |
ram@zedat.fu-berlin.de (Stefan Ram) writes: > Zhengyi Fu <i@fuzy.me> wrote or quoted: > >> int *object = NULL; > > This seems to be what's helping the OP, but when you consider > that the subject line is "how to make an object that throws", > you'd actually have to say that the thrower here is not an > object, but rather the /absence of an object/. > > This of course has to do with how objects are specified. > > In C++, an expression can stand directly for an object, so > an assignment copies that object. In other languages, In some other languages. Certainly not all other languages. > objects > are always implicitly specified by references/pointers, and > an assignment copies that reference/pointer. Some languages that use pointer semantics rather than using "objects" directly don't have a way to do assignment, so the question of what is copied is moot.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web