C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

[Proposal] noreturn_t
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
Andrei Polushin
Guest





PostPosted: Sun Oct 22, 2006 6:09 pm    Post subject: [Proposal] noreturn_t Reply with quote



Hi,

I propose to add a special type, std::noreturn_t, to indicate that
function does never return.

Actually, some compilers have the similar feature, known as either
__declspec(noreturn) or __attribute__ ((noreturn)), but it is used
primarily for optimization purposes and does not affect language.

I suggest using it for strict type checking too, so std::noreturn_t
is not an "attribute", but a type that affects a function signature.

In addition, I suggest the "throw" expression to return "noreturn_t"
instead of "void", see rationale and use case below.

Use cases
---------

Starting from the simplest problem, consider the following code,
which does not compile:

// never returns
void throw_out_of_range(size_type n, size_type m)
{
ostringstream os;
os << "value " << n << " is out of range [0," << m << ")";
throw out_of_range(os.str());
}

// throws if n is out of range [0,size)
reference at(size_type n)
{
if (0 <= n && n < size()) {
return data[n];
}
throw_out_of_range(n, size());
// *error: function "at" should return a value*
}

Yes, we can revert the "if" condition to avoid an error, but why we
need to? Anyway, another example (adapted from boost::lexical_cast):

// never returns
void throw_io_failure()
{
throw ios_base::failure("I/O failure");
}

// throws if I/O failed
char get(const char* prompt) {
char c;
if (!(cout << prompt && cin >> c)) {
throw_io_failure();
}
// *warning: potentially uninitialized variable returned*
return c;
}

Thus we have a spurious warning.

In the following case we will see no warning, where it should be:

int f()
{
abort();

// *no warning about unreachable code*
int n = 22;
return n;
}

More serious case, when the function returns, but nobody expects this:

void hello()
{
cout << "Hello, World!" << endl;
}

set_unexpected(hello);
unexpected();
// execution continues after call to unexpected ?

In the last case, we can know the problem at compile time, imagine
set_unexpected() will accept only handlers that never return:

namespace std
{
typedef noreturn_t (*unexpected_handler)();

unexpected_handler set_unexpected(unexpected_handler f);
}

void hello()
{
cout << "Hello, World!" << endl;
}

std::noreturn_t bye()
{
cout << "Bye, World!" << endl;
// *error: "bye" should never return*
}

set_unexpected(hello); // cannot cast to unexpected_handler
set_unexpected(bye); // ok


Compatibility
-------------

1. Existing C++ implementations that do not check for non-returning
functions, may declare a no-op type:

namespace std
{
typedef void noreturn_t;
}

2. The existing code will fail to compile if it takes the address of
function redeclared with std::noreturn_t return type:

typedef void (*handler)();
void abort_workaround() { abort(); }

handler h = &abort; // error: cannot convert
handler h = &abort_workaround; // ok: workaround

This incompatibility is intentional.

3. Similarly, set_unexpected() etc. will not accept address of
functions that return void, which is also intentional.

4. All control paths of a function that never returns should end
with a call to a function that never returns, or with a throw
statement. This is the direct intent.


Throw expression and noreturn_t
-------------------------------

Throw expression should return std::noreturn_t instead of void, and
the type noreturn_t should be convertible to bool:

namespace std
{
struct noreturn_t {
operator bool() { return false; }
};
}

This allows a Perl-like syntax for checking return value:

cin >> c || throw io_failure("Cannot read from cin");

(Idea inspired by recent posting of Alf P. Steinbach in c.l.c++.m:
http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/85b034283152115e/ee9b31479b8c1e0e?#ee9b31479b8c1e0e
)

The name "noreturn_t" is inspired by std::nothrow_t.


Conclusion
----------

Having noreturn_t, we achieve:

- better compile-time control path analysis,
- better runtime error checking syntax,
- easier optimizable code,

Is it useful? I'm waiting for your comments.


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Sun Oct 22, 2006 8:19 pm    Post subject: Re: [Proposal] noreturn_t Reply with quote



Andrei Polushin ha scritto:
Quote:

I propose to add a special type, std::noreturn_t, to indicate that
function does never return.

snip

Conclusion
----------

Having noreturn_t, we achieve:

- better compile-time control path analysis,
- better runtime error checking syntax,
- easier optimizable code,

Is it useful? I'm waiting for your comments.

Even if it's a change that might break backward compatibility, I like it
and find it useful. Just three comments:

1) I would not allow implementations to define std::noreturn_t as a
typedef to void. In fact I would explicitly disallow such possibility.
If we allow it, the code:

typedef std::noreturn_t (*doesnt_return)();
void set_handler(doesnt_return f);

void bye();
set_handler(bye);

might compile on a conforming compiler and not on another conforming
compiler.

2) About set_unexpected and set_terminate, I think that changing
signatures of existing library function is unacceptable. I would just
add overloads. That would rip a little hole in the system, but otherwise
it looks like a showstopper to me.

3) I am a bit concerned with the implicit conversion to bool. Although I
don't dislike the perl-like syntax, having an implicit conversion would
make the entire proposal pointless, because you might then use
noreturn_t in a lot more places than we actually want. Even the idiom
"implicit conversion to unspecified-bool-type" (as used tr1::shared_ptr,
for example) is not good enough, IMHO. I don't see any alternative
except to explicitly allow built-in operator || and && (and *only* them,
no overloads!) to take as their second operand an expression of type
noreturn_t.

Just my 2 eurocent,

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Alexandrescu (See
Guest





PostPosted: Mon Oct 23, 2006 1:38 am    Post subject: Re: [Proposal] noreturn_t Reply with quote



Andrei Polushin wrote:
Quote:
I propose to add a special type, std::noreturn_t, to indicate that
function does never return.

Actually, some compilers have the similar feature, known as either
__declspec(noreturn) or __attribute__ ((noreturn)), but it is used
primarily for optimization purposes and does not affect language.

There is precedent in the Cecil language as well (the "none" type).

Quote:
Throw expression should return std::noreturn_t instead of void, and
the type noreturn_t should be convertible to bool:

Actually the type noreturn_t should be convertible to any other type.
That makes it the bottom of the type hierarchy, where it belongs.

I implemented and used such a type in existing C++, and found it
marginally useful. I personally don't think it's a compelling feature to
add to the language.


Andrei

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
John Nagle
Guest





PostPosted: Mon Oct 23, 2006 5:45 am    Post subject: Re: [Proposal] noreturn_t Reply with quote

James Dennett wrote:
Quote:
Alberto Ganesh Barbati wrote:

Andrei Alexandrescu (See Website For Email) ha scritto:

Andrei Polushin wrote:

I propose to add a special type, std::noreturn_t, to indicate that
function does never return.

It's not a compelling feature, but if added, it needs to be
part of the declaration, not the implementation, where
the caller can see it.

Realistically, though, it doesn't have much optimization
value. Functions that don't return tend not to be called
many times. (You could potentially have a function
that never returned normally, but could throw an exception.
This might be useful when starting up some task which
normally runs forever but could fail, throw, and be restarted
by its caller.)

John Nagle
Animats

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Mon Oct 23, 2006 6:12 am    Post subject: Re: [Proposal] noreturn_t Reply with quote

Andrei Alexandrescu (See Website For Email) ha scritto:
Quote:
Andrei Polushin wrote:
I propose to add a special type, std::noreturn_t, to indicate that
function does never return.

Actually, some compilers have the similar feature, known as either
__declspec(noreturn) or __attribute__ ((noreturn)), but it is used
primarily for optimization purposes and does not affect language.

There is precedent in the Cecil language as well (the "none" type).

Throw expression should return std::noreturn_t instead of void, and
the type noreturn_t should be convertible to bool:

Actually the type noreturn_t should be convertible to any other type.
That makes it the bottom of the type hierarchy, where it belongs.

Why? IMHO it should behave like void, in the sense that it should not be
convertible to any type (except, possibly, void itself) so that you
cannot put it by mistake into an expression. I would also disallow the
possibility to explicitly convert an expression to noreturn_t (something
that you can do with void).

Quote:
I implemented and used such a type in existing C++, and found it
marginally useful. I personally don't think it's a compelling feature to
add to the language.

It was marginally useful because you implemented it in existing C++! The
proposal is only meaningful if the compiler is able to exploit the added
information for:

Quote:
- better compile-time control path analysis,
- better runtime error checking syntax,
- easier optimizable code,

BTW: I guess the OP meant to say "better *compile-time* error checking
syntax" not runtime. There's no syntax checking happening at runtime...

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
James Dennett
Guest





PostPosted: Mon Oct 23, 2006 6:40 am    Post subject: Re: [Proposal] noreturn_t Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
Andrei Alexandrescu (See Website For Email) ha scritto:
Andrei Polushin wrote:
I propose to add a special type, std::noreturn_t, to indicate that
function does never return.

Actually, some compilers have the similar feature, known as either
__declspec(noreturn) or __attribute__ ((noreturn)), but it is used
primarily for optimization purposes and does not affect language.

There is precedent in the Cecil language as well (the "none" type).

Throw expression should return std::noreturn_t instead of void, and
the type noreturn_t should be convertible to bool:

Actually the type noreturn_t should be convertible to any other type.
That makes it the bottom of the type hierarchy, where it belongs.

Why? IMHO it should behave like void, in the sense that it should not be
convertible to any type (except, possibly, void itself) so that you
cannot put it by mistake into an expression. I would also disallow the
possibility to explicitly convert an expression to noreturn_t (something
that you can do with void).

Typewise, I suspect it should behave like the existing
"no return" part of the language, namely "throw".

return true?throw a:foo;

is currently legal, but not because throw a has a type
that converts to anything -- rather, because if the
expression has a value at all then it was foo that was
evaluated, and so its type is used.

-- James

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Mon Oct 23, 2006 4:55 pm    Post subject: Re: noreturn_t Reply with quote

John Nagle wrote:
Quote:
Andrei Polushin wrote:
I propose to add a special type, std::noreturn_t, to indicate that
function does never return.

It's not a compelling feature, but if added, it needs to be
part of the declaration, not the implementation, where
the caller can see it.

It's just a type, so yes, it affects both the declaration and the
definition.


Quote:
Realistically, though, it doesn't have much optimization
value. Functions that don't return tend not to be called
many times.

The proposal is not about optimization only. In fact, optimization
is the last goal in the list.


Quote:
(You could potentially have a function
that never returned normally, but could throw an exception.
This might be useful when starting up some task which
normally runs forever but could fail, throw, and be restarted
by its caller.)

Thus you discovered the another third possibility for a function
constrained by std::noreturn_t return type:

1. call to a function that never returns,
2. throw an exception,
3. run into the endless loop.


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Mon Oct 23, 2006 4:55 pm    Post subject: Re: noreturn_t Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
1) I would not allow implementations to define std::noreturn_t as a
typedef to void. In fact I would explicitly disallow such possibility.
If we allow it, the code [...] might compile on a conforming compiler
and not on another conforming compiler.

Actually, I'm claiming for the same, but showing the possibility for
the user to compile his conforming code with non-conforming compiler.
Conforming compiler should define a distinct type.

Quote:
2) About set_unexpected and set_terminate, I think that changing
signatures of existing library function is unacceptable. I would just
add overloads. That would rip a little hole in the system, but
otherwise it looks like a showstopper to me.

Good. And deprecate overloads for void-returning handlers.


Quote:
3) I am a bit concerned with the implicit conversion to bool. Although I
don't dislike the perl-like syntax, having an implicit conversion would
make the entire proposal pointless, because you might then use
noreturn_t in a lot more places than we actually want. Even the idiom
"implicit conversion to unspecified-bool-type" (as used tr1::shared_ptr,
for example) is not good enough, IMHO. I don't see any alternative
except to explicitly allow built-in operator || and && (and *only* them,
no overloads!) to take as their second operand an expression of type
noreturn_t.

I tend to agree to disallow implicit conversion, and it seems I am
following your idea with built-in operators in another post.


Quote:
Just my 2 eurocent,

Thank you.


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Mon Oct 23, 2006 4:57 pm    Post subject: Re: noreturn_t Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
Andrei Alexandrescu wrote:
Actually the type noreturn_t should be convertible to any other type.
That makes it the bottom of the type hierarchy, where it belongs.

Why? IMHO it should behave like void, in the sense that it should not be
convertible to any type (except, possibly, void itself) so that you
cannot put it by mistake into an expression. I would also disallow the
possibility to explicitly convert an expression to noreturn_t (something
that you can do with void).

Andrei, I'm also surprised by your claim. I guess it results from
the special treating of /throw-expression/ in conditional operator
(as noted by James Dennett - see below), or could you elaborate?


Quote:
Andrei Alexandrescu wrote:
I implemented and used such a type in existing C++, and found it
marginally useful. I personally don't think it's a compelling feature
to add to the language.

I don't know how to implement it in existing C++, satisfying all the
use cases identified. In fact, I don't know how to completely satisfy
any of those use cases. You cannot avoid the spurious errors and
warnings mentioned, and you cannot generate correct errors and warnings
for incorrect code. You may invent a Perl-like syntax for non-returning
functions on the right side of ||, but not for /throw-expression/ in
its normal form. You may achieve a type safety for set_unexpected(),
and that's everything I can imagine.


Alberto Ganesh Barbati wrote:
Quote:
It was marginally useful because you implemented it in existing C++! The
proposal is only meaningful if the compiler is able to exploit the added
information for:

- better compile-time control path analysis,
- better runtime error checking syntax,
- easier optimizable code,

BTW: I guess the OP meant to say "better *compile-time* error checking
syntax" not runtime. There's no syntax checking happening at runtime...

No-no, namely runtime error checking *syntax* - I was talking about
the very Perl-like syntax used to check runtime errors:

cin >> c || throw failure();

And I agree that the proposal should be taken as a whole, redeclaring
"void abort()" as "noreturn_t abort()" is marginally useful in itself.


James Dennett wrote:
Quote:
Typewise, I suspect it should behave like the existing
"no return" part of the language, namely "throw".

return true?throw a:foo;

is currently legal, but not because throw a has a type
that converts to anything -- rather, because if the
expression has a value at all then it was foo that was
evaluated, and so its type is used.

I wasn't aware of this secret knowledge Smile And I know nobody using it.
But thank you, it really helps in that it's already in the standard:


5.16 Conditional operator [expr.cond]

<orginal>
2 If either the second or the third operand has type (possibly cv-
qualified) void, then the lvalue-to-rvalue (4.1), array-to-pointer
(4.2), and function-to-pointer (4.3) standard conversions are
performed on the second and third operands, and one of the
following shall hold:

- The second or the third operand (but not both) is a
/throw-expression/ (15.1); the result is of the type of the other
and is an rvalue.

- Both the second and the third operands have type void the result
is of type void and is an rvalue. [Note: this includes the case
where both operands are /throw-expressions/. - end note]
</orginal>


Looks like we can restate it like this:


<replacement>
2a If either the second or the third operand (but not both) has type
std::noreturn_t, then the lvalue-to-rvalue (4.1), array-to-pointer
(4.2), and function-to-pointer (4.3) standard conversions are
performed on the other operand, and the result is of the type of
the other and is an rvalue.

2b If both the second and the third operands have type void the result
is of type void and is an rvalue.
</replacement>


Now both statements are about types, no special treating for throw.

Continuing, we can express || and && in the following manner
(following the idea by Alberto Ganesh Barbati):


5.14 Logical OR operator:

If the second operand has type std::noreturn_t, the expression

first || second

is interpreted as conditional operator (5.16)

first ? second : first

but the first operand is evaluated only once. [Note: the result is
the type of the first operand after performing standard conversions
defined in 5.16, and is an rvalue. - end note]

5.15 Logical OR operator:

If the second operand has type std::noreturn_t, the expression

first || second

is interpreted as conditional operator (5.16)

first ? first : second

but the first operand is evaluated only once. [Note: the result is
the type of the first operand after performing standard conversions
defined in 5.16, and is an rvalue. - end note]


With that final note, we have more than desired.

First of all, I don't have to say that std::noreturn_t should be
convertible to bool (the proposal was criticized for that).

Next, we are allowed to obtain the result and check at the same time:

ostream& read(char& c)
{
return cin >> c || throw "Cannot read from cin";
}

FILE* open(const char* name)
{
return fopen(name, "r") || abort();
}


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Mon Oct 23, 2006 5:18 pm    Post subject: Re: noreturn_t Reply with quote

Andrei Polushin wrote:
Quote:
5.14 Logical OR operator:

If the second operand has type std::noreturn_t, the expression

first || second

Sorry for the typo, this should be written as:

5.14 Logical AND operator:

If the second operand has type std::noreturn_t, the expression

first && second

Quote:
is interpreted as conditional operator (5.16)

first ? second : first

but the first operand is evaluated only once. [Note: the result is
the type of the first operand after performing standard conversions
defined in 5.16, and is an rvalue. - end note]

5.15 Logical OR operator:

If the second operand has type std::noreturn_t, the expression

first || second

is interpreted as conditional operator (5.16)

first ? first : second

but the first operand is evaluated only once. [Note: the result is
the type of the first operand after performing standard conversions
defined in 5.16, and is an rvalue. - end note]

--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Mon Oct 23, 2006 7:17 pm    Post subject: Re: noreturn_t Reply with quote

Andrei Polushin ha scritto:
Quote:
Alberto Ganesh Barbati wrote:

No-no, namely runtime error checking *syntax* - I was talking about
the very Perl-like syntax used to check runtime errors:

cin >> c || throw failure();

Oh, sorry... I didn't get it.

Quote:
Continuing, we can express || and && in the following manner
(following the idea by Alberto Ganesh Barbati):

5.14 Logical OR operator:
(AND)

If the second operand has type std::noreturn_t, the expression

first || second
(&&)

is interpreted as conditional operator (5.16)

first ? second : first

but the first operand is evaluated only once. [Note: the result is
the type of the first operand after performing standard conversions
defined in 5.16, and is an rvalue. - end note]

5.15 Logical OR operator:

If the second operand has type std::noreturn_t, the expression

first || second

is interpreted as conditional operator (5.16)

first ? first : second

but the first operand is evaluated only once. [Note: the result is
the type of the first operand after performing standard conversions
defined in 5.16, and is an rvalue. - end note]

I like defining || and && in terms of ?:. Good idea! That implicitly
means that if the second operand of || or && is std::noreturn_t then
overloads won't be considered: the built-ins are always chosen. That's good.

BTW, I recently read that gcc allows as an extension to write "a ? : b"
with the meaning of "a ? a : b" except that a is evaluated only once.
That looks surprisingly similar to your proposed wording ;-)

Quote:
With that final note, we have more than desired.

First of all, I don't have to say that std::noreturn_t should be
convertible to bool (the proposal was criticized for that).

Yup!

Quote:
Next, we are allowed to obtain the result and check at the same time:

ostream& read(char& c)
{
return cin >> c || throw "Cannot read from cin";
}

FILE* open(const char* name)
{
return fopen(name, "r") || abort();
}

Nice! At first I felt uncomfortable to allow built-in || and && to
return something that's not a bool, but... hey! that syntax looks great!

Just my opinion,

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Alexandrescu (See
Guest





PostPosted: Tue Oct 24, 2006 5:01 am    Post subject: Re: noreturn_t Reply with quote

Andrei Polushin wrote:
Quote:
Alberto Ganesh Barbati wrote:
Andrei Alexandrescu wrote:
Actually the type noreturn_t should be convertible to any other type.
That makes it the bottom of the type hierarchy, where it belongs.
Why? IMHO it should behave like void, in the sense that it should not be
convertible to any type (except, possibly, void itself) so that you
cannot put it by mistake into an expression. I would also disallow the
possibility to explicitly convert an expression to noreturn_t (something
that you can do with void).

Andrei, I'm also surprised by your claim. I guess it results from
the special treating of /throw-expression/ in conditional operator
(as noted by James Dennett - see below), or could you elaborate?

The idea is more general; I stole it from the Cecil language, which has
a "none" type at the bottom of the type hierarchy, meaning that it is a
subtype of any other type. One nice intuition is that "any" (the most
general object - the union of all possible types) is at the top of the
type hierarchy, and therefore "none" (the void set - the intersection of
all possible types) is at the bottom.

The rationale is this: a function that never return could statically
claim it returns any type, because a return will never substantiate. As
many people have noticed, this particularity confers "none" remarkable
expressiveness.

Quote:
Andrei Alexandrescu wrote:
I implemented and used such a type in existing C++, and found it
marginally useful. I personally don't think it's a compelling feature
to add to the language.

I don't know how to implement it in existing C++, satisfying all the
use cases identified. In fact, I don't know how to completely satisfy
any of those use cases. You cannot avoid the spurious errors and
warnings mentioned, and you cannot generate correct errors and warnings
for incorrect code. You may invent a Perl-like syntax for non-returning
functions on the right side of ||, but not for /throw-expression/ in
its normal form. You may achieve a type safety for set_unexpected(),
and that's everything I can imagine.

Of course you can't do in a library what can be done in the language. My
implementation goes like:

struct None {
None() { throw "can't happen"; }
None(const None&) {}
template <class T> operator T&() const {
throw "can't happen";
return *this;
}
};

Quote:
Alberto Ganesh Barbati wrote:
It was marginally useful because you implemented it in existing C++! The
proposal is only meaningful if the compiler is able to exploit the added
information for:

- better compile-time control path analysis,
- better runtime error checking syntax,
- easier optimizable code,
BTW: I guess the OP meant to say "better *compile-time* error checking
syntax" not runtime. There's no syntax checking happening at runtime...

No-no, namely runtime error checking *syntax* - I was talking about
the very Perl-like syntax used to check runtime errors:

cin >> c || throw failure();

And I agree that the proposal should be taken as a whole, redeclaring
"void abort()" as "noreturn_t abort()" is marginally useful in itself.

As an aside, I disagree with the idea of making "none" an exception for
operators && and ||. Instead, a "none" type that converts to anything
could work in conjunction with operators || and && if the language
preserved the type of the operators: operator|| would return its first
argument (whatever its type is) if it evaluates to nonzero, and its
second argument otherwise. Similarly, operator&& would return its first
argument if it does NOT evaluate to nonzero, and its second argument
otherwise.

But, while sensible, these all are changes that are too far-reaching and
with too little benefits to be considered seriously.


Andrei

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Tue Oct 24, 2006 5:24 pm    Post subject: Re: noreturn_t Reply with quote

Andrei Alexandrescu wrote:
Quote:
The idea is more general; I stole it from the Cecil language, which has
a "none" type at the bottom of the type hierarchy, meaning that it is a
subtype of any other type. One nice intuition is that "any" (the most
general object - the union of all possible types) is at the top of the
type hierarchy, and therefore "none" (the void set - the intersection of
all possible types) is at the bottom.

As I see it, your reasoning is true, when applied to dynamically typed
language:

struct any {};
struct derived : any { void f(); }

any a = derived();
a.f(); // ok, f() is found dynamically

but it could not be applied to statically typed C++:

struct any { virtual ~any() {} };
struct derived : any { void f(); }

any a = derived();
a.f(); // error, f() is not a member of "any"

derived& d = dynamic_cast<derived&>(a)
d.f(); // ok, f() is a member of "derived"

Therefore, C++ have "void" (intersection of types) at the top of the
hierarchy, and "any" (union of types) at the bottom, while the
dynamically typed language have them in reverse order.


Quote:
The rationale is this: a function that never return could statically
claim it returns any type, because a return will never substantiate. As
many people have noticed, this particularity confers "none" remarkable
expressiveness.

Again, we will notice that "return will never substantiate" at runtime,
so it fits well into dynamically typed phylosophy only.


Quote:
My implementation goes like:

struct None {
None() { throw "can't happen"; }
None(const None&) {}
template <class T> operator T&() const {
throw "can't happen";
return *this;
}
};

Which is a good example of implementing it in a dynamically typed way.


Quote:
As an aside, I disagree with the idea of making "none" an exception for
operators && and ||. Instead, a "none" type that converts to anything
could work in conjunction with operators || and && if the language
preserved the type of the operators: operator|| would return its first
argument (whatever its type is) if it evaluates to nonzero, and its
second argument otherwise. Similarly, operator&& would return its first
argument if it does NOT evaluate to nonzero, and its second argument
otherwise.

But, while sensible, these all are changes that are too far-reaching and
with too little benefits to be considered seriously.

It reaches too far to Perl, because Perl has exactly that semantics for
its || and &&. By the way, I like Perl, but this behavior is absolutely
incompatible with statically typed nature of C++.


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Alexandrescu (See
Guest





PostPosted: Tue Oct 24, 2006 7:35 pm    Post subject: Re: noreturn_t Reply with quote

Andrei Polushin wrote:
Quote:
Andrei Alexandrescu wrote:
The idea is more general; I stole it from the Cecil language, which has
a "none" type at the bottom of the type hierarchy, meaning that it is a
subtype of any other type. One nice intuition is that "any" (the most
general object - the union of all possible types) is at the top of the
type hierarchy, and therefore "none" (the void set - the intersection of
all possible types) is at the bottom.

As I see it, your reasoning is true, when applied to dynamically typed
language:

struct any {};
struct derived : any { void f(); }

any a = derived();
a.f(); // ok, f() is found dynamically

but it could not be applied to statically typed C++:

struct any { virtual ~any() {} };
struct derived : any { void f(); }

any a = derived();
a.f(); // error, f() is not a member of "any"

derived& d = dynamic_cast<derived&>(a)
d.f(); // ok, f() is a member of "derived"

Therefore, C++ have "void" (intersection of types) at the top of the
hierarchy, and "any" (union of types) at the bottom, while the
dynamically typed language have them in reverse order.

I am sorry, I am unable to make sense on where dynamism comes into play
into our discussion of functions that don't return. I can't also
understand what the examples are emphasizing. The best I can do given
the circumstances is trying to re-explain myself in different words.

In any statically-typed language with objects linked by inheritance
relationships (a directed acyclic graph (DAG) with one or more roots),
we could think of two particular nodes: the "top" of the graph (an
existing or imaginary node to which all of the roots of the graph
point), and the "bottom" (an existing or imaginary node that points to
all of the leaves in the graph).

By "points to" above I mean "has a directed arrow from itself to".

The top and the bottom nodes in the DAG correspond to two types with
certain properties. The language may or may not define them. Let's take
a look at the properties.

Top: is the most general type that comprehends all other types. In
inclusion polymorphism (= usual, C++/Java/C# etc.), top can be thought
of as the union of all static types. In Java "Object" is that type. C++
does not prescribe a top type. Claiming that void is that type of C++
would be quite a stretch as void is a type that cannot have a value. It
might be safer to say that void* is the top of all pointer types.

Bottom: is the most particular type, one that inherits every other type
in the typed universe. Because multiple inheritance is intersection of
types, bottom is the intersection of all types. If the typed universe is
considered potentially infinite (a reasonable assumption), bottom cannot
have an instance. Due to its position in the graph, bottom can
statically be converted to any type.

Quote:
My implementation goes like:

struct None {
None() { throw "can't happen"; }
None(const None&) {}
template <class T> operator T&() const {
throw "can't happen";
return *this;
}
};

Which is a good example of implementing it in a dynamically typed way.

I don't understand where dynamism intervenes.


Andrei

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Wed Oct 25, 2006 12:16 am    Post subject: Re: noreturn_t Reply with quote

Andrei Alexandrescu wrote:
Quote:
The idea is more general; I stole it from the Cecil language, which has
a "none" type at the bottom of the type hierarchy, meaning that it is a
subtype of any other type. One nice intuition is that "any" (the most
general object - the union of all possible types) is at the top of the
type hierarchy, and therefore "none" (the void set - the intersection of
all possible types) is at the bottom.

Well, sorry, I've misunderstand the "void set" as "void type".

Quote:
Top: is the most general type that comprehends all other types. In
inclusion polymorphism (= usual, C++/Java/C# etc.), top can be thought
of as the union of all static types. In Java "Object" is that type. C++
does not prescribe a top type. Claiming that void is that type of C++
would be quite a stretch as void is a type that cannot have a value. It
might be safer to say that void* is the top of all pointer types.

Now I clearly see that you mean that "type void" == "type any" is
at the top.

Quote:
Bottom: is the most particular type, one that inherits every other type
in the typed universe. Because multiple inheritance is intersection of
types, bottom is the intersection of all types. If the typed universe is
considered potentially infinite (a reasonable assumption), bottom cannot
have an instance. Due to its position in the graph, bottom can
statically be converted to any type.

And the type "none" is at the bottom. OK. Trying to live with this.

Simple question: having the imaginary variable of type "none", can I
access its methods? As far as I know at this time, the type "none"
derives from Object, File, std::string, float and everything else,
so I write:

void f(const none& x) {
x.File::read();
}

Probably, I will be never allowed to instantiate the object of type
"none", but when do I know about that? Only at runtime?

So this code compiles?

--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.