digitalmars.D - should postconditions be evaluated even if Exception is thrown?
- Andrei Alexandrescu (14/14) Dec 02 2009 If a function throws a class inheriting Error but not Exception (i.e. an...
- Walter Bright (3/18) Dec 02 2009 I have a hard time accepting this as a requirement. An exception means
- Andrei Alexandrescu (8/29) Dec 02 2009 An exception (not an Error) is an expected and documented outcome of a
- Walter Bright (4/10) Dec 02 2009 Consider a constructor. It's postcondition is the class invariant is
- Brad Roberts (2/14) Dec 02 2009 If the constructor fails, the object never existed. Nothing to validate...
- Walter Bright (10/24) Dec 02 2009 Right. And I can't see how you can validate the output of a function
- Michel Fortin (16/44) Dec 03 2009 That's silly indeed. But this is not:
- Andrei Alexandrescu (8/36) Dec 03 2009 Very, very interesting example that actually makes my point very nicely.
- Don (4/43) Dec 03 2009 I don't understand why you think that. I can't believe it adds any value...
- Andrei Alexandrescu (19/66) Dec 03 2009 Checked exceptions are a very different beast. With a checked exception
- Andrei Alexandrescu (10/38) Dec 03 2009 I found one more example.
- Michel Fortin (10/19) Dec 03 2009 That's a good example.
- Andrei Alexandrescu (3/21) Dec 03 2009 I'd think the pre- and postconditions msut be under the lock anyhow.
- Michel Fortin (17/39) Dec 04 2009 That'll only work if the lock is acquired outside of the function call.
- Andrei Alexandrescu (12/24) Dec 03 2009 I agree. But constructors and destructors are already special, so that
- Brad Roberts (8/29) Dec 02 2009 I agree with Andrei on this one. If there's some part of the object tha...
- Rory McGuire (4/24) Dec 02 2009 I would think that if a method in a class throws then at least the class...
- Walter Bright (2/4) Dec 02 2009 No.
- Brad Roberts (2/7) Dec 03 2009 Do you consider that broken or correct?
- Walter Bright (2/9) Dec 03 2009 Not sure.
- Don (4/15) Dec 03 2009 I think it has to. Otherwise, how can the caller restore the invariant?
- Andrei Alexandrescu (3/19) Dec 03 2009 s/delete the object/terminate the program ASAP/
- Andrei Alexandrescu (7/18) Dec 03 2009 Think Boeing: an exception is a possible and expected error of a
- Andrei Alexandrescu (15/26) Dec 03 2009 TDPL says that in non-release mode, public methods have code
- Don (6/37) Dec 03 2009 There are worse problems than that...
- Andrei Alexandrescu (3/42) Dec 03 2009 Ouch. Well, at least these are problems we all agree what the fix should...
- Andrei Alexandrescu (6/11) Dec 03 2009 Well you must do as you preach. Throwing a non-Error exception does not
- Michiel Helvensteijn (14/19) Dec 03 2009 You don't want the regular postcondition to express exceptional outcomes...
- Andrei Alexandrescu (3/26) Dec 03 2009 Yah, I was thinking of something along the same lines.
- Don (2/31) Dec 03 2009 Yup. It's checked exceptions.
- Andrei Alexandrescu (11/44) Dec 03 2009 The way I was thinking of it is:
- Steven Schveighoffer (6/51) Dec 03 2009 That looks fine to me as long as
- Andrei Alexandrescu (4/64) Dec 03 2009 I agree. To entirely accommodate existing behavior, out without an
- Michal Minich (7/21) Dec 04 2009 if the function which throws exception is pure, then there is no world i...
- Michel Fortin (16/40) Dec 04 2009 Well you could still assert something about the exception:
- Michal Minich (13/38) Dec 04 2009 Yes, you could provide more specific error message (or maybe throw more ...
- Leandro Lucarella (20/47) Dec 04 2009 I don't think so, postconditions should not change the programs behavior...
- Denis Koroskin (5/41) Dec 04 2009 You can't throw in pre/postconditions, but it's a bug:
- Michal Minich (6/10) Dec 04 2009 heating up the processor for no effect whatsoever?!
- Leandro Lucarella (14/28) Dec 04 2009 Well, yes, failing a postcondition should be a non-recoverable Error, an...
- Denis Koroskin (4/25) Dec 04 2009 Yes (it's already allowed in DMD trunk).
- Andrei Alexandrescu (5/29) Dec 04 2009 Good point. Probably a pure function has no place to define an
- Don (6/24) Dec 03 2009 If you mean that all class invariants must be satisfied regardless of
- Andrei Alexandrescu (5/32) Dec 03 2009 The file invariant can't be "the file is closed". A free function
- Rainer Deyke (16/24) Dec 03 2009 If an 'Error' is truly unrecoverable, then there's no point in treating
- Andrei Alexandrescu (5/29) Dec 03 2009 Actually, it's not that bad. TDPL explains that in detail, but there are...
- =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= (6/24) Dec 03 2009 Isn't the post-condition mainly to assert the correctness of the return
- Andrei Alexandrescu (8/35) Dec 03 2009 As others have mentioned, you may have different postconditions
- =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= (3/42) Dec 03 2009 In the case of special postconditions for exceptions, I agree it should
- Brad Roberts (5/17) Dec 03 2009 No, post conditions do NOT replace finally. Finally is body code, often...
- Denis Koroskin (24/39) Dec 03 2009 I'm not sure about post-conditions, but invariants have to be called.
- Andrei Alexandrescu (4/54) Dec 03 2009 The language would need to allow you to write an out(result)
- Sean Kelly (2/17) Dec 03 2009 Postconditions serve two purposes in my mind: to verify that object deta...
If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. Andrei
Dec 02 2009
Andrei Alexandrescu wrote:If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.I have a hard time accepting this as a requirement. An exception means it failed, not succeeded.
Dec 02 2009
Walter Bright wrote:Andrei Alexandrescu wrote:An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return. AndreiIf a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.I have a hard time accepting this as a requirement. An exception means it failed, not succeeded.
Dec 02 2009
Andrei Alexandrescu wrote:An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 02 2009
Walter Bright wrote:Andrei Alexandrescu wrote:If the constructor fails, the object never existed. Nothing to validate is valid.An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 02 2009
Brad Roberts wrote:Walter Bright wrote:Right. And I can't see how you can validate the output of a function that failed. Let's say your function sorts an array, and the post condition is the array is sorted. So, what would the postcondition be if it failed? out (result) { assert(failed || isSorted(result)); } ? What's the point?Andrei Alexandrescu wrote:If the constructor fails, the object never existed. Nothing to validate is valid.An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 02 2009
On 2009-12-03 01:06:07 -0500, Walter Bright <newshound1 digitalmars.com> said:Brad Roberts wrote:That's silly indeed. But this is not: char[] array; void func() out { // array is guarantied to be left intact upon failure. if (failed) assert(array == in.array); else assert(isSorted(array)); } body {...} -- Michel Fortin michel.fortin michelf.com http://michelf.com/Walter Bright wrote:Right. And I can't see how you can validate the output of a function that failed. Let's say your function sorts an array, and the post condition is the array is sorted. So, what would the postcondition be if it failed? out (result) { assert(failed || isSorted(result)); } ? What's the point?Andrei Alexandrescu wrote:If the constructor fails, the object never existed. Nothing to validate is valid.An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 03 2009
Walter Bright wrote:Brad Roberts wrote:Very, very interesting example that actually makes my point very nicely. If the function doesn't throw, the postcondition is that the array is sorted. If the function does throw, the postcondition is that the array has not lost any element. So at least you know that information wasn't lost. I can't believe this is working so well in my argument :o). AndreiWalter Bright wrote:Right. And I can't see how you can validate the output of a function that failed. Let's say your function sorts an array, and the post condition is the array is sorted. So, what would the postcondition be if it failed? out (result) { assert(failed || isSorted(result)); } ? What's the point?Andrei Alexandrescu wrote:If the constructor fails, the object never existed. Nothing to validate is valid.An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 03 2009
Andrei Alexandrescu wrote:Walter Bright wrote:I don't understand why you think that. I can't believe it adds any value whatsoever. It's just like checked exceptions, but with a much, much higher burden.Brad Roberts wrote:Very, very interesting example that actually makes my point very nicely. If the function doesn't throw, the postcondition is that the array is sorted. If the function does throw, the postcondition is that the array has not lost any element. So at least you know that information wasn't lost. I can't believe this is working so well in my argument :o).Walter Bright wrote:Right. And I can't see how you can validate the output of a function that failed. Let's say your function sorts an array, and the post condition is the array is sorted. So, what would the postcondition be if it failed? out (result) { assert(failed || isSorted(result)); } ? What's the point?Andrei Alexandrescu wrote:If the constructor fails, the object never existed. Nothing to validate is valid.An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 03 2009
Don wrote:Andrei Alexandrescu wrote:Checked exceptions are a very different beast. With a checked exception you must repeat statically all of the possible exceptions emerging from the function. But that information is next to useless. All that code is interested in is the throws-or-not bit. Postconditions are different. They are checks on the outcome of functions. The bane of exceptions-based languages is that once an exception is thrown, there's no real guarantee of the state of the system. This is because functions are too often written only having the success case in mind and neglecting to think and document how the world remains in case an exception is thrown. In the particular case of array sorting, if you use swap() throughout against elements of the array, the postcondition is always respected. But if you temporarily alter the array (e.g. by moving some of its elements off to temporary storage), then the postcondition is weaker - you're not guaranteed to even have the data in place if your comparison operator throws. I think this is information that a client of sort would be interested in. AndreiWalter Bright wrote:I don't understand why you think that. I can't believe it adds any value whatsoever. It's just like checked exceptions, but with a much, much higher burden.Brad Roberts wrote:Very, very interesting example that actually makes my point very nicely. If the function doesn't throw, the postcondition is that the array is sorted. If the function does throw, the postcondition is that the array has not lost any element. So at least you know that information wasn't lost. I can't believe this is working so well in my argument :o).Walter Bright wrote:Right. And I can't see how you can validate the output of a function that failed. Let's say your function sorts an array, and the post condition is the array is sorted. So, what would the postcondition be if it failed? out (result) { assert(failed || isSorted(result)); } ? What's the point?Andrei Alexandrescu wrote:If the constructor fails, the object never existed. Nothing to validate is valid.An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 03 2009
Walter Bright wrote:Brad Roberts wrote:I found one more example. A function that transfers money from one account to another must provide a postcondition even in the case of failure: no matter what, upon exit, the sum of the monies in the accounts is preserved. The transfer itself may fail for any number of complex reasons (overdraft, limit of transfers per month reached, account has limited access etc.) but the transfer function must in all cases preserve the total sum of funds in the two involved accounts. AndreiWalter Bright wrote:Right. And I can't see how you can validate the output of a function that failed. Let's say your function sorts an array, and the post condition is the array is sorted. So, what would the postcondition be if it failed? out (result) { assert(failed || isSorted(result)); } ? What's the point?Andrei Alexandrescu wrote:If the constructor fails, the object never existed. Nothing to validate is valid.An exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 03 2009
On 2009-12-03 17:16:11 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I found one more example. A function that transfers money from one account to another must provide a postcondition even in the case of failure: no matter what, upon exit, the sum of the monies in the accounts is preserved. The transfer itself may fail for any number of complex reasons (overdraft, limit of transfers per month reached, account has limited access etc.) but the transfer function must in all cases preserve the total sum of funds in the two involved accounts.That's a good example. But make this multithreaded and you have to hold the lock or transaction across the function and its pre- and post-conditions. Where should we stop? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 03 2009
Michel Fortin wrote:On 2009-12-03 17:16:11 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I'd think the pre- and postconditions msut be under the lock anyhow. AndreiI found one more example. A function that transfers money from one account to another must provide a postcondition even in the case of failure: no matter what, upon exit, the sum of the monies in the accounts is preserved. The transfer itself may fail for any number of complex reasons (overdraft, limit of transfers per month reached, account has limited access etc.) but the transfer function must in all cases preserve the total sum of funds in the two involved accounts.That's a good example. But make this multithreaded and you have to hold the lock or transaction across the function and its pre- and post-conditions. Where should we stop?
Dec 03 2009
On 2009-12-03 19:31:37 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Michel Fortin wrote:That'll only work if the lock is acquired outside of the function call. If the lock is acquired inside the function, pre- and post-conditions cannot be under the lock, and thus cannot check that. I think this just show that you probably ought to have two functions: one acquiring the lock which calls the other one to do the actual processing, the later one can have the pre-/post-conditions. But you can't put a contract on the one acquiring the lock since the contract would be outside it. Well, you could avoid it if labeling the function with synchronized was sufficient, but for the case above you probably want two locks, or some sort of database transaction, which won't work with synchronized. -- Michel Fortin michel.fortin michelf.com http://michelf.com/On 2009-12-03 17:16:11 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I'd think the pre- and postconditions msut be under the lock anyhow.I found one more example. A function that transfers money from one account to another must provide a postcondition even in the case of failure: no matter what, upon exit, the sum of the monies in the accounts is preserved. The transfer itself may fail for any number of complex reasons (overdraft, limit of transfers per month reached, account has limited access etc.) but the transfer function must in all cases preserve the total sum of funds in the two involved accounts.That's a good example. But make this multithreaded and you have to hold the lock or transaction across the function and its pre- and post-conditions. Where should we stop?
Dec 04 2009
Walter Bright wrote:Andrei Alexandrescu wrote:I agree. But constructors and destructors are already special, so that doesn't count. A regular function's postcondition should specify how it leaves the world in case an exception is passing through it. string readAllText(File input) out { assert(!input.isOpen()); } body { .... } AndreiAn exception (not an Error) is an expected and documented outcome of a function. After having listened to those endless Boeing stories, please listen to this one :o). Contract Programming covers the correctness of a program, and exceptions are correct behavior. By your very Boeing stories that I stoically endured, it seems like the logical conclusion is that postconditions must be evaluated upon exceptional return.Consider a constructor. It's postcondition is the class invariant is satisfied. If it throws, the object is not successfully constructed and the invariant does not hold.
Dec 03 2009
Walter Bright wrote:Andrei Alexandrescu wrote:I agree with Andrei on this one. If there's some part of the object that's allowed to be in a 'bad' state, then it shouldn't be part of the invariant nor checked in the out contract. But it _should_ be possible for someone to construct an object that is strongly consistent including in the face of exceptions and have the DbC aspects of D help enforce that. Later, BradIf a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.I have a hard time accepting this as a requirement. An exception means it failed, not succeeded.
Dec 02 2009
Walter Bright <newshound1 digitalmars.com> wrote:Andrei Alexandrescu wrote:I would think that if a method in a class throws then at least the class' invariant should be run? does it?If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.I have a hard time accepting this as a requirement. An exception means it failed, not succeeded.
Dec 02 2009
Rory McGuire wrote:I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 02 2009
Walter Bright wrote:Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Brad Roberts wrote:Walter Bright wrote:Not sure.Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Walter Bright wrote:Brad Roberts wrote:I think it has to. Otherwise, how can the caller restore the invariant? Note that once the invariant is invalid, it can't call any member functions! The only thing it could do is delete the object.Walter Bright wrote:Not sure.Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Don wrote:Walter Bright wrote:s/delete the object/terminate the program ASAP/ AndreiBrad Roberts wrote:I think it has to. Otherwise, how can the caller restore the invariant? Note that once the invariant is invalid, it can't call any member functions! The only thing it could do is delete the object.Walter Bright wrote:Not sure.Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Walter Bright wrote:Brad Roberts wrote:Think Boeing: an exception is a possible and expected error of a subsystem. For example, failure to connect with the tower on radio or failure of the radar or failure to connect to the GPS satellite. Would you expect that such failures make no guarantee about the integrity of the plane's controls? AndreiWalter Bright wrote:Not sure.Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Walter Bright wrote:Brad Roberts wrote:TDPL says that in non-release mode, public methods have code instrumented like this: class C { void m() { __check_invariant(); scope(exit) __check_invariant(); ... body ... } } My understanding after a recent discussion to Walter focused on the topic is that in case a non-Exception Error is thrown, scope(exit) statements are not guaranteed to be executed, as aren't destructors of local objects and finally clauses. AndreiWalter Bright wrote:Not sure.Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Andrei Alexandrescu wrote:Walter Bright wrote:There are worse problems than that... At present, scope(exit) isn't executed if it's preceded by a label (!). And if the scope consists of a single declaration, the compiler will ICE if there is a destructor. Deterministic destruction is still horribly broken.Brad Roberts wrote:TDPL says that in non-release mode, public methods have code instrumented like this: class C { void m() { __check_invariant(); scope(exit) __check_invariant(); ... body ... } } My understanding after a recent discussion to Walter focused on the topic is that in case a non-Exception Error is thrown, scope(exit) statements are not guaranteed to be executed, as aren't destructors of local objects and finally clauses. AndreiWalter Bright wrote:Not sure.Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Don wrote:Andrei Alexandrescu wrote:Ouch. Well, at least these are problems we all agree what the fix should be. AndreiWalter Bright wrote:There are worse problems than that... At present, scope(exit) isn't executed if it's preceded by a label (!). And if the scope consists of a single declaration, the compiler will ICE if there is a destructor. Deterministic destruction is still horribly broken.Brad Roberts wrote:TDPL says that in non-release mode, public methods have code instrumented like this: class C { void m() { __check_invariant(); scope(exit) __check_invariant(); ... body ... } } My understanding after a recent discussion to Walter focused on the topic is that in case a non-Exception Error is thrown, scope(exit) statements are not guaranteed to be executed, as aren't destructors of local objects and finally clauses. AndreiWalter Bright wrote:Not sure.Rory McGuire wrote:Do you consider that broken or correct?I would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Walter Bright wrote:Rory McGuire wrote:Well you must do as you preach. Throwing a non-Error exception does not absolve a method from preserving the class invariant. Again: throwing a subclass of Exception is part of the specification and can happen during the working of a system. AndreiI would think that if a method in a class throws then at least the class' invariant should be run? does it?No.
Dec 03 2009
Andrei Alexandrescu wrote:This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.You don't want the regular postcondition to express exceptional outcomes. However, there *should* be an exception-postcondition clause, which describes the conditions which are guaranteed to hold after an exception is thrown. int f() throws (SomeException, SomeOtherException) pre { } body { } post(int result) { } epost(SomeException x) { } epost(SomeOtherException)x) { } I believe JML does something like this. -- Michiel Helvensteijn
Dec 03 2009
Michiel Helvensteijn wrote:Andrei Alexandrescu wrote:Yah, I was thinking of something along the same lines. AndreiThis may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.You don't want the regular postcondition to express exceptional outcomes. However, there *should* be an exception-postcondition clause, which describes the conditions which are guaranteed to hold after an exception is thrown. int f() throws (SomeException, SomeOtherException) pre { } body { } post(int result) { } epost(SomeException x) { } epost(SomeOtherException)x) { } I believe JML does something like this.
Dec 03 2009
Andrei Alexandrescu wrote:Michiel Helvensteijn wrote:Yup. It's checked exceptions.Andrei Alexandrescu wrote:Yah, I was thinking of something along the same lines. AndreiThis may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.You don't want the regular postcondition to express exceptional outcomes. However, there *should* be an exception-postcondition clause, which describes the conditions which are guaranteed to hold after an exception is thrown. int f() throws (SomeException, SomeOtherException) pre { } body { } post(int result) { } epost(SomeException x) { } epost(SomeOtherException)x) { } I believe JML does something like this.
Dec 03 2009
Don wrote:Andrei Alexandrescu wrote:The way I was thinking of it is: int f() out(result) { } out(Exception e) { } body { } So you have a chance to assert what the world looks like in case you plan on returning a result, and what the world looks like if an exception is emerging from the function. So checked exceptions - this is not. AndreiMichiel Helvensteijn wrote:Yup. It's checked exceptions.Andrei Alexandrescu wrote:Yah, I was thinking of something along the same lines. AndreiThis may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.You don't want the regular postcondition to express exceptional outcomes. However, there *should* be an exception-postcondition clause, which describes the conditions which are guaranteed to hold after an exception is thrown. int f() throws (SomeException, SomeOtherException) pre { } body { } post(int result) { } epost(SomeException x) { } epost(SomeOtherException)x) { } I believe JML does something like this.
Dec 03 2009
On Thu, 03 Dec 2009 13:47:25 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Don wrote:That looks fine to me as long as out(Exception e) is optional -- it should revert to the original behavior. -SteveAndrei Alexandrescu wrote:The way I was thinking of it is: int f() out(result) { } out(Exception e) { } body { } So you have a chance to assert what the world looks like in case you plan on returning a result, and what the world looks like if an exception is emerging from the function. So checked exceptions - this is not.Michiel Helvensteijn wrote:Yup. It's checked exceptions.Andrei Alexandrescu wrote:Yah, I was thinking of something along the same lines. AndreiThis may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.You don't want the regular postcondition to express exceptional outcomes. However, there *should* be an exception-postcondition clause, which describes the conditions which are guaranteed to hold after an exception is thrown. int f() throws (SomeException, SomeOtherException) pre { } body { } post(int result) { } epost(SomeException x) { } epost(SomeOtherException)x) { } I believe JML does something like this.
Dec 03 2009
Steven Schveighoffer wrote:On Thu, 03 Dec 2009 13:47:25 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I agree. To entirely accommodate existing behavior, out without an argument should only be evaluated if an exception is not thrown. AndreiDon wrote:That looks fine to me as long as out(Exception e) is optional -- it should revert to the original behavior. -SteveAndrei Alexandrescu wrote:The way I was thinking of it is: int f() out(result) { } out(Exception e) { } body { } So you have a chance to assert what the world looks like in case you plan on returning a result, and what the world looks like if an exception is emerging from the function. So checked exceptions - this is not.Michiel Helvensteijn wrote:Yup. It's checked exceptions.Andrei Alexandrescu wrote:Yah, I was thinking of something along the same lines. AndreiThis may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.You don't want the regular postcondition to express exceptional outcomes. However, there *should* be an exception-postcondition clause, which describes the conditions which are guaranteed to hold after an exception is thrown. int f() throws (SomeException, SomeOtherException) pre { } body { } post(int result) { } epost(SomeException x) { } epost(SomeOtherException)x) { } I believe JML does something like this.
Dec 03 2009
Hello Andrei,The way I was thinking of it is: int f() out(result) { } out(Exception e) { } body { } So you have a chance to assert what the world looks like in case you plan on returning a result, and what the world looks like if an exception is emerging from the function. So checked exceptions - this is not. Andreiif the function which throws exception is pure, then there is no world invariant to hold on after function exits (only return value is to be checked on success). Is there reason to have out(Exception ex) {} postcondition for pure function, or it should be compile time error to specify one? Similarly, when function is nothrow or when is not marked pure but does not make any side effect either.
Dec 04 2009
On 2009-12-04 04:11:22 -0500, Michal Minich <michal.minich gmail.com> said:Hello Andrei,Well you could still assert something about the exception: out (LoginException ex) { assert(ex.errorDescription != ""); } So, although I can't really find an example that looks useful, someone might and I don't think it should be disallowed.The way I was thinking of it is: int f() out(result) { } out(Exception e) { } body { } So you have a chance to assert what the world looks like in case you plan on returning a result, and what the world looks like if an exception is emerging from the function. So checked exceptions - this is not. Andreiif the function which throws exception is pure, then there is no world invariant to hold on after function exits (only return value is to be checked on success). Is there reason to have out(Exception ex) {} postcondition for pure function, or it should be compile time error to specify one?Similarly, when function is nothrow or when is not marked pure but does not make any side effect either.In a nothrow function it certainly does not make sense have contracts for exceptions since none can be thrown. The only reasonable thing you could do in one is this: out (Exception e) { assert(false); } But since the compiler can statically check that no exception can be thrown it's dead code anyway... unless someone cast a function that throws as nothrow. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 04 2009
Hello Michel,Yes, you could provide more specific error message (or maybe throw more specific exception), but I'm not sure how useful is this. I'm also not sure about how some specifics should work: currently, it is not allowed to throw Exception from postcondition, it is only possible to throw Error (assert). Should it be possible to throw Exception from error handling postcondition or not? If exception handling postcondition is empty (or does not throw any Error or Exception), should the exception throw in body be suppressed or not? If you throw in postcondition, what to do with Exception throw in body ?if the function which throws exception is pure, then there is no world invariant to hold on after function exits (only return value is to be checked on success). Is there reason to have out(Exception ex) {} postcondition for pure function, or it should be compile time error to specify one?Well you could still assert something about the exception: out (LoginException ex) { assert(ex.errorDescription != ""); } So, although I can't really find an example that looks useful, someone might and I don't think it should be disallowed.but function and it contracts are defined at compile time anyway. (Such nothrow cast could only badly affect callers of this function.)Similarly, when function is nothrow or when is not marked pure but does not make any side effect either.In a nothrow function it certainly does not make sense have contracts for exceptions since none can be thrown. The only reasonable thing you could do in one is this: out (Exception e) { assert(false); } But since the compiler can statically check that no exception can be thrown it's dead code anyway... unless someone cast a function that throws as nothrow.
Dec 04 2009
Michal Minich, el 4 de diciembre a las 13:13 me escribiste:Hello Michel,I don't think so, postconditions should not change the programs behavior, it's like asserts or any other DbC feature. You can compile the program without it, and it should work the same. I think postconditions should only be able to inspect (in a read-only manner) the exception; once the postcondition finished executing, the exception should be propagated as is.Yes, you could provide more specific error message (or maybe throw more specific exception), but I'm not sure how useful is this. I'm also not sure about how some specifics should work: currently, it is not allowed to throw Exception from postcondition, it is only possible to throw Error (assert). Should it be possible to throw Exception from error handling postcondition or not?if the function which throws exception is pure, then there is no world invariant to hold on after function exits (only return value is to be checked on success). Is there reason to have out(Exception ex) {} postcondition for pure function, or it should be compile time error to specify one?Well you could still assert something about the exception: out (LoginException ex) { assert(ex.errorDescription != ""); } So, although I can't really find an example that looks useful, someone might and I don't think it should be disallowed.If exception handling postcondition is empty (or does not throw any Error or Exception), should the exception throw in body be suppressed or not?No.If you throw in postcondition, what to do with Exception throw in body ?You can't throw in postconditions. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- G: I don't want hope. Hope is killing me. My dream is to become hopeless. When you're hopeless you don't care. And when you care, that indifference makes you attractive. J: So, hopelessness is the key? G: It's my only hope. -- George Constanza & Jerry Seinfeld
Dec 04 2009
On Fri, 04 Dec 2009 16:35:57 +0300, Leandro Lucarella <llucax gmail.com> wrote:Michal Minich, el 4 de diciembre a las 13:13 me escribiste:You can't throw in pre/postconditions, but it's a bug: http://d.puremagic.com/issues/show_bug.cgi?id=3388 http://d.puremagic.com/issues/show_bug.cgi?id=3400Hello Michel,I don't think so, postconditions should not change the programs behavior, it's like asserts or any other DbC feature. You can compile the program without it, and it should work the same. I think postconditions should only be able to inspect (in a read-only manner) the exception; once the postcondition finished executing, the exception should be propagated as is.Yes, you could provide more specific error message (or maybe throw more specific exception), but I'm not sure how useful is this. I'm also not sure about how some specifics should work: currently, it is not allowed to throw Exception from postcondition, it is only possible to throw Error (assert). Should it be possible to throw Exception from error handling postcondition or not?if the function which throws exception is pure, then there is no world invariant to hold on after function exits (only return value is to be checked on success). Is there reason to have out(Exception ex) {} postcondition for pure function, or it should be compile time error to specify one?Well you could still assert something about the exception: out (LoginException ex) { assert(ex.errorDescription != ""); } So, although I can't really find an example that looks useful, someone might and I don't think it should be disallowed.If exception handling postcondition is empty (or does not throw any Error or Exception), should the exception throw in body be suppressed or not?No.If you throw in postcondition, what to do with Exception throw in body ?You can't throw in postconditions.
Dec 04 2009
Hello Leandro,I think postconditions should only be able to inspect (in a read-only manner) the exception; once the postcondition finished executing, the exception should be propagated as is.heating up the processor for no effect whatsoever?! Note also that it is possible, and desired, to use assert statement in conditions; this statement can throw Error (it is corner case of changing behavior of program, but we can consider that it is not changing anything, because it should end the program very fast anyway).
Dec 04 2009
Michal Minich, el 4 de diciembre a las 14:13 me escribiste:Hello Leandro,Well, yes, failing a postcondition should be a non-recoverable Error, and that's an exception, you're right. But I don't think being able to throw any non-Error should be allowed. I think only asserts should be allowed (not throwing using throw), and assert should in post/pre-conditions should dump a core, no more, no less. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Agitamos toda la zona de la paleta al horno, vemos que una luz nos atraviesa toda la zona intestinal... -- Sidharta KiwiI think postconditions should only be able to inspect (in a read-only manner) the exception; once the postcondition finished executing, the exception should be propagated as is.heating up the processor for no effect whatsoever?! Note also that it is possible, and desired, to use assert statement in conditions; this statement can throw Error (it is corner case of changing behavior of program, but we can consider that it is not changing anything, because it should end the program very fast anyway).
Dec 04 2009
On Fri, 04 Dec 2009 16:13:53 +0300, Michal Minich <michal.minich gmail.com> wrote:Hello Michel,Yes (it's already allowed in DMD trunk).Yes, you could provide more specific error message (or maybe throw more specific exception), but I'm not sure how useful is this. I'm also not sure about how some specifics should work: currently, it is not allowed to throw Exception from postcondition, it is only possible to throw Error (assert). Should it be possible to throw Exception from error handling postcondition or not?if the function which throws exception is pure, then there is no world invariant to hold on after function exits (only return value is to be checked on success). Is there reason to have out(Exception ex) {} postcondition for pure function, or it should be compile time error to specify one?Well you could still assert something about the exception: out (LoginException ex) { assert(ex.errorDescription != ""); } So, although I can't really find an example that looks useful, someone might and I don't think it should be disallowed.If exception handling postcondition is empty (or does not throw any Error or Exception), should the exception throw in body be suppressed or not? If you throw in postcondition, what to do with Exception throw in body ?I guess that's what exception chaining is for.
Dec 04 2009
Michal Minich wrote:Hello Andrei,Good point. Probably a pure function has no place to define an out(Exception) guarantee.The way I was thinking of it is: int f() out(result) { } out(Exception e) { } body { } So you have a chance to assert what the world looks like in case you plan on returning a result, and what the world looks like if an exception is emerging from the function. So checked exceptions - this is not. Andreiif the function which throws exception is pure, then there is no world invariant to hold on after function exits (only return value is to be checked on success). Is there reason to have out(Exception ex) {} postcondition for pure function, or it should be compile time error to specify one?Similarly, when function is nothrow or when is not marked pure but does not make any side effect either.Such functions may choose to simply omit the out(Exception) clause. Andrei
Dec 04 2009
Andrei Alexandrescu wrote:If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. AndreiIf you mean that all class invariants must be satisfied regardless of exceptions, then I agree. But if you mean the function postcondition, I don't think that makes sense. If the file needs to be closed, that should be part of the File invariant.
Dec 03 2009
Don wrote:Andrei Alexandrescu wrote:The file invariant can't be "the file is closed". A free function readAllText(File f) could say that the postcondition is that the file is closed, even though a UTF exception does get thrown. AndreiIf a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. AndreiIf you mean that all class invariants must be satisfied regardless of exceptions, then I agree. But if you mean the function postcondition, I don't think that makes sense. If the file needs to be closed, that should be part of the File invariant.
Dec 03 2009
Andrei Alexandrescu wrote:If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied.If an 'Error' is truly unrecoverable, then there's no point in treating it as an exception. Just dump the core and get out. The very existence of 'Error' suggests that recovery is possible, so the same rules should apply to 'Error' and 'Exception'.I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception.Throwing an exception usually indicates a failure to reach the normal postcondition, but functions often have another postcondition that applies when the function terminates from an exception. Common postconditions in the case of an exception include: - The object is in a undetermined but valid state. (The basic exception guarantee in C++ lingo.) - The function has no side effects, i.e. all objects are in the same state as they were before the function was called. (The strong exception guarantee.) -- Rainer Deyke - rainerd eldwood.com
Dec 03 2009
Rainer Deyke wrote:Andrei Alexandrescu wrote:Actually, it's not that bad. TDPL explains that in detail, but there are a number of guarantees given by the language even if you catch Error.If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied.If an 'Error' is truly unrecoverable, then there's no point in treating it as an exception. Just dump the core and get out. The very existence of 'Error' suggests that recovery is possible, so the same rules should apply to 'Error' and 'Exception'.Yah, something like that. AndreiI just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception.Throwing an exception usually indicates a failure to reach the normal postcondition, but functions often have another postcondition that applies when the function terminates from an exception. Common postconditions in the case of an exception include: - The object is in a undetermined but valid state. (The basic exception guarantee in C++ lingo.) - The function has no side effects, i.e. all objects are in the same state as they were before the function was called. (The strong exception guarantee.)
Dec 03 2009
Andrei Alexandrescu wrote:If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. AndreiIsn't the post-condition mainly to assert the correctness of the return value? Or at least partially? The output cannot be correct if an exception is thrown, so any assertion in the post condition concerning the output would fail by definition, right? I would say the invariant() is the correct part to run.
Dec 03 2009
Pelle Månsson wrote:Andrei Alexandrescu wrote:As others have mentioned, you may have different postconditions depending on whether an exception was thrown or not. I think a major failure of exceptions as a language mechanism is that they gave the illusion that functions need not worry about what happens when an exception traverses them, and only need to focus on the success case. AndreiIf a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. AndreiIsn't the post-condition mainly to assert the correctness of the return value? Or at least partially? The output cannot be correct if an exception is thrown, so any assertion in the post condition concerning the output would fail by definition, right? I would say the invariant() is the correct part to run.
Dec 03 2009
Andrei Alexandrescu wrote:Pelle Månsson wrote:In the case of special postconditions for exceptions, I agree it should be there. Something to replace the finally.Andrei Alexandrescu wrote:As others have mentioned, you may have different postconditions depending on whether an exception was thrown or not. I think a major failure of exceptions as a language mechanism is that they gave the illusion that functions need not worry about what happens when an exception traverses them, and only need to focus on the success case. AndreiIf a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. AndreiIsn't the post-condition mainly to assert the correctness of the return value? Or at least partially? The output cannot be correct if an exception is thrown, so any assertion in the post condition concerning the output would fail by definition, right? I would say the invariant() is the correct part to run.
Dec 03 2009
On Thu, 3 Dec 2009, Pelle M?nsson wrote:Andrei Alexandrescu wrote:No, post conditions do NOT replace finally. Finally is body code, often cleanup functionality. Post-conditions are validation.. checking correctness. PC is specifically NOT about cleanup or any data modification.As others have mentioned, you may have different postconditions depending on whether an exception was thrown or not. I think a major failure of exceptions as a language mechanism is that they gave the illusion that functions need not worry about what happens when an exception traverses them, and only need to focus on the success case. AndreiIn the case of special postconditions for exceptions, I agree it should be there. Something to replace the finally.
Dec 03 2009
On Thu, 03 Dec 2009 06:51:32 +0300, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. AndreiI'm not sure about post-conditions, but invariants have to be called. Exception-safe programming is a must. Any function may fail, and in that happens, the function should leave an object it operates on in a correct state. With post-conditions, there is a pitfall: if function throws an exception, there is no return value, and nothing to verify. For example: float sqrt(float value) out (result) { assert(value * value == result); } body { assert(value >= 0); // might throw. What value the 'result' variable in a post-condition would store? return core.stdc.sqrt(value); } Reading your post for a second time, I think you are confusing post-condition with something else. How would you close a file in a post-condition (or an invariant)? I believe both should be relaxedPure/hasNoSideEffects. File closing should be done in a function body using scope (exit) mechanism.
Dec 03 2009
Denis Koroskin wrote:On Thu, 03 Dec 2009 06:51:32 +0300, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:The language would need to allow you to write an out(result) postcondition and an out(Exception) postcondition. AndreiIf a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty. AndreiI'm not sure about post-conditions, but invariants have to be called. Exception-safe programming is a must. Any function may fail, and in that happens, the function should leave an object it operates on in a correct state. With post-conditions, there is a pitfall: if function throws an exception, there is no return value, and nothing to verify. For example: float sqrt(float value) out (result) { assert(value * value == result); } body { assert(value >= 0); // might throw. What value the 'result' variable in a post-condition would store? return core.stdc.sqrt(value); } Reading your post for a second time, I think you are confusing post-condition with something else. How would you close a file in a post-condition (or an invariant)? I believe both should be relaxedPure/hasNoSideEffects. File closing should be done in a function body using scope (exit) mechanism.
Dec 03 2009
Andrei Alexandrescu Wrote:If a function throws a class inheriting Error but not Exception (i.e. an unrecoverable error), then the postcondition doesn't need to be satisfied. I just realized that postconditions, however, must be satisfied if the function throws an Exception-derived object. There is no more return value, but the function must leave everything in a consistent state. For example, a function reading text from a file may have the postcondition that it closes the file, even though it may throw a malformed file exception. This may sound crazy, but if you just follow the facts that distinguish regular error handling from program correctness, you must live with the consequences. And the consequence is - a function's postcondition must be designed to take into account exceptional paths. Only in case of unrecoverable errors is the function relieved of its duty.Postconditions serve two purposes in my mind: to verify that object details are in a valid state when this checking isn't possible or appropriate in an invariant, and to check that the return value is in range. It seems quite reasonable to want the object validation to occur, but impossible for return value checking to occur... unless a feature is added to test if an exception is in flight and then expect the user to call this in postconditions to see if they should omit return value checking. This seems like it may be too onerous of a requirement.
Dec 03 2009