February 27, 2008
On Wed, 27 Feb 2008 10:42:07 +0300, Robert Fraser <fraserofthenight@gmail.com> wrote:

> eao197 wrote:
>> On Mon, 25 Feb 2008 12:44:15 +0300, Walter Bright <newshound1@digitalmars.com> wrote:
>>
>>> Ary Borenszweig wrote:
>>>> Does this mean this will not compile:
>>>>  int foo(int[] someArray, int someIndex) nothrow {
>>>>     return someArray[someIndex];
>>>> }
>>>>  but this will:
>>>>  int foo(int[] someArray, int someIndex) nothrow {
>>>>     if (someIndex < someArray.length) {
>>>>         return someArray[someIndex];
>>>>     } else {
>>>>         return -1;
>>>>     }
>>>> }
>>>
>>> I don't know yet. But the idea is to do static checking of what can throw.
>>  Just my $0.02 about nothrow and DesignByContract: I think that nothrow are incompatible with DbC. A function/method could have contracts or nothrow but not both of them. It is especially actual for virtual (non-final) methods. Suppose that some class has:
>>  class A {
>>   public void cleanup() nothrow { ... };
>> }
>>  so it could be safely used in 'finally' statement:
>>  A someResource = acquireResource();
>> try { ... /* some processing */ ... }
>> finally {
>>   someResource.cleanup; /* looks like exception-safe action */
>> }
>>  But if there is a derived class B, which overrides cleanup() with postcondition:
>>  class B : A {
>>   public void cleanup() nothrow
>>     out { ... some checking ... }
>>     body { ... some actions ... }
>> }
>>  and acquireResource() would return B instead of A, then the code above won't be exception-safe. Moreover the behaviour of 'someResource.cleanup' would depend on compiler switches.
>>
>
> So the code generated depends on compiler switches... Isn't this always true? The "nothrow" spec could only actually be used when building release mode, and in non-release mode code, exception handling frames are always set up. This means that nothrow functions can still use assert() and array indexing without worries, since these only throw exceptions in non-release-mode code.
>
> Of course, then problems occur when mixing code compiled with different switches...

I'm affraid that you misunderstand my point. When you use a[i] or new in nothrow function you always known what could happen. But if you call virtual method from any object you can't predict its behaviour. Because the method implementation in some derived class could define contract for that method. And you may don't known about it.

And becouse of this I think that 'nothrow' is a kind of function contract. And if a function defines such contract then it can't redefine it in derived classes.

-- 
Regards,
Yauheni Akhotnikau
February 27, 2008
eao197 escribió:
>> eao197 wrote:
> I'm affraid that you misunderstand my point. When you use a[i] or new in nothrow function you always known what could happen. But if you call virtual method from any object you can't predict its behaviour. Because the method implementation in some derived class could define contract for that method. And you may don't known about it.
> 
> And becouse of this I think that 'nothrow' is a kind of function contract. And if a function defines such contract then it can't redefine it in derived classes.

But contracts are predictable. Say B extends A, and A has a foo method. If foo says nothrow, than if B overrides foo, it must also be nothrow (this will be enforced by the compiler, I'm sure).

For in and out, http://www.digitalmars.com/d/1.0/dbc.html shows there will be no problem.
February 27, 2008
On Wed, 27 Feb 2008 12:40:03 +0300, Ary Borenszweig <ary@esperanto.org.ar> wrote:

> eao197 escribió:
>>> eao197 wrote:
>> I'm affraid that you misunderstand my point. When you use a[i] or new in nothrow function you always known what could happen. But if you call virtual method from any object you can't predict its behaviour. Because the method implementation in some derived class could define contract for that method. And you may don't known about it.
>>  And becouse of this I think that 'nothrow' is a kind of function contract. And if a function defines such contract then it can't redefine it in derived classes.
>
> But contracts are predictable. Say B extends A, and A has a foo method. If foo says nothrow, than if B overrides foo, it must also be nothrow (this will be enforced by the compiler, I'm sure).

B.foo may looks like:

void foo() nothrow
  in { assert( <some condition> ); }
  out { assert( <some condition> ); }
  body { <some code without exception> }

Body of B.foo() doesn't throw exception but assert in pre/postcondition could do that. A call of B.foo could produce exception but B.foo is declared as 'nothrow' :(

-- 
Regards,
Yauheni Akhotnikau
February 27, 2008
eao197 wrote:
> B.foo may looks like:
> 
> void foo() nothrow
>   in { assert( <some condition> ); }
>   out { assert( <some condition> ); }
>   body { <some code without exception> }
> 
> Body of B.foo() doesn't throw exception but assert in pre/postcondition could do that. A call of B.foo could produce exception but B.foo is declared as 'nothrow' :(
> 

I'm happy with that. Contracts aren't compiled in release mode, and they aren't part of the function; they're part of the tests. I'd hate to have to avoid one language feature for reliability in order to gain another one.
February 27, 2008
On Wed, 27 Feb 2008 16:56:34 +0300, Christopher Wright <dhasenan@gmail.com> wrote:

> eao197 wrote:
>> B.foo may looks like:
>>  void foo() nothrow
>>   in { assert( <some condition> ); }
>>   out { assert( <some condition> ); }
>>   body { <some code without exception> }
>>  Body of B.foo() doesn't throw exception but assert in pre/postcondition could do that. A call of B.foo could produce exception but B.foo is declared as 'nothrow' :(
>>
>
> I'm happy with that. Contracts aren't compiled in release mode, and they aren't part of the function; they're part of the tests. I'd hate to have to avoid one language feature for reliability in order to gain another one.

People are different. You want to compile your programs in release mode to remove any run-time checks and contracts. I want to save them in my programs to catch errors at the most earliest stage ('fail fast' principle is very important in server-side systems). But a programing language must provide logical and consistent rules for each of us.

-- 
Regards,
Yauheni Akhotnikau
February 27, 2008
On Tue, 26 Feb 2008 23:36:34 -0800, Robert Fraser wrote:

> Graham St Jack wrote:
>> It will be a good trick if you can pull it off. I don't see how it can be done without examining the source code of all the called functions, leaving us back where we started with throw specs.
> 
> I think the idea would be that nothrow is part of the function signature and a nothrow function can only call other nothrow functions or wrap any function calls or news in a catch(Exception) (since there's no way to know specifically which exceptions could be thrown).

That would work, but my feeling is that it would be so restrictive that hardly any functions could be nothrow.
February 28, 2008
I wonder if asserts() should be the exception to nothrow.  Like eao197, I normally run my programs with assert()s turned on.  But it would be a shame to lose nothrow because of that.

Are assert()s catchable?  Other than in some sort of weird systems programming context (where you are running one program inside another), why would you want to catch them?  (I'm sure somebody has a compelling example...but would that example be ruined by asserts-that-penetrate-nothrow.)

eao197 wrote:
> On Wed, 27 Feb 2008 16:56:34 +0300, Christopher Wright <dhasenan@gmail.com> wrote:
> 
>> eao197 wrote:
>>> B.foo may looks like:
>>>  void foo() nothrow
>>>   in { assert( <some condition> ); }
>>>   out { assert( <some condition> ); }
>>>   body { <some code without exception> }
>>>  Body of B.foo() doesn't throw exception but assert in pre/postcondition could do that. A call of B.foo could produce exception but B.foo is declared as 'nothrow' :(
>>>
>>
>> I'm happy with that. Contracts aren't compiled in release mode, and they aren't part of the function; they're part of the tests. I'd hate to have to avoid one language feature for reliability in order to gain another one.
> 
> People are different. You want to compile your programs in release mode to remove any run-time checks and contracts. I want to save them in my programs to catch errors at the most earliest stage ('fail fast' principle is very important in server-side systems). But a programing language must provide logical and consistent rules for each of us.
> 
> --Regards,
> Yauheni Akhotnikau
February 28, 2008
On Thu, 28 Feb 2008 07:27:24 +0300, Russell Lewis <webmaster@villagersonline.com> wrote:

> I wonder if asserts() should be the exception to nothrow.  Like eao197, I normally run my programs with assert()s turned on.  But it would be a shame to lose nothrow because of that.
>
> Are assert()s catchable?

Yes, it is catchable:

import std.stdio;
import std.asserterror;

void do_something( int i, int j )
  in
    {
      assert( i < j, "i must be lesser than j" );
    }
  body
    {
      writefln( "i=", i, ", j=", j );
    }

void main()
  {
    try
      {
        do_something( 0, 1 );
        do_something( 1, 0 );
      }
    catch( AssertError x )
      {
        writefln( x );
      }
  }

> Other than in some sort of weird systems programming context (where you are running one program inside another), why would you want to catch them?

It is not necessary to catch AssertError. Sometimes it is necessary to catch any error. For example, in a HTTP-server you could start processing of a new request and catch different kinds of errors to make appropriate response:

void processNewRequest( SomeRequestData request )
  {
    try
      {
        requestProcessingActions( request );
      }
    catch( Error x )
      {
        logError( x );
        classifyErrorAndMakeAppropriateResponse( x );
      }
  }

There is no difference between some application-logic error, index out of range error, no memory error or AssertError. The request processing failed and the reason must be logged.

>  (I'm sure somebody has a compelling example...but would that example be ruined by asserts-that-penetrate-nothrow.)

May be I don't understand your question, but I think that nothrow should help write exception-safe code. For example, some resource cleanup actions in finally statements:

auto firstStream = createStream();
auto secondStream = createStream();
auto thirdStream = createStream();

try {
  firstStream.open( 'first' );
  secondStream.open( 'second' );
  thirdStream.open( 'third' );
  ... some actions with firstStream, secondStream and thirdStream ...
}
finally {
  // All stream should be closed here.
  firstStream.close;
  secondStream.close;
  thirdStream.close;
  ... some other cleanup code...
}

It is rather naive resource cleanup code, because without nothrow specification we can't assume that a 'close' call doesn't throw an exception. If close can throw exceptions we must rewrite it, for example:

finally {
  void safeClose( Stream s ) { try { s.close; } catch( Error ) {} }
  safeClose( firstStream );
  safeClose( secondStream );
  safeClose( thirdStream );
  ... some other cleanup code...
}

But if we know that close doesn't throw exceptions then we can write less code (without safeClose helper function). And I suppose that 'nothrow' is a promise of function's developer that the function doesn't throw an exception.

But if 'close' is written as:

close() nothrow
  in { assert( is_opened(), "close() must be called only in stream is open" ); }
  body { ... }

I think that such implementation brokes a promise about non-throwing exception. For example, what if some exception is thrown at secondStream.open("second") in the sample above? We are going to finally statement, successfully close firstStream, but get AssertError at secondStream.close(). It breaks finally statement and we have no chance to perform other cleanup code.

So I think that nothrow is a contract which is violated by any assert in in/out statements. And because of that nothrow shouldn't be used with in/out contracts.

But here is another kind of problem with nothrow. I don't know is it possible to write really exception free code in D (AFAIK it is impossible on JVM/.NET because VM could raise some of it internal exception at any moment). Exceptions could be everywere -- on accessing array items, on string concatenations, on new statements, on calling some functions with pre/postconditions and so on. So probably nothrow function could throw some kind of exceptions even if function's writter don't known about them (it reminds me unchecked exceptions in Java which could be thrown despite of method's exception specification). In such case AssertError could be one of such 'unchecked exception' in D, and in such case nothrow could be combined with in/out statements. But in such case the profit from nothrow is under doubt for me.

Disclaimer: I know that my sample with streams and resource cleanup in finally statement could be rewritten in different ways. It is just a sample.

>
> eao197 wrote:
>> On Wed, 27 Feb 2008 16:56:34 +0300, Christopher Wright <dhasenan@gmail.com> wrote:
>>
>>> eao197 wrote:
>>>> B.foo may looks like:
>>>>  void foo() nothrow
>>>>   in { assert( <some condition> ); }
>>>>   out { assert( <some condition> ); }
>>>>   body { <some code without exception> }
>>>>  Body of B.foo() doesn't throw exception but assert in pre/postcondition could do that. A call of B.foo could produce exception but B.foo is declared as 'nothrow' :(
>>>>
>>>
>>> I'm happy with that. Contracts aren't compiled in release mode, and they aren't part of the function; they're part of the tests. I'd hate to have to avoid one language feature for reliability in order to gain another one.
>>  People are different. You want to compile your programs in release mode to remove any run-time checks and contracts. I want to save them in my programs to catch errors at the most earliest stage ('fail fast' principle is very important in server-side systems). But a programing language must provide logical and consistent rules for each of us.
>>  --Regards,
>> Yauheni Akhotnikau



-- 
Regards,
Yauheni Akhotnikau
February 28, 2008
Walter Bright wrote:
> http://www.digitalmars.com/d/2.0/changelog.html
>  Now allow static arrays to be lvalues.

Cool, and about time! :) I've just tried it out and it's so much more natural.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
February 28, 2008
eao197 wrote:
> On Thu, 28 Feb 2008 07:27:24 +0300, Russell Lewis <webmaster@villagersonline.com> wrote:
> 
>> I wonder if asserts() should be the exception to nothrow.  Like eao197, I normally run my programs with assert()s turned on.  But it would be a shame to lose nothrow because of that.
>>
>> Are assert()s catchable?
> 
> Yes, it is catchable:

(snip)

>> Other than in some sort of weird systems programming context (where you are running one program inside another), why would you want to catch them?
> 
> It is not necessary to catch AssertError. Sometimes it is necessary to catch any error. For example, in a HTTP-server you could start processing of a new request and catch different kinds of errors to make appropriate response:

I agree that a web server needs to post an appropriate response.  But if an assert() has failed, you don't know if the failure is in your main program, in a library, or maybe even in your network code.  In that case, you can't really rely on your program to keep working correctly, and the only sane solution would be to restart it.

My argument, then, is that you need a metaprogram or "watchdog" (such as the init process in *NIX, or maybe just a "web server launcher") which manages the server programs and restarts them when they crash.

> There is no difference between some application-logic error, index out of range error, no memory error or AssertError. The request processing failed and the reason must be logged.

From the web client's or the system administrator's perspective, I agree.  The error should be reported to the client, and logged for the admin.  But from the internal-consistency-of-the-program perspective, these are very different.  An out-of-memory error is a (possibly transient) memory issue.  The internal logic of the program is intact. Array index out of range might (or might not) be survivable.  But a failed assert() means that something is (or might be) deeply wrong with the internal logic of the program.  That's not something, IMHO, that you ought to try to catch and then forget.

Things which are recoverable should throw Exceptions.  Things which are fatal should fail assert()s.