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
↑ ↓←→ 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
↑ ↓←→ 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/
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
↑ ↓ ←→ 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
↑ ↓ ←→ 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
↑ ↓← → 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
↑ ↓ ← → 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.
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
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
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
↑ ↓ ←→ 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.
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
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
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
↑ ↓ ←→ 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.
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
↑ ↓ ← → 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.
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?
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.
"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
↑ ↓ ← → 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
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.
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