Topic: Should flowing off the end of a value-returning function be illegal?
Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: 27 Sep 2005 02:00:15 GMT Raw View
Francis Glassborow wrote:
> In article <1126787893.367671.41500@g14g2000cwa.googlegroups.com>,
> ThosRTanner <ttanner2@bloomberg.net> writes
> >The compiler can, however, check for violations of the language
> >contract "you can't drop off the end of a function that returns a
> >value", even on the basis of "if I can't tell you won't get here, I'll
> >assume you will".
>
> Which leads to the silly coding style of always ending a function with a
> return statement to keep the compiler happy even though you know that it
> will never be executed.
It does require a level of intelligence from the compiler:
a)The compiler needs to be able to detect infinite loops, and realise
you'll never execute the code afterwards - most optimisers do this
anyway.
b) There's probably the need for a 'no return' type keyword. So that a
function can be declared as 'noreturn xxxx()' - i.e. the function
behaves like exit or assert(false), and will never, ever, ever return.
I realise there is a lot of pressure against adding new keywords, so
I'd suggest something like 'void void func(...)' as being reasonably
clear (I thought about 'void return func(...)' but that's probably too
counterintuitive).
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: brangdon@cix.co.uk (Dave Harris)
Date: Sat, 17 Sep 2005 17:09:50 GMT Raw View
kanze@gabi-soft.fr (kanze) wrote (abridged):
> I don't think you really understood my objections to fixing it.
> I'm all in favor of a maximum of safety. But the difference
> here with Java is notable: in Java, you can only return a
> pointer or a built in type, so in every case, there is a trival
> default that you can use, even if you know that you will never
> get there. In C++, you can return complex value types, and
> there are cases where there is no reasonable default available,
> even if you know that it will never be used.
Surely you can always use:
return *(MyType*) 0;
and this could be wrapped up in a suitably-named template or macro:
return unreachable_value<MyType>();
or whatever. I'd have thought this would only fail if the type has no
accessible copy-constructor, in which case we shouldn't be returning it in
the first place.
-- Dave Harris, Nottingham, UK.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: rogero@howzatt.demon.co.uk
Date: Sat, 17 Sep 2005 12:11:49 CST Raw View
Francis Glassborow wrote:
> Which leads to the silly coding style of always ending a function with a
> return statement to keep the compiler happy even though you know that it
> will never be executed.
Unfortunately we programmers have a poor record of success with
statements like:
"... know it will never be ..."
Personally I'd like a warning by default, and an explicit way to turn
it off.
That way when the code changes there is a reminder that I turned the
warning off.
Roger Orr
--
MVP in C++ at www.brainbench.com
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Sun, 18 Sep 2005 08:12:45 GMT Raw View
Dave Harris wrote:
> kanze@gabi-soft.fr (kanze) wrote (abridged):
>
>>I don't think you really understood my objections to fixing it.
>>I'm all in favor of a maximum of safety. But the difference
>>here with Java is notable: in Java, you can only return a
>>pointer or a built in type, so in every case, there is a trival
>>default that you can use, even if you know that you will never
>>get there. In C++, you can return complex value types, and
>>there are cases where there is no reasonable default available,
>>even if you know that it will never be used.
There's always "throw". Which is the right answer in this case.
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.jamesd.demon.co.uk/csc/faq.html ]
Author: James Kanze <kanze@none.news.free.fr>
Date: 18 Sep 2005 21:50:02 GMT Raw View
Francis Glassborow wrote:
> In article
> <1126787893.367671.41500@g14g2000cwa.googlegroups.com>,
> ThosRTanner <ttanner2@bloomberg.net> writes
>> The compiler can, however, check for violations of the
>> language contract "you can't drop off the end of a function
>> that returns a value", even on the basis of "if I can't tell
>> you won't get here, I'll assume you will".
> Which leads to the silly coding style of always ending a
> function with a return statement to keep the compiler happy
> even though you know that it will never be executed.
It's not so much that it is silly, as that sometimes, it is
downright difficult to find a value that you can return. I
guess something like :
return *(MyType*)0 ;
would be acceptable regardless of the MyType (no default
constructor, etc.), but somehow, I just don't like writing such
things.
--
James Kanze mailto: james.kanze@free.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre S mard, 78210 St.-Cyr-l' cole, France +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@none.news.free.fr (James Kanze)
Date: Sun, 18 Sep 2005 21:49:33 GMT Raw View
Ian wrote:
> kanze wrote:
>> I don't think you really understood my objections to fixing
>> it. I'm all in favor of a maximum of safety. But the
>> difference here with Java is notable: in Java, you can only
>> return a pointer or a built in type, so in every case, there
>> is a trival default that you can use, even if you know that
>> you will never get there. In C++, you can return complex
>> value types, and there are cases where there is no reasonable
>> default available, even if you know that it will never be
>> used. To introduce a requirement here would either require
>> the compiler to be able to do all of the necessary analysis
>> (which in turn means cross-module flow analysis), or to ban
>> returning values, at least of user defined types. Not only
>> would this break almost all existing applications, it would
>> introduce any number of lifetime of object issues. IMHO, the
>> ability to return values is more important than catching the
>> few errors which result from this not being controlled.
> Going off on a bit of a tangent, but isn't the existence of
> functions that might not return what they say they will a code
> smell?
It depends. I thought I gave an example elsewhere. The
classical example, of course, is an interface with optional
functionality and the ability to test whether the functionality
is present. Something like:
class Interface
{
public:
virtual bool supportsGetWhatever() const =3D 0 ;
virtual Whatever getWhatever() =3D 0 ;
// ...
} ;
Given that, I would consider perfectly reasonable something
like:
class Concrete : public Interface
{
public:
virtual bool supportsGetWhatever() const
{
return false ;
}
virtual Whatever getWhatever()
{
fatalError( "getWhatever called on Concrete" ) ;
}
} ;
Of course, you could just as easily have a case where the
operation was only supported in certain states, and a particular
derived class where none of those states were possible.
> All I was asking for was a diagnostic or error if each branch
> within a function didn't return the correct type. Whether or
> not a function throws an exception isn't relevant.
Consider cases like the above, where the function doesn't ever
return. And where the return type has no default constructor,
so there is no simple value available for a dummy return.
--=20
James Kanze mailto: james.kanze@free.fr
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 =
34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@none.news.free.fr (James Kanze)
Date: Sun, 18 Sep 2005 21:49:55 GMT Raw View
Dave Harris wrote:
> kanze@gabi-soft.fr (kanze) wrote (abridged):
>>I don't think you really understood my objections to fixing
>>it. I'm all in favor of a maximum of safety. But the
>>difference here with Java is notable: in Java, you can only
>>return a pointer or a built in type, so in every case, there
>>is a trival default that you can use, even if you know that
>>you will never get there. In C++, you can return complex
>>value types, and there are cases where there is no reasonable
>>default available, even if you know that it will never be
>>used.
> Surely you can always use:
> return *(MyType*) 0;
The thought did occur to me, but I find this a little too ugly
for general use. At the least, if I saw it in someone else's
code, I'd wonder about the author's competence.
> and this could be wrapped up in a suitably-named template or macro:
> return unreachable_value<MyType>();
> or whatever. I'd have thought this would only fail if the type
> has no accessible copy-constructor, in which case we shouldn't
> be returning it in the first place.
Formally, the statement contains undefined behavior. But if
we never execute it. I hadn't thought of the idea of wrapping
it in a template like this, with a name which explains why we're
using it.
On the other hand... if we're going to start down this road,
let's do it right. Introduce some means of saying that a
function never returns, for example -- maybe a return type of
"void void". I think that with very, very few additions, we
could reach a point where the compiler could decide, at least in
almost all reasonable cases. Of course, there is the problem of
backwards compatible -- my "fatalError" function doesn't return
"void void" at present.
--=20
James Kanze mailto: james.kanze@free.fr
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 =
34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@none.news.free.fr (James Kanze)
Date: Sun, 18 Sep 2005 21:50:23 GMT Raw View
John Nagle wrote:
> Dave Harris wrote:
>> kanze@gabi-soft.fr (kanze) wrote (abridged):
>>> I don't think you really understood my objections to fixing
>>> it. I'm all in favor of a maximum of safety. But the
>>> difference here with Java is notable: in Java, you can only
>>> return a pointer or a built in type, so in every case, there
>>> is a trival default that you can use, even if you know that
>>> you will never get there. In C++, you can return complex
>>> value types, and there are cases where there is no
>>> reasonable default available, even if you know that it will
>>> never be used.
> There's always "throw". Which is the right answer in this case.
throw what? Or just throw -- it doesn't matter that we're not
in a catch block, since it will never be executed anyway.
Or what about a new keyword never_gets_here? Which causes the
program to abort if it is ever executed (but has the advantage
that the compiler knows that it will never be executed).
--=20
James Kanze mailto: james.kanze@free.fr
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 =
34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: usenet-nospam@nmhq.net (Niklas Matthies)
Date: Mon, 19 Sep 2005 05:51:49 GMT Raw View
On 2005-09-18 21:49, James Kanze wrote:
:
> On the other hand... if we're going to start down this road,
> let's do it right. Introduce some means of saying that a
> function never returns, for example -- maybe a return type of
> "void void". I think that with very, very few additions, we
> could reach a point where the compiler could decide, at least in
> almost all reasonable cases.
How about a library type "std::noreturn" (with a private constructor,
or invoke std::unexpected() upon instantiation)? This would avoid
introducing new syntax, and code using it would still compile under
legacy compilers.
-- Niklas Matthies
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Mon, 19 Sep 2005 05:52:20 GMT Raw View
James Kanze wrote:
> John Nagle wrote:
> > Dave Harris wrote:
>
> >> kanze@gabi-soft.fr (kanze) wrote (abridged):
>
> >>> I don't think you really understood my objections to fixing
> >>> it. I'm all in favor of a maximum of safety. But the
> >>> difference here with Java is notable: in Java, you can only
> >>> return a pointer or a built in type, so in every case, there
> >>> is a trival default that you can use, even if you know that
> >>> you will never get there. In C++, you can return complex
> >>> value types, and there are cases where there is no
> >>> reasonable default available, even if you know that it will
> >>> never be used.
>
> > There's always "throw". Which is the right answer in this case.
>
> throw what? Or just throw -- it doesn't matter that we're not
> in a catch block, since it will never be executed anyway.
"throw", with no value, is allowed by the C++ syntax.
It's a good choice to put at an "unreachable" point. The
compiler knows that control can't pass though a "throw",
which resolves any ambiguities about what should be done
at unreachable points. You can catch it with "catch ...",
but for most programs, it's an abort condition. And it's
well-defined.
From a standards perspective, I'd argue for the following:
If a value-returning function has no specified return value,
"return(0)" is assumed. This provides backwards compatibility
for legacy code.
If an implicit "return(0)" generates a value which is not
convertable to the declared return type, failure to explicitly
provide a "return" statement is an error.
A program that has a nontrivial return type but falls through
to a return point is more likely than not to be broken.
This is a clean, workable solution. It's unlikely to break
working code, although it may bring out some bugs in broken
programs.
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.jamesd.demon.co.uk/csc/faq.html ]
Author: "Anders Dalvander" <anders.dalvander@gmail.com>
Date: Mon, 19 Sep 2005 16:53:23 CST Raw View
John Nagle wrote:
> "throw", with no value, is allowed by the C++ syntax.
> It's a good choice to put at an "unreachable" point. The
> compiler knows that control can't pass though a "throw",
> which resolves any ambiguities about what should be done
> at unreachable points. You can catch it with "catch ...",
> but for most programs, it's an abort condition. And it's
> well-defined.
Cannot catch it though:
" 15.1.8 If no exception is presently being handled, executing a
throw-expression with no operand calls terminate() (15.5.1)."
Anders Dalvander
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: chris jefferson <caj@cs.york.ac.uk>
Date: 20 Sep 2005 02:30:01 GMT Raw View
James Kanze wrote:
> Francis Glassborow wrote:
>> In article
>> <1126787893.367671.41500@g14g2000cwa.googlegroups.com>,
>> ThosRTanner <ttanner2@bloomberg.net> writes
>
>>> The compiler can, however, check for violations of the
>>> language contract "you can't drop off the end of a function
>>> that returns a value", even on the basis of "if I can't tell
>>> you won't get here, I'll assume you will".
>
>> Which leads to the silly coding style of always ending a
>> function with a return statement to keep the compiler happy
>> even though you know that it will never be executed.
>
> It's not so much that it is silly, as that sometimes, it is
> downright difficult to find a value that you can return. I
> guess something like :
>
> return *(MyType*)0 ;
>
> would be acceptable regardless of the MyType (no default
> constructor, etc.), but somehow, I just don't like writing such
> things.
>
Personally, I would perfer abort(), or perhaps throw std::no_return. The
standard could even state that such a thing is implicitally attached to
the end of functions (although of course, in most cases, the compiler
would be able to deduce they were unreachable).
The problem with returning *(MyType*)0 is that I'd expect it might make
code crash in random unpredicatable ways.
Chris
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: JavaByExample_at_KickJava_com@yahoo.com
Date: Mon, 19 Sep 2005 21:28:49 CST Raw View
> I'm all for the compiler stopping dangerous code. It saves a lot of
> grief in the long run.
You are asking lots from compiler to identify all those ' dangerous
code', I am not even sure that it is possible?
David J
-----------------------------------------------------------------------------------------------------
http://KickJava.com - Java API By Example, From Geeks To Geeks.
http://KickJava.com/freeBooks.html - 100s of Free online Java Books.
http://KickJava.com/browse.html - Browse all J2SE, J2EE and J2ME APIs
and examples in one place.
http://kickjava.com/search.html - Searching 20,041,731 lines of Java
source codes.
http://KickJava.com/news - Daily Java news and articles.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: caj@cs.york.ac.uk (chris jefferson)
Date: Tue, 20 Sep 2005 02:28:27 GMT Raw View
James Kanze wrote:
> Francis Glassborow wrote:
>> In article
>> <1126787893.367671.41500@g14g2000cwa.googlegroups.com>,
>> ThosRTanner <ttanner2@bloomberg.net> writes
>
>>> The compiler can, however, check for violations of the
>>> language contract "you can't drop off the end of a function
>>> that returns a value", even on the basis of "if I can't tell
>>> you won't get here, I'll assume you will".
>
>> Which leads to the silly coding style of always ending a
>> function with a return statement to keep the compiler happy
>> even though you know that it will never be executed.
>
> It's not so much that it is silly, as that sometimes, it is
> downright difficult to find a value that you can return. I
> guess something like :
>
> return *(MyType*)0 ;
>
> would be acceptable regardless of the MyType (no default
> constructor, etc.), but somehow, I just don't like writing such
> things.
>
Personally, I would perfer abort(), or perhaps throw std::no_return. The
standard could even state that such a thing is implicitally attached to
the end of functions (although of course, in most cases, the compiler
would be able to deduce they were unreachable).
The problem with returning *(MyType*)0 is that I'd expect it might make
code crash in random unpredicatable ways.
Chris
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 20 Sep 2005 02:28:42 GMT Raw View
kanze@none.news.free.fr (James Kanze) wrote (abridged):
> > and this could be wrapped up in a suitably-named template or macro:
>
> > return unreachable_value<MyType>();
>
> > or whatever. I'd have thought this would only fail if the type
> > has no accessible copy-constructor, in which case we shouldn't
> > be returning it in the first place.
>
> Formally, the statement contains undefined behavior. But if
> we never execute it.
By "fail" I meant "fail to compile". The undefined behaviour is desirable
as it means the compiler doesn't have to generate code for this case. If
it does generate code, it's likely to be short.
I had considered "throw", and in fact more elaborate schemes:
template <typename T>
T unreachable_value() {
assert( false );
// __assume( false ); // where supported
throw;
return *reinterpret_cast<T*>(0);
}
but wanted to minimise the generated code.
> On the other hand... if we're going to start down this road,
> let's do it right.
The point of this is that it's a library solution that can be adopted now.
It doesn't require a language change.
> Introduce some means of saying that a function never returns,
> for example -- maybe a return type of "void void".
I don't think that's what we want here. Some functions do return, but not
by falling off the end.
int demo() {
while (true) {
if (!rand())
return 1;
}
return unreachable_value<int>();
}
This will eventually return an int, not a void void, but it is probably
beyond the compiler's ability to prove it.
If we do add a language concept of code that is never reached, then I
think we should do so in a general way, not just for function return.
I quite like __assume(false). See:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/ht
ml/vcref_assume.asp
-- Dave Harris, Nottingham, UK.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "msalters" <Michiel.Salters@logicacmg.com>
Date: 20 Sep 2005 14:00:47 GMT Raw View
rogero@howzatt.demon.co.uk schreef:
> Francis Glassborow wrote:
> > Which leads to the silly coding style of always ending a function with a
> > return statement to keep the compiler happy even though you know that it
> > will never be executed.
>
> Unfortunately we programmers have a poor record of success with
> statements like:
> "... know it will never be ..."
Dunno. I tend to write a lot of those statements. See assert( ).
I think that assert(false) ought to shut up even the most picky
compiler
in these cases. That makes it clear the code path is unreachable, even
though the compiler thinks otherwise.
HTH,
Michiel Salters
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: 20 Sep 2005 14:00:53 GMT Raw View
Dave Harris wrote:
[...]
> > Introduce some means of saying that a function never returns,
> > for example -- maybe a return type of "void void".
> I don't think that's what we want here. Some functions do
> return, but not by falling off the end.
> int demo() {
> while (true) {
> if (!rand())
> return 1;
> }
> return unreachable_value<int>();
> }
> This will eventually return an int, not a void void, but it is
> probably beyond the compiler's ability to prove it.
Just a nit, but what the compiler has to prove is that the code
will never return except by executing an appropriate return
statement. Which is trivial here.
Still, I imagine that there are other cases...
I'm not sure what the solution is. I think compilers could do a
lot more than they currently do; regard what Java requires with
regards to program flow analysis. I have no problem with
requiring as much from C++ compilers. The problem is what to do
in the cases where even this analysis comes up with a wrong
answer -- in Java (where it concerning the initialization of
variables and return statements), it is always simple for the
programmer to throw in an extra statement, return null, or
whatever, to shut up the compiler. In C++, it isn't always that
simple.
--
James Kanze GABI Software
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: 14 Sep 2005 05:10:10 GMT Raw View
kanze wrote:
> Ron Natalie wrote:
> > Francis Glassborow wrote:
>
> > > void * something(){
> > > for(int i(0); i<10; ++i) dosomething(i);
> > > }
>
> > > should also be accepted unless the compiler can prove that
> > > dosomething(int) cannot throw an exception.
>
> > What difference does dosomthing throwing an exception make?
> > Since nothing is catching the exception in something, then the
> > stack will be unwound out of something without flowing off the
> > end of the function.
>
> That's exactly Francis' point. If dosomething exits by means of
> an exception, the code is legal, has well defined behavior, and
> must be ascepted, even though the compiler detects flowing off
> the end.
But code like that is totally unmaintainable. A minor change to
"dosomething" could make the behaviour of the something() undefined.
I'm all for the compiler stopping dangerous code. It saves a lot of
grief in the long run.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: Wed, 14 Sep 2005 09:30:05 CST Raw View
ThosRTanner wrote:
> kanze wrote:
> > Ron Natalie wrote:
> > > Francis Glassborow wrote:
> > > > void * something(){
> > > > for(int i(0); i<10; ++i) dosomething(i);
> > > > }
> > > > should also be accepted unless the compiler can prove that
> > > > dosomething(int) cannot throw an exception.
> > > What difference does dosomthing throwing an exception
> > > make? Since nothing is catching the exception in
> > > something, then the stack will be unwound out of something
> > > without flowing off the end of the function.
> > That's exactly Francis' point. If dosomething exits by
> > means of an exception, the code is legal, has well defined
> > behavior, and must be ascepted, even though the compiler
> > detects flowing off the end.
> But code like that is totally unmaintainable.
Certainly. Any code with functions named something() and
dosomething() is unmaintainable. What if instead of
dosomething(), the function was called fatalError, and instead
of throwing an exception, it aborted? (OK, there probably
wouldn't be a loop in this case. But I don't think that Francis
meant his example as a literal example of what he would write.
I don't think he names functions something and dosomething in
real code.)
> A minor change to "dosomething" could make the behaviour of
> the something() undefined.
Presumably, dosomething has a contract. Any minor change which
violates the contract could make the behavior of any function
which calls it undefined.
Regretfully, I don't know of a way for the compiler to detect
violations of contract, and generate an error whenever they
occur.
--
James Kanze GABI Software
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: virtanea@mustatilhi.cs.tut.fi (Virtanen Antti)
Date: Wed, 14 Sep 2005 14:29:59 GMT Raw View
On 2005-09-14, ThosRTanner <ttanner2@bloomberg.net> wrote:
>> That's exactly Francis' point. If dosomething exits by means of
>> an exception, the code is legal, has well defined behavior, and
>> must be ascepted, even though the compiler detects flowing off
>> the end.
>
> But code like that is totally unmaintainable. A minor change to
> "dosomething" could make the behaviour of the something() undefined.
Indeed.
> I'm all for the compiler stopping dangerous code. It saves a lot of
> grief in the long run.
Me too. In my opinion there's a major philosophical difference between
C++ and, say, Java in this sense. (Don't start arguing which one is
better, that's not the point)
I have found out C++ programmers are very reluctant to introduce this
sort of constraints to the language. And certainly such restrictions
are useless to competent programmers, because a competent programmer
knows what kind of solutions are undesirable and unmaintainable, even
if the language permits them. For most people, however, it's better if
the compiler restricts their creativity and at least warns them when
they do something peculiar.
It was pointed out that if this particular feature is fixed, it will
break existing code, which means it shouldn't be fixed, even if
everyone here agrees it's really broken. If a lot of existing
production code really depends on undefined behaviour, I think it
proves the point why such code shouldn't be allowed in the first
place.
--
// Antti Virtanen
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: Thu, 15 Sep 2005 21:25:25 CST Raw View
kanze wrote:
> ThosRTanner wrote:
> > kanze wrote:
> > > Ron Natalie wrote:
> > > > Francis Glassborow wrote:
>
> > > > > void * something(){
> > > > > for(int i(0); i<10; ++i) dosomething(i);
> > > > > }
>
> > > > > should also be accepted unless the compiler can prove that
> > > > > dosomething(int) cannot throw an exception.
>
> > > > What difference does dosomthing throwing an exception
> > > > make? Since nothing is catching the exception in
> > > > something, then the stack will be unwound out of something
> > > > without flowing off the end of the function.
>
> > > That's exactly Francis' point. If dosomething exits by
> > > means of an exception, the code is legal, has well defined
> > > behavior, and must be ascepted, even though the compiler
> > > detects flowing off the end.
>
> > But code like that is totally unmaintainable.
>
> Certainly. Any code with functions named something() and
> dosomething() is unmaintainable. What if instead of
> dosomething(), the function was called fatalError, and instead
> of throwing an exception, it aborted? (OK, there probably
> wouldn't be a loop in this case. But I don't think that Francis
> meant his example as a literal example of what he would write.
> I don't think he names functions something and dosomething in
> real code.)
I wasn't complaining about the function names. Even if the function was
called fatalErrorIfCalledWithValue10 it wouldn't be maintainable,
because it is too easy to subtly violate parts of the contract that
cannot be expressed in the language.
> > A minor change to "dosomething" could make the behaviour of
> > the something() undefined.
>
> Presumably, dosomething has a contract. Any minor change which
> violates the contract could make the behavior of any function
> which calls it undefined.
>
> Regretfully, I don't know of a way for the compiler to detect
> violations of contract, and generate an error whenever they
> occur.
The compiler can, however, check for violations of the language
contract "you can't drop off the end of a function that returns a
value", even on the basis of "if I can't tell you won't get here, I'll
assume you will".
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 15 Sep 2005 21:23:40 CST Raw View
Virtanen Antti wrote:
> On 2005-09-14, ThosRTanner <ttanner2@bloomberg.net> wrote:
> >> That's exactly Francis' point. If dosomething exits by
> >> means of an exception, the code is legal, has well defined
> >> behavior, and must be ascepted, even though the compiler
> >> detects flowing off the end.
> > But code like that is totally unmaintainable. A minor change
> > to "dosomething" could make the behaviour of the something()
> > undefined.
> Indeed.
> > I'm all for the compiler stopping dangerous code. It saves a
> > lot of grief in the long run.
> Me too. In my opinion there's a major philosophical difference
> between C++ and, say, Java in this sense. (Don't start arguing
> which one is better, that's not the point)
I think the issues are more complicated. I don't particularly
care for Java because I find that it is more dangerous than C++.
The way I write C++. The difference in philosophy is that Java
decides exactly how safe it should be, where as C++ leaves it up
to the programmer (or the organisation); my problem with Java is
that the level of safety the language imposes is less than that
I normally require (and attain with C++).
> I have found out C++ programmers are very reluctant to
> introduce this sort of constraints to the language. And
> certainly such restrictions are useless to competent
> programmers, because a competent programmer knows what kind of
> solutions are undesirable and unmaintainable, even if the
> language permits them. For most people, however, it's better
> if the compiler restricts their creativity and at least warns
> them when they do something peculiar.
> It was pointed out that if this particular feature is fixed,
> it will break existing code, which means it shouldn't be
> fixed, even if everyone here agrees it's really broken. If a
> lot of existing production code really depends on undefined
> behaviour, I think it proves the point why such code shouldn't
> be allowed in the first place.
I don't think you really understood my objections to fixing it.
I'm all in favor of a maximum of safety. But the difference
here with Java is notable: in Java, you can only return a
pointer or a built in type, so in every case, there is a trival
default that you can use, even if you know that you will never
get there. In C++, you can return complex value types, and
there are cases where there is no reasonable default available,
even if you know that it will never be used. To introduce a
requirement here would either require the compiler to be able to
do all of the necessary analysis (which in turn means
cross-module flow analysis), or to ban returning values, at
least of user defined types. Not only would this break almost
all existing applications, it would introduce any number of
lifetime of object issues. IMHO, the ability to return values
is more important than catching the few errors which result from
this not being controlled.
--
James Kanze GABI Software
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sat, 17 Sep 2005 02:01:47 GMT Raw View
In article <1126787893.367671.41500@g14g2000cwa.googlegroups.com>,
ThosRTanner <ttanner2@bloomberg.net> writes
>The compiler can, however, check for violations of the language
>contract "you can't drop off the end of a function that returns a
>value", even on the basis of "if I can't tell you won't get here, I'll
>assume you will".
Which leads to the silly coding style of always ending a function with a
return statement to keep the compiler happy even though you know that it
will never be executed.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "Vladimir Marko" <swelef@post.sk>
Date: 8 Sep 2005 04:20:08 GMT Raw View
Ian wrote:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
>
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
int foo(){
bar();
}
Without analyzing the definition of bar the compiler can not prove that
the control flow shall reach the end of foo (bar may terminate the
program or throw an exception, the latter being a reasonable way of
error reporting). Even if the definition of bar would be visible the
proof may not exist -- it may for example depend on run-time parameters
controlled by a different program. That's why such code is well-formed.
Do you want to make reasonable code ill-formed?
And what about this:
int report_error(int x){
assert(::throwing);
report_error_core_(x); // throws if ::throwing, returns otherwise
}
Should it compile in debug mode and fail to compile in release mode?
(I know this is an artificial example but something similar may actualy
be used.)
Vladimir Marko
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "msalters" <Michiel.Salters@logicacmg.com>
Date: 8 Sep 2005 04:20:14 GMT Raw View
Ian schreef:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
>
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
How do you prove at compile time that a function flows off the end?
In general, that requires solving the halting problem, plus you can't
see into other functions.
char* foo( char* bar )
{
do {
if ( !*bar ) return bar;
} while( bar++ );
}
This is legal if bar is null-terminated. In fact, strlen is often
implemented similarly. However, the compiler can't determine at
compile time whether this will flow off the end.
HTH,
Michiel Salters
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: 8 Sep 2005 04:20:18 GMT Raw View
Addendum to my previous post: Yes, of course there are other ways of
confusing the compiler. But compilers are capable of a reasonable
amount of flow analysis (for optimising out dead code if nothing else),
and they can deduce one of the following:
1) The end of the function can never be reached - no problem
2) The end of the function will be reached - should be an error
3) The end of the function might be reached - should require a
diagnostic. I'd prefer an error, because if the compiler can't tell,
how can a maintainer?
I've seen a few of the last using lint and working out whether or not
the code will drop through or not because of variables that depend on
other variables causing a return before the end of the function is
quite hairy.
Another argument for SESE....
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: 8 Sep 2005 04:20:28 GMT Raw View
Ian wrote:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
>
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
Well, yes, although it's a little difficult for the compiler to tell
all the time. For instance
int wibble(int a, int b, int c)
{
while (some_condition_that_can_never_be_true_with_these_args(a, b,
c))
{
if (fed_up()) return 99;
}
//You know you can never get here, but the compiler doesn't
}
Under the circumstances I still think it should error, as either the
function always returns false (in which case, the function should be
void and you would code the loop differently), or the arguments might
possibly be different one day, and the function could unexpectedly
return true, and then where would you be?
I'm pretty sure other people will disagree with this though.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: 8 Sep 2005 04:20:31 GMT Raw View
Ian wrote:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
> "flowing off the end of a function is equivalent to a return
> with no value; this results in undefined behaviour in a
> value-returning function".
> Should this undefined behaviour be promoted to a compile time
> error?
How can a compiler detect the problem (with no false positives)?
--
James Kanze GABI Software
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@spamcop.net (Ron Natalie)
Date: Thu, 8 Sep 2005 04:22:00 GMT Raw View
Ian wrote:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
>
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
>
It's not a compile time error because it's not easy to tell if the
program will flow off the end in all circumstances. A compiler that
can tell is free to generate extra diagnostics (and many do).
For example:
int foo() {
while(some_condition()) {
if(some_other_condition())
return 1;
}
}
does some_other_condition return true before some_condition ever returns
false?
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@spamcop.net (Ron Natalie)
Date: Thu, 8 Sep 2005 04:21:42 GMT Raw View
Maciej Sobczak wrote:
>
> It should be probably clarified.
> Flowing off the end is equivalent to a return with no value *only* if
> the function is declared as returning void - and this part is missing in
> the standard. If the function returns something else, then return with
> no value would be illegal (earlier in 6.6.3/2 and I think diagnostic is
> required) and therefore it is not true that flowing off the end is
> equivalent to it.
>
Not true. The standard is quite specific:
"Flowing off the end of end of a function is equivelent to return with
no value; this results in undefined behavior in a value returning
function. (6.6.3).
No diagnostic is required for undefined behavior.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: no.spam@no.spam.com (Maciej Sobczak)
Date: Fri, 9 Sep 2005 03:12:06 GMT Raw View
Ron Natalie wrote:
>> It should be probably clarified.
>> Flowing off the end is equivalent to a return with no value *only* if
>> the function is declared as returning void - and this part is missing
>> in the standard. If the function returns something else, then return
>> with no value would be illegal (earlier in 6.6.3/2 and I think
>> diagnostic is required) and therefore it is not true that flowing off
>> the end is equivalent to it.
>>
> Not true. The standard is quite specific:
>
> "Flowing off the end of end of a function is equivelent to return with
> no value; this results in undefined behavior in a value returning
> function. (6.6.3).
>
> No diagnostic is required for undefined behavior.
What about diagnostic for return with no value from function returning
non-void?
// 1.
int fun()
{
return;
}
That's what I'm talking about. If the above is ill-formed (I think it is
and I think diagnostic is required), then the following:
// 2.
int fun()
{
}
cannot be equivalent to 1.
The fact that 2. has UB and that for this single reason no diagnostic is
required is true. The question is, what about 2. being equivalent to 1.?
This is the point which requires clarification.
My understanding is that flowing off-the end is equivalent to return
with no value *only* in void-returning functions, where it is
well-formed. In other cases (non-void returning functions) it is UB.
The distinction between these two situations is not clear from the
standard wording.
--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Fri, 9 Sep 2005 03:16:10 GMT Raw View
ThosRTanner wrote:
> Addendum to my previous post: Yes, of course there are other ways of
> confusing the compiler. But compilers are capable of a reasonable
> amount of flow analysis (for optimising out dead code if nothing else),
> and they can deduce one of the following:
>
> 1) The end of the function can never be reached - no problem
> 2) The end of the function will be reached - should be an error
> 3) The end of the function might be reached - should require a
> diagnostic. I'd prefer an error, because if the compiler can't tell,
> how can a maintainer?
In fact, gcc does just that. gcc will not complain if you write
void* somethread()
{ for (;;)
{ dosomething(); }
}
because it is able to determine that there is no way to return from
that function. But it will generate a warning if there is any
possible way to return.
The comments about the halting problem are generally wrong. I've
actually built a proof of correctness system (see POPL '83), and
loop termination usually isn't that hard to prove. If loop termination
is anywhere near undecidable, the program is too unreliable to use.
It's worth noting, incidentally, for people who think the
halting problem matters, that there is a completely decidable subtheory
that's quite useful in determining halting. As long as control
flow is determined only by integer addition, subtraction, multiplication
by constants (only), the relational and logical operators, subscripting,
structure access, conditionals, and the initial contents of
memory are known, the problem is formally decidable.
That covers most loop termination conditions.
If your loop termination condition goes beyond that (floating
point convergence, for example) you probably need a counter
to prevent infinite loops.
See Oppen and Nelson,
"http://portal.acm.org/citation.cfm?id=512775". Not only is the
problem formally decidable, but there are efficient ways to decide
it and even generate counterexamples. At least three working
proof systems have been built using that approach.
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.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: 9 Sep 2005 03:20:54 GMT Raw View
Michael Karcher wrote:
> Ian <ian-news@hotmail.com> wrote:
> > "flowing off the end of a function is equivalent to a return with no
> > value; this results in undefined behaviour in a value-returning function".
> >
> > Should this undefined behaviour be promoted to a compile time error?
>
> I also thought this way some time ago, especially in functions returning
> objects with a non-trivial destructor, but the problem is code like this:
>
> // returns the string value of a bool-with-error (-1: error flag) given
> // as argument.
> std::string foo(int a)
> {
> switch(a)
> {
> case 0:
> return "false";
> case 1:
> return "true";
> case -1:
> return "ERROR";
> }
> }
>
> This code does fail horribly if a is not in the correct range, because of
> the undefined behaviour you cited. But do you really want to make code
> like this, which does exist, illegal?
I'm not sure how Ian intended his proposal to be interpreted. He's
apparantly of the opinion that the only code that would be made illegal
by his proposal is code which is currently broken. The only way I can
see to interpret his suggestion that would be consistent with that
opinion, would be that it would be a compile-time error only if the
compiler can actually prove, at compile time, that the function will
run off the end. This requires that it be able to prove, at compile
time, that the program as a whole unavoidably calls the function in a
context that it can prove, at compile time, will result in control
flowing off the end of the function.
Of course, in general, determining whether or not control is guaranteed
to flow off the end of a function is equivalent to solving the Halting
Problem. We can't require an implementation to do a perfect job of
detecting such situations. If this is the interpretation Ian intended,
a diagnostic cannot be mandatory. In which case, there's no change
needed to the standard. If the diagnostic is only an option, and not
mandatory, then "undefined behavior" already covers that. One of the
permissible forms of undefined behavior, if it can be proven at compile
time that having undefined behavior is an unavoidable consequence of
running the program, is to refuse to compile the code, with a
diagnostic.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sat, 10 Sep 2005 04:34:22 GMT Raw View
In article <EP2Ue.2796$I7.377@newssvr25.news.prodigy.net>, John Nagle
<nagle@animats.com> writes
> In fact, gcc does just that. gcc will not complain if you write
>
> void* somethread()
> { for (;;)
> { dosomething(); }
> }
>
>because it is able to determine that there is no way to return from
>that function. But it will generate a warning if there is any
>possible way to return.
However:
void * something(){
for(int i(0); i<10; ++i) dosomething(i);
}
should also be accepted unless the compiler can prove that
dosomething(int) cannot throw an exception.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: Fri, 9 Sep 2005 23:35:12 CST Raw View
Maciej Sobczak wrote:
> Ron Natalie wrote:
.
> > "Flowing off the end of end of a function is equivelent to return with
> > no value; this results in undefined behavior in a value returning
> > function. (6.6.3).
> >
> > No diagnostic is required for undefined behavior.
>
> What about diagnostic for return with no value from function returning
> non-void?
6.8.6.4p1: constraint violation. A diagnostic therefore required
(5.1.1.3p1)
So you are correct; they are not equivalent, despite the fact that
standard specifies that they are.
As a practical matter, the statement that they're equivalent is the
error. A return statement with no value from a function returning
non-void can easily be diagnosed at compile time. Flow running off the
end of a function cannot in generally be diagnosed until run time,
though with sufficiently thorough flow analysis you can prove it at
compile time in some cases, but not all of them. Since it can be
arbitrarily expensive to identify this problem at compile time, a
diagnostic shouldn't be mandatory.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: Fri, 9 Sep 2005 23:32:49 CST Raw View
Ian wrote:
> Maciej Sobczak wrote:
> > In general, flowing off the end cannot be reliably detected
> > at compile time due to exceptions that can prevent the
> > control from flowing off the end:
> > int foo()
> > {
> > bar();
> > } // flowing off the end? no, if bar throws
> This is obviously making no attempt to return something. It
> should be possible to detect the absence of any return
> statement, or a void return in a value returning function.
But what if you know that bar throws, or doesn't return for some
other reason?
The case is not so implausible. Consider the following code:
class Base
{
public:
virtual bool isOkToFoo() const = 0 ;
int foo()
{
return isOkToFoo() ? doFoo() : -1 ;
}
private:
virtual int doFoo() = 0 ;
} ;
class Derived : public Base
{
public:
virtual bool isOkToFoo() const
{
return false ;
}
private:
virtual int doFoo()
{
fatalError( "Derived::doFoo called" ) ;
// outputs message to log and aborts.
}
} ;
> I think Sun CC has it right:
I don't think so. It refuses to compile the above snippet,
which is fully legal code. I have occasionally used the idiom.
In this particular case, it would be trivial to add a useless
"return 0" to the implementation of doFoo(). But suppose that
the return type were a user defined class, with no default
constructor.
I don't like the possibility of undefined code, but I don't see
a workable alternative in this case.
--
James Kanze GABI Software
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: 10 Sep 2005 04:40:11 GMT Raw View
John Nagle wrote:
.
> It's worth noting, incidentally, for people who think the
> halting problem matters, that there is a completely decidable subtheory
> that's quite useful in determining halting. As long as control
> flow is determined only by integer addition, subtraction, multiplication
> by constants (only), the relational and logical operators, subscripting,
> structure access, conditionals, and the initial contents of
> memory are known, the problem is formally decidable.
> That covers most loop termination conditions.
What is the key feature that's been left out that renders the research
that's been done of the halting problem inapplicable? I presume I could
find out by reading the paper you cite, but it's pretty densely
written, and it's simpler (for me, at least) to just ask you.
You didn't mention function calls to opaque functions. Is it capable of
handling that? As a programmer reading the documentation of a routine,
I can determine what it's behavior should be with certain inputs, in
ways that that the compiler can't do unless it has access to that
routine's source code (and possibly not even then). Even if that source
code is available, if it's in a different translation unit, I think
it's a bad idea to require that a compiler look at that code.
> See Oppen and Nelson,
> "http://portal.acm.org/citation.cfm?id=512775". Not only is the
> problem formally decidable, but there are efficient ways to decide
> it and even generate counterexamples. At least three working
> proof systems have been built using that approach.
Is it really a good idea to mandate that much sophistication in a C++
implmentation? It's already permitted, why make it mandatory? An
implementation is free right now to warn you if it can't prove that
flow won't run off the end, performing flow analysis at whatever level
of sophistication the implementation feels is appropriate. It's just a
QoI issue whether or not the checking is suphiciently sophisticated for
your needs.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: usenet-nospam@nmhq.net (Niklas Matthies)
Date: Sat, 10 Sep 2005 06:02:20 GMT Raw View
On 2005-09-10 05:32, kanze wrote:
> Ian wrote:
>> Maciej Sobczak wrote:
>
>> > In general, flowing off the end cannot be reliably detected
>> > at compile time due to exceptions that can prevent the
>> > control from flowing off the end:
>
>> > int foo()
>> > {
>> > bar();
>> > } // flowing off the end? no, if bar throws
:
> But what if you know that bar throws, or doesn't return for some
> other reason?
:
> In this particular case, it would be trivial to add a useless
> "return 0" to the implementation of doFoo(). But suppose that
> the return type were a user defined class, with no default
> constructor.
>
> I don't like the possibility of undefined code, but I don't see
> a workable alternative in this case.
UDT foo(T whatever)
{
bar();
return foo(whatever);
}
-- Niklas Matthies
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Sat, 10 Sep 2005 06:04:50 GMT Raw View
kanze wrote:
> Ian wrote:
>
>>Maciej Sobczak wrote:
>
>
>>>In general, flowing off the end cannot be reliably detected
>>>at compile time due to exceptions that can prevent the
>>>control from flowing off the end:
> But what if you know that bar throws, or doesn't return for some
> other reason?
Microsoft C++ uses the "noreturn" keyword to indicate
functions which cannot return. Perhaps that should be standardized.
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.jamesd.demon.co.uk/csc/faq.html ]
Author: John Nagle <nagle@animats.com>
Date: Sat, 10 Sep 2005 16:48:17 CST Raw View
kuyper@wizard.net wrote:
> John Nagle wrote:
> .
>
>> It's worth noting, incidentally, for people who think the
>>halting problem matters, that there is a completely decidable subtheory
>>that's quite useful in determining halting. As long as control
>>flow is determined only by integer addition, subtraction, multiplication
>>by constants (only), the relational and logical operators, subscripting,
>>structure access, conditionals, and the initial contents of
>>memory are known, the problem is formally decidable.
>>That covers most loop termination conditions.
>
>
> What is the key feature that's been left out that renders the research
> that's been done of the halting problem inapplicable? I presume I could
> find out by reading the paper you cite, but it's pretty densely
> written, and it's simpler (for me, at least) to just ask you.
The prospect of undecidability appears when you introduce
multiplication by non-constants. Note, though, that
subscript calculations usually involve only multiplication
by constants. My real point here is that if your subscript
computation is so complicated that it approaches undecidabilty,
run-time checks should be mandatory.
> You didn't mention function calls to opaque functions. Is it capable of
> handling that?
You usually have to annotate the program with entry and exit
conditions visible to the caller. This is what "design by contract"
is really about.
> Is it really a good idea to mandate that much sophistication in a C++
> implmentation? It's already permitted, why make it mandatory? An
> implementation is free right now to warn you if it can't prove that
> flow won't run off the end, performing flow analysis at whatever level
> of sophistication the implementation feels is appropriate. It's just a
> QoI issue whether or not the checking is suphiciently sophisticated for
> your needs.
Only because of bad history dating back to the K&R C era is it
allowed to return without a value from a valued C function. This should
never have made it into C++, since C++ can return complex
objects for which the compiler must generate code. In K&R C, you
could return an int, a float, or a pointer. So "return" didn't
really do much internally. Most functions returned "int", so
this wasn't a big deal. "return" really just left something
in a register for the caller to pick up.
The world has changed. Today, we think nothing of returning an
object which implicitly invokes a user-defined "operator="
or a copy constructor. Return value processing requires
considerable compiler processing. There are subtle optimizations
to avoid multiple copying of returned objects. Given this,
it's no longer appropriate to treat this as "undefined behavior".
A possible compromise is to treat "return" or fall-through
from a valued function as "return(0)". If "return(0)" is not
meaningful for the return type, consider this a compile-time
error. Thus, functions with this problem returning "int",
"float", or "enum" types, or pointers, will still compile,
while those returning references or objects will not.
This will allow very old legacy code to compile, while
catching errors in newer code. Any code that this breaks is
probably a bug waiting to happen.
It also cleanly settles the issue of "what happens when
you fall off the end of "main"", without having that be
a special case.
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.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@spamcop.net (Ron Natalie)
Date: Sat, 10 Sep 2005 21:48:33 GMT Raw View
Francis Glassborow wrote:
>
> void * something(){
> for(int i(0); i<10; ++i) dosomething(i);
> }
>
> should also be accepted unless the compiler can prove that
> dosomething(int) cannot throw an exception.
>
What difference does dosomthing throwing an exception make?
Since nothing is catching the exception in something, then
the stack will be unwound out of something without flowing
off the end of the function.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: 13 Sep 2005 04:20:01 GMT Raw View
kanze wrote:
> But what if you know that bar throws, or doesn't return for some
> other reason?
>
> The case is not so implausible. Consider the following code:
>
> class Base
> {
> public:
> virtual bool isOkToFoo() const = 0 ;
> int foo()
> {
> return isOkToFoo() ? doFoo() : -1 ;
> }
> private:
> virtual int doFoo() = 0 ;
> } ;
>
> class Derived : public Base
> {
> public:
> virtual bool isOkToFoo() const
> {
> return false ;
> }
> private:
> virtual int doFoo()
> {
> fatalError( "Derived::doFoo called" ) ;
> // outputs message to log and aborts.
> }
> } ;
>
That would require the compiler to know that fatalError can never
return, unfortunately not really possible without a language change.
And I have known software where even a function with a name like
fatalError has been changed to return under some situations "because
that error is called from so many places but we've worked out how to
deal with it know and we can deal with it inside fatalError and carry
on".
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: 13 Sep 2005 04:30:35 GMT Raw View
Ron Natalie wrote:
> Francis Glassborow wrote:
> > void * something(){
> > for(int i(0); i<10; ++i) dosomething(i);
> > }
> > should also be accepted unless the compiler can prove that
> > dosomething(int) cannot throw an exception.
> What difference does dosomthing throwing an exception make?
> Since nothing is catching the exception in something, then the
> stack will be unwound out of something without flowing off the
> end of the function.
That's exactly Francis' point. If dosomething exits by means of
an exception, the code is legal, has well defined behavior, and
must be ascepted, even though the compiler detects flowing off
the end.
--
James Kanze GABI Software
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: ian-news@hotmail.com (Ian)
Date: Wed, 7 Sep 2005 03:39:47 GMT Raw View
Section 6.6.3.2 was brought to my attention on a thread over on
comp.lang.c++.
"flowing off the end of a function is equivalent to a return with no
value; this results in undefined behaviour in a value-returning function".
Should this undefined behaviour be promoted to a compile time error?
Ian
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: v.Abazarov@comAcast.net ("Victor Bazarov")
Date: Wed, 7 Sep 2005 13:54:09 GMT Raw View
Ian wrote:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
>
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning
> function".
> Should this undefined behaviour be promoted to a compile time error?
Why should it? Compile time errors are only about ill-formed code.
What if that function is never called? What if the return value is
never used? It's like dereferencing a null pointer. What if it is
done in a part of code that never gets executed?
#include <stdio.h>
int foo() { printf("abc"); }
int bar() { int *p = 0; return *p; }
int main() {}
V
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Wed, 7 Sep 2005 13:54:13 GMT Raw View
Ian wrote:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
>
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
Of course it should be an error.
But it won't be changed. That would break existing code.
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.jamesd.demon.co.uk/csc/faq.html ]
Author: no.spam@no.spam.com (Maciej Sobczak)
Date: Wed, 7 Sep 2005 13:54:36 GMT Raw View
Ian wrote:
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
It should be probably clarified.
Flowing off the end is equivalent to a return with no value *only* if
the function is declared as returning void - and this part is missing in
the standard. If the function returns something else, then return with
no value would be illegal (earlier in 6.6.3/2 and I think diagnostic is
required) and therefore it is not true that flowing off the end is
equivalent to it.
In general, flowing off the end cannot be reliably detected at compile
time due to exceptions that can prevent the control from flowing off the
end:
int foo()
{
bar();
} // flowing off the end? no, if bar throws
--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: caj@cs.york.ac.uk (chris jefferson)
Date: Wed, 7 Sep 2005 13:55:08 GMT Raw View
Ian wrote:
> Section 6.6.3.2 was brought to my attention on a thread over on
> comp.lang.c++.
>
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
>
I'm sure I won't be the only person to reply to this. The problem is
that it is undecidable to decide if a function will reach the end or
not. At the moment different compilers do different amounts of deduction
to try to give helpful advice, but it's not possible in general. We
could impose some very simple deductions a compiler must make to check,
and if not there must be an obvious final return value. That would
however force people to bloat code which they don't have to. Consider
the following cases, what do you think behaviour should be? (I've seen
code like both of these in real code, although obviously these are
massively simplified
int foo()
{
while(1)
{
if(g()) return 1;
if(h()) return 2;
}
}
int foo(int i, int j)
{
if(i) return 0;
if(j) return 1;
}
int foo(int i)
{
if(i>0) return 0;
if((i-1)<0) return 1;
}
One thing I would like to see, and I'm suprised no compiler seems to
have, is a way of adding an "abort()" to the end of each function which
should return where the compiler can't deduce that the function always
returns correctly, as a way of catching some errors.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: Michael.Karcher@writeme.com (Michael Karcher)
Date: Thu, 8 Sep 2005 04:13:52 GMT Raw View
Ian <ian-news@hotmail.com> wrote:
> "flowing off the end of a function is equivalent to a return with no
> value; this results in undefined behaviour in a value-returning function".
>
> Should this undefined behaviour be promoted to a compile time error?
I also thought this way some time ago, especially in functions returning
objects with a non-trivial destructor, but the problem is code like this:
// returns the string value of a bool-with-error (-1: error flag) given
// as argument.
std::string foo(int a)
{
switch(a)
{
case 0:
return "false";
case 1:
return "true";
case -1:
return "ERROR";
}
}
This code does fail horribly if a is not in the correct range, because of
the undefined behaviour you cited. But do you really want to make code
like this, which does exist, illegal?
A good solution to this question is, of course, ensuring the precondition,
or make the code fail in a non-undefined-behaviour-way like replacing the
"case -1:" by "default:". But this still implies that the compiler does
flow-tracking and knows that you can not get past the switch statement. An
easier-to-track version would have the error case after the switch, so there
is no falling-off-the-edge.
So, I have a counter-proposal: Instead of making it illegal, compile the
code "as if" the procedure ended in
'assert((__func__ " should return a value ",0));'.
If the compiler supports flow-tracking and figures out that this line can
not be reached, you get current behaviour with zero overhead; if the line
cannot be reached, but the compiler does not deduce it, you get a little
overhead and hopefully a compiler warning, telling you about it. If the
line really can be reached you replace undefined behaviour by defined program
termination, which is a good thing, IMHO.
Michael Karcher
Michael Karcher
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: 8 Sep 2005 04:20:04 GMT Raw View
I think an addendum to my previous email didn't make it. If it appears
twice, I apologise.
There are obviously more subtle ways of confusing the compiler than
mentioned in my previous post. Any compiler with an optimiser should be
able to determine one of the following.
1) The function never drops off the end - not an error
2) The function always drops off the end - should generate an error
3) The function might drop off the end
The 3rd case is contentious. My experience with lint indicates that
"might drop off the end" is generally the result of program flow being
dependant on a a chain of variables being set as the result of
something like (and this is somewhat simplified):
bool first_time = true;
bool some_logical_value;
do {
do some processing
if (first_time) { some_logical_value = true };
do some more processing
if (some_good_reason) { return a_value };
} while (some_logical_value);
This sort of stuff can be a nightmare to maintain, and I've found it
better to try and get that sort of mutual dependancy out of the loop.
Really, if the compiler can't tell whether or not some point in the
code is reached, how is the maintainer going to?
That's why I'd prefer it to be an error, though I rather anticipate
other people will have different views to me.
(This could be put forward as another argument for SESE I suppose).
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]