|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#26 |
|
Messages: n/a
Hébergeur: |
* gnuist006@gmail.com:
> On Oct 23, 9:33 am, Stefan Monnier <monn...@iro.umontreal.ca> wrote: >>> NOTE: I am really afraid of try-catch-throw. I have never been >>> able to understand it since it does not exist in C and I can't >>> really visualize the construct in terms of C. That is what my >> Actually, these constructs pretty much exist in C as well: `catch' is called >> `setjmp', and `throw' is called `longjmp'. >> >> Stefan > > Stefan, let me thank you for what seems to me to be the correct > concept. > I searched this whole thread in google for setjmp and YOU are the only > one who mentioned it. Uh, have you plonked me, then? I think that my reply was the very first reply in the thread. I suggest you read that article again, because it contains some important details not mentioned by Stefan et.al. - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#27 |
|
Messages: n/a
Hébergeur: |
On Oct 20, 3:55 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * gnuist...@gmail.com: > > > > > I have some code like this: > > > (if (test) > > (exit) > > (do something)) > > > or > > > (if (test) > > ( do something) > > (exit)) > > > Various levels of nestings. > > > I have several questions, basic to sophisticated. > > > (1) What is the lisp equivalent idiom for (exit) as in bash or > > in C. > > C++ does not have a built-in 'exit' command. There is a library > function 'exit' which exits the process. One must assume that's not > what you mean, and that you're not asking C and C++ programmers to teach > you Lisp. > > Therefore, assuming you want to exit the function or the block. > > > (2) What is the best practice to handle this kind of problems? > > It's not a general class of problem. > > Appropriate solutions depend on the problem at hand. > > E.g., in C++, > > // (if (test) (exit) (do something)) > > void foo() > { > if( !test ) > { > doSomething(); > } > } > > void bar() > { > if( test ) { return; } > doSomething(); > } > > > (3) What is the intermediate practice to handle this kind of > > problems. > > ? > > > NOTE: I am really afraid of try-catch-throw. I have never been > > able to understand it since it does not exist in C and I cant > > really visualize the construct in terms of C. That is what my > > brain can process. If you understand it so well, you can show > > me how one would really implement that kind of construct in > > C and then by extension I can see that kind of program flow > > in LISP. Whether its imperative programming or functional, > > beneath there is program counter and assembly. C is close > > to machine so much that it is almost assembly. So understanding try-c- > > t in C is equivalent to understanding at > > the level of machine language. > > The closest equivalent in C would be a 'longjmp'. However, a C++ > exception is more limited, in that it will only jump up the call chain, > and it's more powerful, in that it will destroy local objects as it does > so. Also, if you use 'longjmp' in C++ you're practically doomed (unless > you use it to jump between co-routines with their own stacks), because > 'longjmp' doesn't destroy local objects. Sure you have good ideas. I still would like an equivalent implementation explained. Ofcourse, smart companies and smart programmers were doing all this before C++ came and even in LISP they have atleast two of try catch throw. |
|
|
|
#28 |
|
Messages: n/a
Hébergeur: |
* gnuist006@gmail.com:
> On Oct 20, 3:55 pm, "Alf P. Steinbach" <al...@start.no> wrote: >> The closest equivalent in C would be a 'longjmp'. However, a C++ >> exception is more limited, in that it will only jump up the call chain, >> and it's more powerful, in that it will destroy local objects as it does >> so. Also, if you use 'longjmp' in C++ you're practically doomed (unless >> you use it to jump between co-routines with their own stacks), because >> 'longjmp' doesn't destroy local objects. > > Sure you have good ideas. Note that some people could read that as an attempt at insulting. > I still would like an equivalent implementation explained. Ofcourse, > smart > companies and smart programmers were doing all this before C++ came > and even in LISP they have atleast two of try catch throw. Ada introduced to the wider community much that was subsequently adopted in C++. Interestingly, (much of) the STL was implemented in Ada before it was implemented in C++. And perhaps also interestingly, Ada's high level thread primitives are seemingly now /not/ considered for C++. Now as for equivalence, you don't really want C code, because that would have to emulate C++ objects! But in C++ such longjm-based code is hairy compiler-dependent stuff, with formally Undefined Behavior. Also, as an example of equivalent-except-for-efficiency, note that a call of a virtual function can be specified equivalently as a dynamic lookup in most derived class, base class, base class' base class and so on, a search up the base class chain, but is in actuality implemented as a table look-up (with all compilers). Exceptions are implemented in more than just one main way. However, analogously to the case with virtual functions, equivalent code that performs dynamic lookup, such as the code below, is extremely ineffecient compared to the Real Thing(TM). Depending on the actual implementation of exceptions, there can be no overhead at all for normal case code. <code> #include <vector> #include <csetjmp> #include <string> #include <iostream> #include <ostream> #if defined( _MSC_VER ) # define LNGJMP_DESTROYS_AUTOMAGICALLY #elif defined( __GNUC__ ) # undef LNGJMP_DESTROYS_AUTOMAGICALLY # // No automatic destruction, at least in MingW 3.4.4 version. #else # error Your compiler is not supported by this program. #endif struct AbstractLngjmpCleanup { virtual ~AbstractLngjmpCleanup() {} virtual void destroy() = 0; }; template< typename T > struct LngjmpCleanup: AbstractLngjmpCleanup { T* myTarget; LngjmpCleanup( T& target ): myTarget( &target ) {} virtual void destroy() { #ifndef LNGJMP_DESTROYS_AUTOMAGICALLY myTarget->T::~T(); // Call destructor on target. #endif } }; struct LongjmpCleanups { std::vector<AbstractLngjmpCleanup*> myDestroyers; ~LongjmpCleanups() { for( size_t i = 0; i < myDestroyers.size(); ++i ) { delete myDestroyers.at( i ); } } template< typename T > void add( T& target ) { myDestroyers.push_back( new LngjmpCleanup<T>( target ) ); } void destroyAll() { for( size_t i = 0; i < myDestroyers.size(); ++i ) { myDestroyers.at( i )->destroy(); } } }; template< typename T > void say( T const& v ) { std::cout << v << std::endl; } struct Whatever { std::string myId; Whatever( std::string id ): myId( id ) { say( "Constructed " + myId + "." ); } ~Whatever() { say( "Destroyed " + myId + "." ); } }; jmp_buf* pReturnAddress = 0; void bottom() { LongjmpCleanups destroyers; LngjmpCleanup<LongjmpCleanups> destroyersDestroyer( destroyers ); Whatever localObject( "bottom()'s local object" ); destroyers.add( localObject ); say( "Executing body of bottom()." ); say( "Throwing simulated exception." ); { destroyers.destroyAll(); destroyersDestroyer.destroy(); longjmp( *pReturnAddress, 1 ); } } void middle() { jmp_buf returnAddress; jmp_buf* pOldReturnAddress; LongjmpCleanups destroyers; LngjmpCleanup<LongjmpCleanups> destroyersDestroyer( destroyers ); Whatever localObject( "middle()'s local object" ); destroyers.add( localObject ); pOldReturnAddress = pReturnAddress; if( setjmp( returnAddress ) == 0 ) { pReturnAddress = &returnAddress; say( "Executing body of middle(), calling bottom()." ); bottom(); pReturnAddress = pOldReturnAddress; } else { destroyers.destroyAll(); destroyersDestroyer.destroy(); pReturnAddress = pOldReturnAddress; longjmp( *pReturnAddress, 1 ); } } void top() { jmp_buf returnAddress; jmp_buf* pOldReturnAddress; LongjmpCleanups destroyers; LngjmpCleanup<LongjmpCleanups> destroyersDestroyer( destroyers ); Whatever localObject( "top()'s local object" ); destroyers.add( localObject ); pOldReturnAddress = pReturnAddress; if( setjmp( returnAddress ) == 0 ) { pReturnAddress = &returnAddress; say( "Executing body of top(), calling middle()." ); middle(); pReturnAddress = pOldReturnAddress; } else { destroyers.destroyAll(); destroyersDestroyer.destroy(); pReturnAddress = pOldReturnAddress; longjmp( *pReturnAddress, 1 ); } } int main() { jmp_buf returnAddress; pReturnAddress = &returnAddress; if( setjmp( returnAddress ) == 0 ) { say( "Main business code, calling top()..." ); top(); return EXIT_SUCCESS; } else { say( "Caught simulated exception!" ); return EXIT_FAILURE; } } </code> <output> Main business code, calling top()... Constructed top()'s local object. Executing body of top(), calling middle(). Constructed middle()'s local object. Executing body of middle(), calling bottom(). Constructed bottom()'s local object. Executing body of bottom(). Throwing simulated exception. Destroyed bottom()'s local object. Destroyed middle()'s local object. Destroyed top()'s local object. Caught simulated exception! </output> Now I leave it as an exercise to reimplement this program to use C++ exceptions instead of longjmp, and perhaps compare clarity (and efficiency, if that's interesting). Cheers, & hth., - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#29 |
|
Messages: n/a
Hébergeur: |
On Tue, 23 Oct 2007 12:33:17 -0400, Stefan Monnier wrote:
>> NOTE: I am really afraid of try-catch-throw. I have never been >> able to understand it since it does not exist in C and I can't >> really visualize the construct in terms of C. That is what my > > Actually, these constructs pretty much exist in C as well: > `catch' is called `setjmp', and `throw' is called `longjmp'. If you ignore the thing about scope that I was being very careful to illustrate properly, then yes. And, the fact that try-catch blocks can be nested, recursed, etc, and only catching the matching type of exception stops the unwinding. -- Joel Yliluoma - http://bisqwit.iki.fi/ : comprehension = 1 / (2 ^ precision) |
|
|
|
#30 |
|
Messages: n/a
Hébergeur: |
>>> NOTE: I am really afraid of try-catch-throw. I have never been
>>> able to understand it since it does not exist in C and I can't >>> really visualize the construct in terms of C. That is what my >> >> Actually, these constructs pretty much exist in C as well: `catch' is >> called `setjmp', and `throw' is called `longjmp'. > I believe a better way would be to imagine that 'try', not 'catch', > is called 'setjmp'. Sorry, I'm reading this on gnu.emacs. where Elisp only provides `catch' and `throw' (no `try') and these map pretty closely to setjmp/longjmp. Stefan |
|
|
|
#31 |
|
Messages: n/a
Hébergeur: |
> Anyone, care to show how this translates into assembly after we deal
> thoroughly with this in the context of C ? I believe that one way to look at setjmp/longjmp in C is that setjmp saves a copy of the registers (most importantly PC and SP) and longjmp uses that copy to jump back to the corresponding point in the program (and stack activation). Stefan |
|
|
|
#32 |
|
Messages: n/a
Hébergeur: |
On Sun, 21 Oct 2007 00:55:53 +0200, "Alf P. Steinbach"
<alfps@start.no> wrote: > * gnuist006@gmail.com: > > NOTE: I am really afraid of try-catch-throw. I have never been > > able to understand it since it does not exist in C and I cant > > really visualize the construct in terms of C. <snip> > > The closest equivalent in C would be a 'longjmp'. However, a C++ > exception is more limited, in that it will only jump up the call chain, C longjmp/setjmp also is only guaranteed to work up the stack; the fact that _some_ implementations can work cross-stack and in particular cross-thread is not standard nor portable. > and it's more powerful, in that it will destroy local objects as it does > so. Also, if you use 'longjmp' in C++ you're practically doomed (unless > you use it to jump between co-routines with their own stacks), because > 'longjmp' doesn't destroy local objects. > Actually it's Undefined Behavior; a good quality C++ implementation CAN coordinate longjmp, and also pthreads cancellation, with exceptions to destruct locals cleanly -- but it's not required. - formerly david.thompson1 || achar(64) || worldnet.att.net |
|
|
|
#33 |
|
Messages: n/a
Hébergeur: |
* David Thompson:
> On Sun, 21 Oct 2007 00:55:53 +0200, "Alf P. Steinbach" > <alfps@start.no> wrote: > >> * gnuist006@gmail.com: > >>> NOTE: I am really afraid of try-catch-throw. I have never been >>> able to understand it since it does not exist in C and I cant >>> really visualize the construct in terms of C. <snip> >> The closest equivalent in C would be a 'longjmp'. However, a C++ >> exception is more limited, in that it will only jump up the call chain, > > C longjmp/setjmp also is only guaranteed to work up the stack; the > fact that _some_ implementations can work cross-stack and in > particular cross-thread is not standard nor portable. So? But also, what on Earth do you mean by a cross-thread longjmp? I implemented coroutines in terms of longjmp at the time that was popular, so the concepts involved are not unfamiliar to me. Yet I fail to envision what you could be talking about, especially as "fact". I think perhaps you're talking about restoring the full context (registers etc) of a moment in a thread's execution? >> and it's more powerful, in that it will destroy local objects as it does >> so. Also, if you use 'longjmp' in C++ you're practically doomed (unless >> you use it to jump between co-routines with their own stacks), because >> 'longjmp' doesn't destroy local objects. >> > Actually it's Undefined Behavior; a good quality C++ implementation > CAN coordinate longjmp, and also pthreads cancellation, with > exceptions to destruct locals cleanly -- but it's not required. I don't know about ptheads cancellation, but other than that you're right. Visual C++ coordinates longjmp with C++ stack unwinding. g++, on the other hand, does not. Cheers, & hth., - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#34 |
|
Messages: n/a
Hébergeur: |
* Alf P. Steinbach:
> * David Thompson: >> On Sun, 21 Oct 2007 00:55:53 +0200, "Alf P. Steinbach" >> <alfps@start.no> wrote: >> >>> * gnuist006@gmail.com: >> >>>> NOTE: I am really afraid of try-catch-throw. I have never been >>>> able to understand it since it does not exist in C and I cant >>>> really visualize the construct in terms of C. <snip> >>> The closest equivalent in C would be a 'longjmp'. However, a C++ >>> exception is more limited, in that it will only jump up the call chain, >> >> C longjmp/setjmp also is only guaranteed to work up the stack; the >> fact that _some_ implementations can work cross-stack and in >> particular cross-thread is not standard nor portable. > > So? > > But also, what on Earth do you mean by a cross-thread longjmp? I > implemented coroutines in terms of longjmp at the time that was popular, > so the concepts involved are not unfamiliar to me. Yet I fail to > envision what you could be talking about, especially as "fact". I think > perhaps you're talking about restoring the full context (registers etc) > of a moment in a thread's execution? > > >>> and it's more powerful, in that it will destroy local objects as it >>> does so. Also, if you use 'longjmp' in C++ you're practically doomed >>> (unless you use it to jump between co-routines with their own >>> stacks), because 'longjmp' doesn't destroy local objects. >>> >> Actually it's Undefined Behavior; a good quality C++ implementation >> CAN coordinate longjmp, and also pthreads cancellation, with >> exceptions to destruct locals cleanly -- but it's not required. > > I don't know about ptheads cancellation, but other than that you're > right. Visual C++ coordinates longjmp with C++ stack unwinding. g++, > on the other hand, does not. Sorry, I didn't see the weasel-word "actually", which indicates a contradiction. When I wrote that you're right, that just meant that you supplied some extra info that wasn't incorrect. Cheers, - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#35 |
|
Messages: n/a
Hébergeur: |
On Mon, 05 Nov 2007 06:07:25 +0100, "Alf P. Steinbach"
<alfps@start.no> wrote: > * David Thompson: > > On Sun, 21 Oct 2007 00:55:53 +0200, "Alf P. Steinbach" > > <alfps@start.no> wrote: > >> The closest equivalent in C would be a 'longjmp'. However, a C++ > >> exception is more limited, in that it will only jump up the call chain, > > > > C longjmp/setjmp also is only guaranteed to work up the stack; the > > fact that _some_ implementations can work cross-stack and in > > particular cross-thread is not standard nor portable. > > So? > > But also, what on Earth do you mean by a cross-thread longjmp? I > implemented coroutines in terms of longjmp at the time that was popular, > so the concepts involved are not unfamiliar to me. Yet I fail to > envision what you could be talking about, especially as "fact". I think IME 'coroutine' has been used for several slightly different concepts, but if you mean the one of separate threads of control passing CPU ownership often along with data anytime they choose, also known more specifically as cooperative/nonpreemptive threading/tasking, yes. I think you are agreeing that it did actually work, because 'restoring' PC and SP (or equivalents) was enough; but I am pointing out it wasn't and isn't _required_ to work that way. > perhaps you're talking about restoring the full context (registers etc) > of a moment in a thread's execution? > IME a cooperative switch itself doesn't need to save and restore other state, as the language mechanism(s) e.g. 'call yield' handle it. Or for cache-y things it happens automatically, or mostly automatically. - formerly david.thompson1 || achar(64) || worldnet.att.net |
|
|
|
#36 |
|
Messages: n/a
Hébergeur: |
* David Thompson:
> On Mon, 05 Nov 2007 06:07:25 +0100, "Alf P. Steinbach" > <alfps@start.no> wrote: > >> * David Thompson: >>> On Sun, 21 Oct 2007 00:55:53 +0200, "Alf P. Steinbach" >>> <alfps@start.no> wrote: > >>>> The closest equivalent in C would be a 'longjmp'. However, a C++ >>>> exception is more limited, in that it will only jump up the call chain, >>> C longjmp/setjmp also is only guaranteed to work up the stack; the >>> fact that _some_ implementations can work cross-stack and in >>> particular cross-thread is not standard nor portable. >> So? >> >> But also, what on Earth do you mean by a cross-thread longjmp? I >> implemented coroutines in terms of longjmp at the time that was popular, >> so the concepts involved are not unfamiliar to me. Yet I fail to >> envision what you could be talking about, especially as "fact". I think > > IME 'coroutine' has been used for several slightly different concepts, > but if you mean the one of separate threads of control passing CPU > ownership often along with data anytime they choose, also known more > specifically as cooperative/nonpreemptive threading/tasking, yes. I > think you are agreeing that it did actually work, because 'restoring' > PC and SP (or equivalents) was enough; but I am pointing out it wasn't > and isn't _required_ to work that way. > >> perhaps you're talking about restoring the full context (registers etc) >> of a moment in a thread's execution? >> > IME a cooperative switch itself doesn't need to save and restore other > state, as the language mechanism(s) e.g. 'call yield' handle it. Or > for cache-y things it happens automatically, or mostly automatically. Sorry, I fail to see the point, whatever it is. But regarding definition of 'coroutine', it really doesn't map to more than one concept. Coroutines are treated in Knuth's TAOCPM, which locked in the terminology (although Knuth didn't always succeed in in establishing convention, e.g. he had to redraw his trees because he at first did them with the root down, while the rest of the CS community chose root up, and same for his misconception of "real time" as "reel time", he couldn't make that stick either :-) ); some languages, notably Modula-2, had built-in support for coroutines; you can find some dicussion of coroutines at <url: http://en.wikipedia.org/wiki/Coroutine>. Cheers, & hth., - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
![]() |
| Outils de la discussion | |
|
|