www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What is nothrow for?

reply "Janice Caron" <caron800 googlemail.com> writes:
D2.013 just added the "nothrow" keyword, so that one can write, e.g.

    inf f() nothrow
    {
        return 42;
    }

to indicate that f does not throw an exception. My question is, what's
the point?

The documentation notes that the semantics are not implemented, but I
have to ask, why is this desirable in general?

Like any annotation, "nothrow" indicates a /contract/. Like any
annation, there are two rules

(1) if a function is annotated with the nothrowkeyword, then the
compiler will emit a compile error within the function body, if the
function body of f throws an exception.

(2) if the caller of a function requires that the the called function
not throw any exceptions, then the compiler will emit a compile error
at the caller site if the callee is not annotated with the nothrow
keyword.

Rule one helps the human. Rule two helps the compiler - but positively
/hinders/ the human. The problem is one of logical fallacy - given the
proposition "all dogs have four legs", one may /not/ assume that if it
has four legs, it must be a dog. Likewise, given the proposition "any
function decorated with the nothrow keyword will not throw an
exception", one may /not/ assume that if it doesn't throw an
exception, then it will be decorated with the nothrow keyword. Here's
a simple counterexample:

    int f() { return 42; }
    int g() nothrow { return f(); }

Once the semantics of nothrow are implemented, the above code will not
compile. This is because, /even though/ f doesn't throw any
exceptions, the compiler isn't able to prove that (or at least, can't
be bothered to prove that) at the time g is compiled.

Like all annotations, "nothrow" therefore /propogates/ throughout
code. In order to get the above to compile, the user must now decorate
f.

This is all very well, unless f is in a library, and the user is
unable to modify f. In that case, presumably the user must do
something like:

    int g() nothrow { return cast(nothrow) f(); }

or perhaps

    int g() nothrow
    {
        try { return f(); }
        catch(Exception e) { return 0; }
    }

Sure - we could decorate /every/ function which does not throw an
exception with "nothrow", but are we really going to do that?

So I guess my question is, in what circumstance would "nothrow" be
helpful? And is it helpful /enough/ to warrant "polluting" all library
code with "nothrow" annotations?
Apr 24 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 So I guess my question is, in what circumstance would "nothrow" be
 helpful? And is it helpful /enough/ to warrant "polluting" all library
 code with "nothrow" annotations?

"nothrow" is, as you say, a contract. It specifies that a function must return normally (unless it aborts, crashes, or hangs). Such annotations: 1. improves the API documentation 2. enables significantly better code generation (if you use a lot of scope statements and struct destructors) 3. nothrow can be very useful in building up transactions, because you know that the components cannot fail 4. destructors cannot throw exceptions (because they are already in one). Andrei has proposed a method to deal with this, but it is as yet unimplemented. For more info, see http://www.gotw.ca/gotw/082.htm and http://www.boost.org/community/exception_safety.html
Apr 25 2008
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2008-04-25 03:23:39 -0400, Walter Bright <newshound1 digitalmars.com> said:

 Janice Caron wrote:
 So I guess my question is, in what circumstance would "nothrow" be
 helpful? And is it helpful /enough/ to warrant "polluting" all library
 code with "nothrow" annotations?

"nothrow" is, as you say, a contract. It specifies that a function must return normally (unless it aborts, crashes, or hangs).

I presume "aborts, crashes, or hangs" should also include "asserts". After all, one can't assert in release mode so it doesn't hinder the part about better code generation.
 4. destructors cannot throw exceptions (because they are already in 
 one). Andrei has proposed a method to deal with this, but it is as yet 
 unimplemented.

Hum, I wonder, can one assert in a destructor? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 25 2008
next sibling parent janderson <askme me.com> writes:
Michel Fortin wrote:
 On 2008-04-25 03:23:39 -0400, Walter Bright <newshound1 digitalmars.com> 
 said:
 
 Janice Caron wrote:
 So I guess my question is, in what circumstance would "nothrow" be
 helpful? And is it helpful /enough/ to warrant "polluting" all library
 code with "nothrow" annotations?

"nothrow" is, as you say, a contract. It specifies that a function must return normally (unless it aborts, crashes, or hangs).

I presume "aborts, crashes, or hangs" should also include "asserts". After all, one can't assert in release mode so it doesn't hinder the part about better code generation.
 4. destructors cannot throw exceptions (because they are already in 
 one). Andrei has proposed a method to deal with this, but it is as yet 
 unimplemented.

Hum, I wonder, can one assert in a destructor?

It shouldn't include asserts. Asserts can be disabled and don't cause the problems that exceptions do. -Joel
Apr 25 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michel Fortin wrote:
 I presume "aborts, crashes, or hangs" should also include "asserts". 

Yes. An assert is an error that is not recoverable, so there is no need for stack unwinding.
Apr 25 2008
parent reply Frank Benoit <keinfarbton googlemail.com> writes:
Walter Bright schrieb:
 Michel Fortin wrote:
 I presume "aborts, crashes, or hangs" should also include "asserts". 

Yes. An assert is an error that is not recoverable, so there is no need for stack unwinding.

Perhaps to get the stack trace?
Apr 25 2008
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Frank Benoit wrote:
 Walter Bright schrieb:
 Michel Fortin wrote:
 I presume "aborts, crashes, or hangs" should also include "asserts". 

Yes. An assert is an error that is not recoverable, so there is no need for stack unwinding.

Perhaps to get the stack trace?

Getting a stack trace doesn't require actually unwinding the stack, just looking at it.
Apr 25 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Frank Benoit wrote:
 Walter Bright schrieb:
 Michel Fortin wrote:
 I presume "aborts, crashes, or hangs" should also include "asserts". 

Yes. An assert is an error that is not recoverable, so there is no need for stack unwinding.

Perhaps to get the stack trace?

Sure, but that isn't "recovering" from the error. It's just collecting diagnostic information.
Apr 25 2008
prev sibling next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Walter Bright wrote:
 Janice Caron wrote:
 So I guess my question is, in what circumstance would "nothrow" be
 helpful? And is it helpful /enough/ to warrant "polluting" all library
 code with "nothrow" annotations?

"nothrow" is, as you say, a contract. It specifies that a function must return normally (unless it aborts, crashes, or hangs). Such annotations: 1. improves the API documentation 2. enables significantly better code generation (if you use a lot of scope statements and struct destructors) 3. nothrow can be very useful in building up transactions, because you know that the components cannot fail 4. destructors cannot throw exceptions (because they are already in one). Andrei has proposed a method to deal with this, but it is as yet unimplemented. For more info, see http://www.gotw.ca/gotw/082.htm and http://www.boost.org/community/exception_safety.html

I'd like to point out that you both agree that "nothrow" is a _contract_. That immediately begs the question: why implement it as yet another ad hoc feature instead of making it part of D's DBC (which is yet to be implemented...)? Personally, I don't see the point of constantly adding more annotations and keywords to D2 since it complicates the syntax and makes D2 much less attractive from a syntax POV. D2 will allow the following: pure invariant invariant(int) func(invariant(int)) nothrow; Am I the only one that thinks the above is too much? It's time for a standardized Annotations/Attributes mechanism for D. I'll post my initial suggestion for such a mechanism in a new thread. --Yigal
Apr 25 2008
parent reply janderson <askme me.com> writes:
Yigal Chripun wrote:
 Walter Bright wrote:
 Janice Caron wrote:
 So I guess my question is, in what circumstance would "nothrow" be
 helpful? And is it helpful /enough/ to warrant "polluting" all library
 code with "nothrow" annotations?

return normally (unless it aborts, crashes, or hangs). Such annotations: 1. improves the API documentation 2. enables significantly better code generation (if you use a lot of scope statements and struct destructors) 3. nothrow can be very useful in building up transactions, because you know that the components cannot fail 4. destructors cannot throw exceptions (because they are already in one). Andrei has proposed a method to deal with this, but it is as yet unimplemented. For more info, see http://www.gotw.ca/gotw/082.htm and http://www.boost.org/community/exception_safety.html

I'd like to point out that you both agree that "nothrow" is a _contract_. That immediately begs the question: why implement it as yet another ad hoc feature instead of making it part of D's DBC (which is yet to be implemented...)? Personally, I don't see the point of constantly adding more annotations and keywords to D2 since it complicates the syntax and makes D2 much less attractive from a syntax POV. D2 will allow the following: pure invariant invariant(int) func(invariant(int)) nothrow; Am I the only one that thinks the above is too much? It's time for a standardized Annotations/Attributes mechanism for D. I'll post my initial suggestion for such a mechanism in a new thread. --Yigal

While attributes are a nice idea for somethings; for things like invariants it would make the client syntax more difficult to read. Also invariant const etc.. could not go into the standard lib because then the compiler would make it much more difficult for the compiler to perform optimizations (Walters point 2). Also it would be more difficult to extend the concept of invariants; for example, to something like functional programming because of attribute system limitations. If your moving something like invariants to attributes, don't forget your not actually reducing the complexity to the end user. Now they have to figure-out what the standard lib is doing also. The complexity only reduces for the compiler writer. -Joel
Apr 25 2008
parent reply Yigal Chripun <yigal100 gmail.com> writes:
janderson wrote:
 
 While attributes are a nice idea for somethings; for things like
 invariants it would make the client syntax more difficult to read.  Also
 invariant const etc.. could not go into the standard lib because then
 the compiler would make it much more difficult for the compiler to
 perform optimizations (Walters point 2).
 
 Also it would be more difficult to extend the concept of invariants; for
 example, to something like functional programming because of attribute
 system limitations.
 
 If your moving something like invariants to attributes, don't forget
 your not actually reducing the complexity to the end user.  Now they
 have to figure-out what the standard lib is doing also.  The complexity
 only reduces for the compiler writer.
 
 -Joel

Regarding optimizations, I don't know if it would be possible with attributes - I guess it depends on the compiler APIs exposed to the attribute writer. I do agree that not _all_things_ should be implemented as attributes. The invariants are a bad example and I just used that to illustrate how complex the D syntax has become. It's like the type system - D provides a a set of built in primitive types like int,char,long,etc.. and a way to use those to create your own via classes/unions/structs... so it may make sense to have a built-in const but IMO nothrow doesn't deserve the same status. I'm also not sure that pure should be provided by D. Look at the link bellow for a Java DBC using annotations. Seems much better than what D provides (nothing.. since it's not implemented). Since D is not backed up by a giant like Sun/MS/Google/etc it makes sense to delegate these features to the community, since it's obvious not high on Walter's todo list and annotations make perfect sense for that. Note, you mention "attribute system limitations" - since D does have that system yet, we do not know what limitations D's system would have compared to the .net or Java implementations. http://en.wikipedia.org/wiki/Java_Modeling_Language
Apr 25 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Yigal Chripun wrote:
 Since D is not backed up by a giant like Sun/MS/Google/etc it makes
 sense to delegate these features to the community, since it's obvious
 not high on Walter's todo list and annotations make perfect sense for that.

If attributes had meaning only in a library or for some special tool, the compiler cannot extract any useful information from them.
Apr 25 2008
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Walter Bright wrote:
 Yigal Chripun wrote:
 Since D is not backed up by a giant like Sun/MS/Google/etc it makes
 sense to delegate these features to the community, since it's obvious
 not high on Walter's todo list and annotations make perfect sense for
 that.

If attributes had meaning only in a library or for some special tool, the compiler cannot extract any useful information from them.

if the compiler provides hooks for the attribute writers than an attribute would have meaning for the compiler. for example, it should be possible to write a user defined attribute and via a hook, tell the compiler to verify transitivity of it at compile time. BTW, what information does the compiler extract from an attribute? wouldn't it be enough to use the above approach to tell the compiler what to do for each attribute? --Yigal
Apr 25 2008
next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Janice Caron wrote:
 On 25/04/2008, Yigal Chripun <yigal100 gmail.com> wrote:
 if the compiler provides hooks for the attribute writers than an
  attribute would have meaning for the compiler.

I don't agree. I think Walter's right. An attribute is a contract, and only the compiler is in a position to enforce that code complies with contracts. For example, suppose I wanted an attribute that meant "this function does not modify static members" - what kind of "hooks" would make it possible to enforce that contract, if it were not built into the compiler?

if I understand you correctly, you want a function that receives an instance of some class and an attribute that makes sure that the above function does not modify any static members (data members) of that instance. I'm not sure how the compiler can verify that at all due to polymorphism - the dynamic type of the instance will be known only at run-time. maybe something like the following can work: you should be able to get a list of all the static members of an instance via introspection and for each of those, you'd need to check in your attribute implementation that the old value (before executing the function body) is the same as the one after executing the function body. what if there was a way to "keep" the old value? than you'd throw an exception if (old(var) != var). I don't understand how this can be checked by the compiler at all (even if the attribute is not user defined) without analyzing the entire code of the program. if you compile only one module the compiler does not know if there are derived classes that add more static data members. I'm not sure I'm correct on all of this so please point out errors. somewhat confused, Yigal
Apr 25 2008
parent Yigal Chripun <yigal100 gmail.com> writes:
Janice Caron wrote:
 On 25/04/2008, Yigal Chripun <yigal100 gmail.com> wrote:
 if I understand you correctly, you want

No, I was merely postulating. It's not something I want, it was merely an example of something the compiler could do that a library add-on couldn't.
  I'm not sure how the compiler can verify that at all due to polymorphism
  - the dynamic type of the instance will be known only at run-time.

Who cares? If I'm going to invent an arbitrary attribute, I can define it to do anything I want. Besides, structs have a "this", but not polymorphism, so the compiler could certainly check in the case of structs. To give an even sillier example, a compiler could introduce a function attribute that meant "this function will not modify any variable starting with the letter x". I don't see how an add-on could do that through hooks.

I don't understand what you're trying to say here... anyway, I've searched the Java docs to see How Java works with annotations.I've found [1] which is a reflective API for build-time. This API provides information about the source code of a program. java 5 had a tool called apt that as of java 6 is part of the compiler, it runs annotation processors on the code. (these are Java programs that use the APIs in [1] and [2] and generate new source files) [1]http://java.sun.com/javase/6/docs/jdk/api/apt/mirror/overview-summary.html [2]http://java.sun.com/javase/6/docs/technotes/guides/apt/index.html --Yigal
Apr 25 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Yigal Chripun wrote:
 BTW, what information does the compiler extract from an attribute?

With nothrow, for example, it can verify that the code inside the function cannot propagate an exception outside of it. I have no idea how you could do that with a user defined attribute.
Apr 25 2008
parent Max Samukha <nospam nospam.com> writes:
On Fri, 25 Apr 2008 14:10:23 -0700, Walter Bright
<newshound1 digitalmars.com> wrote:

Yigal Chripun wrote:
 BTW, what information does the compiler extract from an attribute?

With nothrow, for example, it can verify that the code inside the function cannot propagate an exception outside of it. I have no idea how you could do that with a user defined attribute.

Like in .NET. And the proposed syntax was taken from C#. A number of intrinsic attributes are treated specially by the IL compiler. For example, DllImport, Obsolete, MarshalAs, StructLayout etc. .NET has a nice extensible attribute system. User defined attributes can be inspected through reflection at run-time. I guess, D could allow to do that at compile time as well.
Apr 26 2008
prev sibling parent Christopher Wright <dhasenan gmail.com> writes:
Walter Bright wrote:
 Janice Caron wrote:
 So I guess my question is, in what circumstance would "nothrow" be
 helpful? And is it helpful /enough/ to warrant "polluting" all library
 code with "nothrow" annotations?

"nothrow" is, as you say, a contract. It specifies that a function must return normally (unless it aborts, crashes, or hangs). Such annotations: 1. improves the API documentation 2. enables significantly better code generation (if you use a lot of scope statements and struct destructors) 3. nothrow can be very useful in building up transactions, because you know that the components cannot fail 4. destructors cannot throw exceptions (because they are already in one). Andrei has proposed a method to deal with this, but it is as yet unimplemented. For more info, see http://www.gotw.ca/gotw/082.htm and http://www.boost.org/community/exception_safety.html

It's a usability argument that Janice is making. She isn't saying that nothrow lacks benefits.
Apr 25 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 25/04/2008, Yigal Chripun <yigal100 gmail.com> wrote:
 if the compiler provides hooks for the attribute writers than an
  attribute would have meaning for the compiler.

I don't agree. I think Walter's right. An attribute is a contract, and only the compiler is in a position to enforce that code complies with contracts. For example, suppose I wanted an attribute that meant "this function does not modify static members" - what kind of "hooks" would make it possible to enforce that contract, if it were not built into the compiler?
Apr 25 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 25/04/2008, Yigal Chripun <yigal100 gmail.com> wrote:
 if I understand you correctly, you want

No, I was merely postulating. It's not something I want, it was merely an example of something the compiler could do that a library add-on couldn't.
  I'm not sure how the compiler can verify that at all due to polymorphism
  - the dynamic type of the instance will be known only at run-time.

Who cares? If I'm going to invent an arbitrary attribute, I can define it to do anything I want. Besides, structs have a "this", but not polymorphism, so the compiler could certainly check in the case of structs. To give an even sillier example, a compiler could introduce a function attribute that meant "this function will not modify any variable starting with the letter x". I don't see how an add-on could do that through hooks.
Apr 25 2008
prev sibling next sibling parent reply "Ameer Armaly" <ameer.armaly furman.edu> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message 
news:mailman.465.1209106347.2351.digitalmars-d puremagic.com...
 D2.013 just added the "nothrow" keyword, so that one can write, e.g.

a grain of salt: It seems to me that the compiler could figure out whether or not a function throws exceptions and act accordingly; I really don't see why it needs to be told. That means the only real use of nothrow that I could see would be to say that you don't want this function ever throwing an exception in any current or future incarnation.
    inf f() nothrow
    {
        return 42;
    }

 to indicate that f does not throw an exception. My question is, what's
 the point?

 The documentation notes that the semantics are not implemented, but I
 have to ask, why is this desirable in general?

 Like any annotation, "nothrow" indicates a /contract/. Like any
 annation, there are two rules

 (1) if a function is annotated with the nothrowkeyword, then the
 compiler will emit a compile error within the function body, if the
 function body of f throws an exception.

 (2) if the caller of a function requires that the the called function
 not throw any exceptions, then the compiler will emit a compile error
 at the caller site if the callee is not annotated with the nothrow
 keyword.

 Rule one helps the human. Rule two helps the compiler - but positively
 /hinders/ the human. The problem is one of logical fallacy - given the
 proposition "all dogs have four legs", one may /not/ assume that if it
 has four legs, it must be a dog. Likewise, given the proposition "any
 function decorated with the nothrow keyword will not throw an
 exception", one may /not/ assume that if it doesn't throw an
 exception, then it will be decorated with the nothrow keyword. Here's
 a simple counterexample:

    int f() { return 42; }
    int g() nothrow { return f(); }

 Once the semantics of nothrow are implemented, the above code will not
 compile. This is because, /even though/ f doesn't throw any
 exceptions, the compiler isn't able to prove that (or at least, can't
 be bothered to prove that) at the time g is compiled.

 Like all annotations, "nothrow" therefore /propogates/ throughout
 code. In order to get the above to compile, the user must now decorate
 f.

 This is all very well, unless f is in a library, and the user is
 unable to modify f. In that case, presumably the user must do
 something like:

    int g() nothrow { return cast(nothrow) f(); }

 or perhaps

    int g() nothrow
    {
        try { return f(); }
        catch(Exception e) { return 0; }
    }

 Sure - we could decorate /every/ function which does not throw an
 exception with "nothrow", but are we really going to do that?

 So I guess my question is, in what circumstance would "nothrow" be
 helpful? And is it helpful /enough/ to warrant "polluting" all library
 code with "nothrow" annotations? 

Apr 26 2008
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On 26/04/2008, Ameer Armaly <ameer.armaly furman.edu> wrote:
  It seems to me that the compiler could figure out whether or not a function
  throws exceptions and act accordingly;

Without the nothrow keyword, the only way it could do that is by checking not only the function itself, but the function bodies of all functions called by the function, and so, recursively, forever.
 I really don't see why it needs to be
 told.

With nothrow, it doesn't have to recurse.

Yeh, it's the same problem with deducing things like pure and const (which is the conclusion I came to following our previous discussion on the topic... though I just let the thread fizzle rather than stating this conclusion.). If you want to have the benefits of separate compilation then you have to tell the compiler what to expect of functions without it having to have the bodies of those functions present. --bb
Apr 26 2008
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 26/04/2008, Ameer Armaly <ameer.armaly furman.edu> wrote:
  It seems to me that the compiler could figure out whether or not a function
  throws exceptions and act accordingly;

Without the nothrow keyword, the only way it could do that is by checking not only the function itself, but the function bodies of all functions called by the function, and so, recursively, forever.
 I really don't see why it needs to be
 told.

With nothrow, it doesn't have to recurse.
Apr 26 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Janice Caron" wrote
 On 26/04/2008, Ameer Armaly wrote:
  It seems to me that the compiler could figure out whether or not a 
 function
  throws exceptions and act accordingly;

Without the nothrow keyword, the only way it could do that is by checking not only the function itself, but the function bodies of all functions called by the function, and so, recursively, forever.

Enter your algorithmic friend, memoization :) The compiler could store attributes with the functions as they are compiled, marking ones which don't throw exceptions and ones which are pure, etc. in the object files. The only issue then is if you are a developer and you desire a function to be a nothrow, it must be marked by the developer. Otherwise it's like inlining. You never know which functions will be marked nothrow/pure and which ones will not. It also becomes a question of maintainability, if one makes a change in a nothrow function that throws an exception, this is no good for dynamic libraries, who may depend on it keeping the nothrow status. -Steve
Apr 28 2008