Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

extending conditions with declarators?

8 views
Skip to first unread message

Malte Starostik

unread,
Sep 24, 2002, 12:37:47 AM9/24/02
to
Hi,

thinking about the second possible condition syntax as of 6.4:
condition:
type-specifier-seq declarator = assignment-expression

I wonder why such an initialized declarator cannot be part of an expression
used as condition.
Wouldn't it encourage closer scoping to allow the following as well?

typedef std::vector< int, int > some_vector;

void do_something( const some_vector& v )
{
if ( ( some_vector::const_iterator it = v.find( 42 ) ) != v.end() )
{
// act on it
}
// some other stuff, it is out of scope
}

where it would be in scope only until the end of the if's substatements?
Consequently, this could be valid as well:

class A { /* ... */ };

void do_stuff()
{
if ( ( A* a1 = get_some_a_or_null() ) && ( A* a2 =
get_another_a_or_null() ) )
{
// act on a1 and a2
}
// other stuff, a1 and a2 are out of scope
}

TIA for your replies,
-Malte

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Sungbom Kim

unread,
Sep 24, 2002, 11:31:29 AM9/24/02
to
Malte Starostik wrote:
>
> thinking about the second possible condition syntax as of 6.4:
> condition:
> type-specifier-seq declarator = assignment-expression
>
> I wonder why such an initialized declarator cannot be part of an expression
> used as condition.
> Wouldn't it encourage closer scoping to allow the following as well?

Agreed. There's no reason why 0 should be the only value with
which to compare some expression in conditions, as well illustrated
in the previous posting.

I also guess allowing initialised declarators as part of expressions
in conditions should lead to allowing them everywhere, as:

bool found =
(vector<int>::const_iterator it = v.find(42)) != v.end();

Caching some intermediate value in a series of operations
would be easier:

if ((double y = f(x)) >= minimum || y <= maximum) { /* ... */ }

I think this is a nice extension of the language, without
much trouble to the implementations or to existing codes.

One question is about the lifetime for the initialised declarators;
"to the end of the controlled block if used in a condition;
the same as those for temporaries otherwise" is a possible rule
I can think of. I'd be looking forward to further ideas.

--
Sungbom Kim <musi...@bawi.org>

Victor Bazarov

unread,
Sep 24, 2002, 1:21:24 PM9/24/02
to
"Sungbom Kim" <musi...@bawi.org> wrote...

> Malte Starostik wrote:
> >
> > thinking about the second possible condition syntax as of 6.4:
> > condition:
> > type-specifier-seq declarator = assignment-expression
> >
> > I wonder why such an initialized declarator cannot be part of an
expression
> > used as condition.
> > Wouldn't it encourage closer scoping to allow the following as well?
>
> Agreed. There's no reason why 0 should be the only value with
> which to compare some expression in conditions, as well illustrated
> in the previous posting.
>
> I also guess allowing initialised declarators as part of expressions
> in conditions should lead to allowing them everywhere, as:
>
> bool found =
> (vector<int>::const_iterator it = v.find(42)) != v.end();

(a) what would be the scope of 'it'?

(b) if it's limited to the statement above (declaration of 'found'),
why do you need it at all, when you can simply write
bool found = v.find(42) != v.end();
?

(c) if it is NOT limited, why not have it in a separate declaration,
as in
vector<int>::const_iterator it = v.find();
bool found = it != v.end();
, which is MUCH MORE readable?

> Caching some intermediate value in a series of operations
> would be easier:
>
> if ((double y = f(x)) >= minimum || y <= maximum) { /* ... */ }

Yes, but you have a sequence point at '||'. What if you don't:

if ((double y = f(x)) >= somefunc(y))

? Should it be disallowed? Or should the rules for the order
of execution be changed? It probably won't break any code
simply because nobody does it this way right now. And what
to do in this case:

if ((double y = f(x)) > (double x = g(y))) ...

which 'y' and 'x' are they? Is the second declaration (of 'x')
using the object 'y' from the first declaration? Or are they
both using external objects 'x' and 'y', respectively?

> I think this is a nice extension of the language, without
> much trouble to the implementations or to existing codes.

I agree that there isn't much trouble to the existing code,
but I do think that implementors will have hard time and
those who need to learn the language will have hard time...

>
> One question is about the lifetime for the initialised declarators;
> "to the end of the controlled block if used in a condition;
> the same as those for temporaries otherwise" is a possible rule
> I can think of. I'd be looking forward to further ideas.

There is a fine line between allowing declarations in 'condition'
and opening the can of worms if declarations returned a value.
What would happen if I wanted to declare two variables:

if ((double x = obj.x(), y = obj.y()) ???

Not allowed? Allowed but the value of the declaration is the
value of the last declared object? What about if they are not
of the same type:

if ((double x = 2, *px = &x) ...

I think we'd have opened a floodgate for new obfuscated C++
contests...

Victor
--
Please remove capital A's from my address when replying by mail

Allan W

unread,
Sep 25, 2002, 11:32:50 AM9/25/02
to
malte.s...@t-online.de ("Malte Starostik") wrote

> Wouldn't it encourage closer scoping to allow the following as well?
> void do_something( const some_vector& v )
> {
> if ( ( some_vector::const_iterator it = v.find( 42 ) ) != v.end() )
> {
> // act on it
> }
> // some other stuff, it is out of scope
> }

We can do this today:

if (sometype name=value) {
// ...
} else {
// ...
}

If I read 6.4/3 and 6.4/4 right, then in an if() statement sometype
must either be bool, or something that converts to bool. (It looks
to me like this applies to for() also, which is clearly silly, but
that's a topic for another day.) The examples all use int, which is
implicitly compared to zero.

I think that the only reason that they even allowed variable declaration
inside an if() condition, was to make selection statements compatible
with iteration statements (where they are more obviously useful).

I quite agree with you that it ought to be able to initialize a
variable and then compare it to something else, all within the
condition (and scope) of an if().
if ((string err=myMathObject.longcalc()) != "")
myGui.Complain(err);

However -- if I read your proposal right, you propose to extend
variable declaration to the expression syntax? That would let you
declare a variable inside any scope where you can use an expression.
That would make things like this possible:
if ( (int a=func1()) != (int b=func2()) ) {
myGui.Complain(a,"!=",b);

or even this strange way to declare four variables:
int a = (foo b = getfoo()).size +
(bar c = b.getbar()).factor / (baz d = b.getbaz()).length;
...which would be equivalent to
foo b = getfoo();
bar c = b.getbar();
baz d = b.getbaz();
int a = b.size + c.factor / d.length;

Not saying if I like this part or not. Surely it would allow people
to write bad, practically unreadable code -- but that's true of any
new tool. Would it actually encourage bad code?

Also, from anyone who knows compiler internals -- would this be
difficult to implement? I'm guessing not, but I don't know.

Victor Bazarov

unread,
Sep 25, 2002, 12:00:19 PM9/25/02
to
"Malte Starostik" <malte.s...@t-online.de> wrote...

> thinking about the second possible condition syntax as of 6.4:
> condition:
> type-specifier-seq declarator = assignment-expression
>
> I wonder why such an initialized declarator cannot be part of an
expression
> used as condition.
> Wouldn't it encourage closer scoping to allow the following as well?
>
> typedef std::vector< int, int > some_vector;
>
> void do_something( const some_vector& v )
> {
> if ( ( some_vector::const_iterator it = v.find( 42 ) ) != v.end() )
> {
> // act on it
> }
> // some other stuff, it is out of scope
> }
>
> where it would be in scope only until the end of the if's substatements?
> Consequently, this could be valid as well:
>
> class A { /* ... */ };
>
> void do_stuff()
> {
> if ( ( A* a1 = get_some_a_or_null() ) && ( A* a2 =
> get_another_a_or_null() ) )
> {
> // act on a1 and a2
> }
> // other stuff, a1 and a2 are out of scope
> }

So, are you suggesting adding declarations to expressions in
general or only to expressions used in 'if' and 'while'?

If in general, what would be the scope of 'a' in this case:

#include <iostream>
int main()
{
std::cout << (int a = 5) << std::endl;
return a; // well-formed? ill-formed?
}

Would the declaration be limited to the same statement where
it appears? How about this, then:

#include <iostream>
int foo(int a, int b)
{
std::cout << a << ' ' << b << std::endl;
}
int main()
{
foo((int a = 5), ++a); // should it first declare and
// then initialise and increment
// or should it be rejected because
// the order is unspecified?
return 0;
}

Whould what you're suggesting really be an improvement, considering
that you already can do

if (A* a1 = get_some_a_or_null())
if (A* a2 = get_another_a_or_null())


{
// act on a1 and a2
}

?

Victor
--
Please remove capital A's from my address when replying by mail

Hyman Rosen

unread,
Sep 25, 2002, 12:56:42 PM9/25/02
to
Allan W wrote:
> I think that the only reason that they even allowed variable declaration
> inside an if() condition, was to make selection statements compatible
> with iteration statements

It's useful for RTTI probing -

if (Derived *der_p = dynamic_cast<Derived *>(base_p))
{
// use der_p here

James Russell Kuyper Jr.

unread,
Sep 25, 2002, 7:35:22 PM9/25/02
to
Allan W wrote:
....

> if (sometype name=value) {
> // ...
> } else {
> // ...
> }
>
> If I read 6.4/3 and 6.4/4 right, then in an if() statement sometype
> must either be bool, or something that converts to bool. (It looks
> to me like this applies to for() also, which is clearly silly, but

6.4p4 applies only to conditions. The first part of a for() statement is
parsed as a _for-init-statement_, not as "a _condition_ that is an
initialized declaration". The condition in a for() statement is the
second part, and as such it's entirely reasonable to require it to be
bool or implicitly convertible to bool. The value, (converted to bool,
if necessary) determines whether the for() loop keeps looping.

James Kanze

unread,
Sep 26, 2002, 1:22:22 PM9/26/02
to
all...@my-dejanews.com (Allan W) wrote in message
news:<7f2735a5.02092...@posting.google.com>...

> malte.s...@t-online.de ("Malte Starostik") wrote
> > Wouldn't it encourage closer scoping to allow the following as well?
> > void do_something( const some_vector& v )
> > {
> > if ( ( some_vector::const_iterator it = v.find( 42 ) ) != v.end() )
> > {
> > // act on it
> > }
> > // some other stuff, it is out of scope
> > }

> We can do this today:

> if (sometype name=value) {
> // ...
> } else {
> // ...
> }

> If I read 6.4/3 and 6.4/4 right, then in an if() statement sometype
> must either be bool, or something that converts to bool. (It looks to
> me like this applies to for() also, which is clearly silly, but that's
> a topic for another day.) The examples all use int, which is
> implicitly compared to zero.

> I think that the only reason that they even allowed variable
> declaration inside an if() condition, was to make selection statements
> compatible with iteration statements (where they are more obviously
> useful).

>From what I remember, the main reason for allowing the variable
declaration was for use in an if, particularly:

if ( Derived* pd = dynamic_cast< Derived* >( aBase ) ) {
}

The idea behind this is that any access through pd is impossible unless
aBase really is a Derived -- the pointer just isn't in scope anywhere
else.

And of course, the original poster is right. The logic also applies to
something like:

if ( std::map< X, Y >::const_iterator = aMap.find( aKey ) ) {
}

except that the condition should be != aMap.end(), and not an implicit
conversion to bool. (Sounds like another argument for a single iterator
model:-).) In this case, of course, one could always wrap things in a
MappedObject wrapper:

if ( MappedObject m( aMap, aKey ) ) {
// Use *m...
}

for example, with:

template< typename Map >
class MappedObject
{
public:
MappedObject( Map& map, Map::key_type const& key )
: myEntry( NULL )
{
Map::iterator it = map.find( key ) ;
if ( it != map.end() ) {
myEntry = &it->second ;
}
}
operator Map::mapped_type*()
{
return myEntry ;
}
private:
Map::mapped_type* myEntry ;
} ;

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

Francis Glassborow

unread,
Sep 26, 2002, 1:40:01 PM9/26/02
to
In article <3D92459F...@wizard.net>, James Russell Kuyper Jr.
<kuy...@wizard.net> writes

>Allan W wrote:
>....
>> if (sometype name=value) {
>> // ...
>> } else {
>> // ...
>> }
>>
>> If I read 6.4/3 and 6.4/4 right, then in an if() statement sometype
>> must either be bool, or something that converts to bool. (It looks
>> to me like this applies to for() also, which is clearly silly, but
>
>6.4p4 applies only to conditions. The first part of a for() statement is
>parsed as a _for-init-statement_, not as "a _condition_ that is an
>initialized declaration". The condition in a for() statement is the
>second part, and as such it's entirely reasonable to require it to be
>bool or implicitly convertible to bool. The value, (converted to bool,
>if necessary) determines whether the for() loop keeps looping.

And note that declarations in condition's are redeclared each time the
flow of control passes through them. The flow of control only passes
through a for-init-statement once before the first pass through the
controlled statement. The condition statement is executed before each
pass through the controlled statement.

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Shao Wu

unread,
Sep 27, 2002, 7:51:31 AM9/27/02
to
Victor Bazarov wrote:

>
> > Caching some intermediate value in a series of operations
> > would be easier:
> >
> > if ((double y = f(x)) >= minimum || y <= maximum) { /* ... */ }
>
> Yes, but you have a sequence point at '||'. What if you don't:
>
> if ((double y = f(x)) >= somefunc(y))
>

Since C++ does not define which function to be evaluated
first, hence the result is "undefine" -- the compiler could
issue an error for undeclared "y" for somefunc(y), or take
y from outter scope, or take the result of f(x), or format the
hard disk, for blue screen, or send email to your boss for
bad coding ....

>
> ? Should it be disallowed? Or should the rules for the order
> of execution be changed? It probably won't break any code
> simply because nobody does it this way right now. And what
> to do in this case:
>
> if ((double y = f(x)) > (double x = g(y))) ...
>
> which 'y' and 'x' are they? Is the second declaration (of 'x')
> using the object 'y' from the first declaration? Or are they
> both using external objects 'x' and 'y', respectively?
>

Can the standard says something like "undefined behavior" for
both cases?

>
>
> There is a fine line between allowing declarations in 'condition'
> and opening the can of worms if declarations returned a value.
> What would happen if I wanted to declare two variables:
>
> if ((double x = obj.x(), y = obj.y()) ???

Not allowed, or follow the usual left-to-right evaluation
order for "," operator.

As of today, you can do
if (int x = y) {
...
}
But
if (int x = y, a = y)
is NOT ALLOWED.

With this new extention, you can do:
if ((int x = f(y)) > 0)


>
>
> Not allowed? Allowed but the value of the declaration is the
> value of the last declared object? What about if they are not
> of the same type:
>
> if ((double x = 2, *px = &x) ...
>
> I think we'd have opened a floodgate for new obfuscated C++
> contests...

May be we can follow the existing rule that "," operator
is not allowed in this cases.

On the other hand, please try this little code with your
belove standard compliant compiler:

// WARNING: take your medication if you a heart
// condition before compiling!

int
main(void)
{
int a=5, b=6;

while (a < b, false) { // <<<-- What does your compiler say? Nothing?
a++, b--;
}
return 0;
}

Welcome to C++ ! ;-)

Regards,
Shao

Shao Wu

unread,
Sep 27, 2002, 7:52:23 AM9/27/02
to
Victor Bazarov wrote:

>
>
> Whould what you're suggesting really be an improvement, considering
> that you already can do
>
> if (A* a1 = get_some_a_or_null())
> if (A* a2 = get_another_a_or_null())
> {
> // act on a1 and a2
> }
>
> ?

If I am not mistaken, this already allowed in C++.

Shao

James Russell Kuyper Jr.

unread,
Sep 27, 2002, 11:32:20 AM9/27/02
to
Shao Wu wrote:
>
> Victor Bazarov wrote:
>
> >
> >
> > Whould what you're suggesting really be an improvement, considering
> > that you already can do
^^^^^^^^^^^^^^^^^^

> >
> > if (A* a1 = get_some_a_or_null())
> > if (A* a2 = get_another_a_or_null())
> > {
> > // act on a1 and a2
> > }
> >
> > ?
>
> If I am not mistaken, this already allowed in C++.

Correct. As he said.

Shao Wu

unread,
Sep 27, 2002, 12:35:54 PM9/27/02
to
Allan W wrote:

I think these should be allowed and are handy and useful.

>
> or even this strange way to declare four variables:
> int a = (foo b = getfoo()).size +
> (bar c = b.getbar()).factor / (baz d = b.getbaz()).length;
> ...which would be equivalent to
> foo b = getfoo();
> bar c = b.getbar();
> baz d = b.getbaz();
> int a = b.size + c.factor / d.length;
>
> Not saying if I like this part or not. Surely it would allow people
> to write bad, practically unreadable code -- but that's true of any
> new tool. Would it actually encourage bad code?

LISP? ;-(

Actually the above expression could not be valid and should
be "undefined" because the subexpression


(bar c = b.getbar()).factor / (baz d = b.getbaz()).length

could be evaluated before
(foo b = getfoo()).size

Regards,
Shao

Malte Starostik

unread,
Sep 27, 2002, 12:36:27 PM9/27/02
to
In article <up0q6eb...@corp.supernews.com>, vAba...@dAnai.com
says...

> "Malte Starostik" <malte.s...@t-online.de> wrote...
> > thinking about the second possible condition syntax as of 6.4:
> > condition:
> > type-specifier-seq declarator = assignment-expression
> >
> > I wonder why such an initialized declarator cannot be part of an
> expression
> > used as condition.
[snip]

> > class A { /* ... */ };
> >
> > void do_stuff()
> > {
> > if ( ( A* a1 = get_some_a_or_null() ) && ( A* a2 =
> > get_another_a_or_null() ) )
> > {
> > // act on a1 and a2
> > }
> > // other stuff, a1 and a2 are out of scope
> > }
>
> So, are you suggesting adding declarations to expressions in
> general or only to expressions used in 'if' and 'while'?
Only the latter. IMHO allowing them in any expression would indeed
encourage too many obfuscated constructs, YMMV.

[snip examples of scoping problems that may arise otherwise]
> Whould what you're suggesting really be an improvement, considering
> that you already can do
>
> if (A* a1 = get_some_a_or_null())
> if (A* a2 = get_another_a_or_null())
> {
> // act on a1 and a2
> }
>
> ?
Agreed. But what if the condition is a different one than the declared
variable converted to bool?

// open() returns a file descriptor on success or -1 on error
// Assume that for some reason it's not possible to use an fstream here
// e.g. because we need the fd to pass it to other system calls or
// 3rd party libraries.
if ( ( int fd = open( filename, O_RDONLY ) ) >= 0 )
{
// use fd
}

Regards,
-Malte

Victor Bazarov

unread,
Sep 28, 2002, 12:36:14 AM9/28/02
to
"Shao Wu" <sw...@earthlink.net> wrote...

> Victor Bazarov wrote:
>
> >
> >
> > Whould what you're suggesting really be an improvement, considering
> > that you already can do
> >
> > if (A* a1 = get_some_a_or_null())
> > if (A* a2 = get_another_a_or_null())
> > {
> > // act on a1 and a2
> > }
> >
> > ?
>
> If I am not mistaken, this already allowed in C++.


You're not mistaken. Please re-read my posting (to which replied).
BTW, you snipped too much of it when you quoted.

Victor
--
Please remove capital A's from my address when replying by mail

Victor Bazarov

unread,
Sep 28, 2002, 12:36:19 AM9/28/02
to
"Shao Wu" <sw...@earthlink.net> wrote...

> Victor Bazarov wrote:
>
> >
> > > Caching some intermediate value in a series of operations
> > > would be easier:
> > >
> > > if ((double y = f(x)) >= minimum || y <= maximum) { /* ... */ }
> >
> > Yes, but you have a sequence point at '||'. What if you don't:
> >
> > if ((double y = f(x)) >= somefunc(y))
> >
>
> Since C++ does not define which function to be evaluated
> first, hence the result is "undefine" -- the compiler could
> issue an error for undeclared "y" for somefunc(y), or take
> y from outter scope, or take the result of f(x), or format the
> hard disk, for blue screen, or send email to your boss for
> bad coding ....

You're confusing undefined behaviour and ill-formed code. If 'y'
has to be defined before 'somefunc' is called, then with unknown
order of evaluation of the operands of '>=', we get the compile
error (similar to declaring a variable in a 'case' clause of some
'switch' statement without a block) -- declaration of 'y' does not
happen before its use.

The compiler is not allowed to choose in such situation. Even if
there is a 'y' in the outer scope, my intentions must be unclear
to the compiler: did I want to use 'y' declared on the left-hand
side of '>=' or did I want to use the one from the outer scope?

That's ambiguity and not undefined behaviour.

>
> >
> > ? Should it be disallowed? Or should the rules for the order
> > of execution be changed? It probably won't break any code
> > simply because nobody does it this way right now. And what
> > to do in this case:
> >
> > if ((double y = f(x)) > (double x = g(y))) ...
> >
> > which 'y' and 'x' are they? Is the second declaration (of 'x')
> > using the object 'y' from the first declaration? Or are they
> > both using external objects 'x' and 'y', respectively?
> >
>
> Can the standard says something like "undefined behavior" for
> both cases?

No, it cannot. Undefined behaviour is a run-time thing, not
a compile-time thing. Please read the definition of it in your
copy of the Standard.

> > There is a fine line between allowing declarations in 'condition'
> > and opening the can of worms if declarations returned a value.
> > What would happen if I wanted to declare two variables:
> >
> > if ((double x = obj.x(), y = obj.y()) ???
>
> Not allowed, or follow the usual left-to-right evaluation
> order for "," operator.

There is no "," operator here. It's a list of declarations.

>
> As of today, you can do
> if (int x = y) {
> ...
> }
> But
> if (int x = y, a = y)
> is NOT ALLOWED.

No shouting necessary.

>
> With this new extention, you can do:
> if ((int x = f(y)) > 0)
>
>
> >
> >
> > Not allowed? Allowed but the value of the declaration is the
> > value of the last declared object? What about if they are not
> > of the same type:
> >
> > if ((double x = 2, *px = &x) ...
> >
> > I think we'd have opened a floodgate for new obfuscated C++
> > contests...
>
> May be we can follow the existing rule that "," operator
> is not allowed in this cases.

It's not the comma operator. It's a syntactic separator of
declarators. Just like the one in a list of function parameters:
it too is _not_ a comma operator.

>
> On the other hand, please try this little code with your
> belove standard compliant compiler:

There is no such thing.

>
> // WARNING: take your medication if you a heart
> // condition before compiling!
>
> int
> main(void)
> {
> int a=5, b=6;
>
> while (a < b, false) { // <<<-- What does your compiler say? Nothing?

> [...]

Nothing. The contents of the parentheses here is an _expression_
and not a declaration. Now, if it would start with a type-id,
it would be a declaration and the comma would not be the operator,
but a separator of declarations, maybe.

Of course this whole thing brings up another good topic: if we
try allowing declarations in an expression, what would we do
with commas?

double b = 1;
if (int a = 5, b) /////// line 2634
{
// something
}

Would the contents of the parentheses of the 'if' statement on
line 2634 mean that 'b' is a new uninitialised variable declared
in the same declaration statement as 'a', or would it mean that
'a' is declared and after the comma operator 'b' is _evaluated_
and the result of the expression is 'double(1)'?

Allowing declaraions in expressions is more difficult than some
might thing...

>
> Welcome to C++ ! ;-)

A bit belated, don't you think? I've been in C++ for about ten
years now.

Victor
--
Please remove capital A's from my address when replying by mail

James Kuyper Jr.

unread,
Sep 28, 2002, 8:04:08 AM9/28/02
to
Victor Bazarov wrote:
....

> No, it cannot. Undefined behaviour is a run-time thing, not
> a compile-time thing. Please read the definition of it in your
> copy of the Standard.

The standard uses the terms "translation" and "execution", rather than
"compile-time" and "run-time". An interpreted implementation of C might
perform translation at run-time. And a really intelligent optimizing
compiler could, at compile-time, pre-execute any code that doesn't
depend upon the runtime context. But those terms are the ones used by
the standard that come closest to matching your distinction.

The definition of "undefined behavior" in 1.3.12 simply says that it is
"behavior ... for which this International Standard imposes no
requirements". None. Not any. Not even the requirement that it occur
during execution rather than translation. A conforming implementation
could even use time travel to make the undefined behavior occur before
the code had even been written. :-) There is a Note in that same section
that makes this clear. It say that "permissible undefined behavior
ranges from ... behaving during translation .. in a documented manner
.... to terminating a translation ...".

Shao Wu

unread,
Sep 28, 2002, 8:02:21 AM9/28/02
to
"James Russell Kuyper Jr." wrote:

> Shao Wu wrote:
> >
> > Victor Bazarov wrote:
> >
> > >
> > >
> > > Whould what you're suggesting really be an improvement, considering
> > > that you already can do
> ^^^^^^^^^^^^^^^^^^
> > >
> > > if (A* a1 = get_some_a_or_null())
> > > if (A* a2 = get_another_a_or_null())
> > > {
> > > // act on a1 and a2
> > > }
> > >
> > > ?
> >
> > If I am not mistaken, this already allowed in C++.
>
> Correct. As he said.
>

Sorry. Must be faulty memory failing in the middle of
the night. ;-)
> Subject: Re: extending conditions with declarators?
> Date: Fri, 27 Sep 2002 11:52:23 +0000 (UTC)
>

Shao

Andy Sawyer

unread,
Sep 28, 2002, 5:47:35 PM9/28/02
to
sw...@earthlink.net (Shao Wu) writes:

> On the other hand, please try this little code with your
> belove standard compliant compiler:
>
> // WARNING: take your medication if you a heart
> // condition before compiling!
>
> int
> main(void)
> {
> int a=5, b=6;
>
> while (a < b, false) { // <<<-- What does your compiler say? Nothing?

Actually, my compiler says:

,----
| "Shao.cpp", line 7: warning: expression has no effect


| while (a < b, false) { // <<<-- What does your compiler say? Nothing?

| ^
`----

What do you expect it to say?


Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man

Allan W

unread,
Sep 30, 2002, 9:32:40 PM9/30/02
to
JRKu...@netscape.net ("James Kuyper Jr.") wrote

> The definition of "undefined behavior" in 1.3.12 simply says that it is
> "behavior ... for which this International Standard imposes no
> requirements". None. Not any. Not even the requirement that it occur
> during execution rather than translation. A conforming implementation
> could even use time travel to make the undefined behavior occur before
> the code had even been written. :-) There is a Note in that same section
> that makes this clear. It say that "permissible undefined behavior
> ranges from ... behaving during translation .. in a documented manner
> .... to terminating a translation ...".

The note doesn't mention time travel.

Assuming you're right, that the standard allows time travel... how would
you go about implementing such a compiler?

Also, how far does this go? Can the compiler, having gone back in time,
refuse to compile completely-valid programs based only on the fact that
two years later you're going to invoke undefined behavior on a completely
different program?

Here's the same question without reference to time travel. If the
program invokes undefined behavior, could a conforming compiler
(with unusually bad QoI) erase part of the standard library, so
that future compiles would fail?

Andy Sawyer

unread,
Oct 1, 2002, 1:15:23 PM10/1/02
to
all...@my-dejanews.com (Allan W) writes:

> JRKu...@netscape.net ("James Kuyper Jr.") wrote
> > The definition of "undefined behavior" in 1.3.12 simply says that it is
> > "behavior ... for which this International Standard imposes no
> > requirements". None. Not any. Not even the requirement that it occur
> > during execution rather than translation. A conforming implementation
> > could even use time travel to make the undefined behavior occur before
> > the code had even been written. :-) There is a Note in that same section
> > that makes this clear. It say that "permissible undefined behavior
> > ranges from ... behaving during translation .. in a documented manner
> > .... to terminating a translation ...".
>
> The note doesn't mention time travel.

The note, being a note, is non-normative. The first (normative)
sentence is the important one, and clearly states:

,----
| "behavior, such as might arise upon use of an erroneous program
| construct or erroneous data, _for which this International Standard
| imposes no requirements_."
`----
(my emphasis).

"Imposes no requirements" means that time travel is permitted (as is
global thermonuclear war, finding a cure for cancer or explaining why
Keanu Reeves is a movie star).

> Assuming you're right, that the standard allows time travel... how would
> you go about implementing such a compiler?

That's a quality of implementation issue for the compiler vendors to
solve.

> Also, how far does this go? Can the compiler, having gone back in time,
> refuse to compile completely-valid programs based only on the fact that
> two years later you're going to invoke undefined behavior on a completely
> different program?

I'd say probably not - but it could travel back in time to the point
before you compiled your valid program, change it to an invalid one,
and then refuse to compile the changed version.

> Here's the same question without reference to time travel. If the
> program invokes undefined behavior, could a conforming compiler
> (with unusually bad QoI) erase part of the standard library, so
> that future compiles would fail?

Yes, that's absolutelty possible (if somewhat unlikly). "undefined
behaviour" could (for example) include destruction of the media on
which the compiler and library is stored. I doubt the vendor would
stay in business for long though. On the other hand, a vendor that can
producee a compiler whose undefined behaviour delivers a cure for
cancer is probably on to a good thing.

Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man

---

James Russell Kuyper Jr.

unread,
Oct 1, 2002, 1:23:15 PM10/1/02
to
Allan W wrote:
> JRKu...@netscape.net ("James Kuyper Jr.") wrote
>
>>The definition of "undefined behavior" in 1.3.12 simply says that it is
>>"behavior ... for which this International Standard imposes no
>>requirements". None. Not any. Not even the requirement that it occur
>>during execution rather than translation. A conforming implementation
>>could even use time travel to make the undefined behavior occur before
>>the code had even been written. :-) There is a Note in that same section
>>that makes this clear. It say that "permissible undefined behavior
>>ranges from ... behaving during translation .. in a documented manner
>>.... to terminating a translation ...".
>
>
> The note doesn't mention time travel.

True. The note is non-normative, it's just helpful additional text to
emphasize how wide the range of possibilities are. It is NOT meant to be
an exhaustive list of the possibilities. The normative text covers it
all: "imposes no requirements". That's as clear a mention of time travel
as is needed in this context.

> Assuming you're right, that the standard allows time travel... how would
> you go about implementing such a compiler?

I only said that such an implementation would be conforming, not that it
would be feasible. :-)

However, time travel is an active and serious subject of study by
physicists. It's been conjectured that spacetimes which contain closed
time-like loops are subject to an ultraviolet catastrophe that prevent
them from ever being formed. It's also been conjectured that closed
time-like loops can only be found in the vicinity of structures which
are as big, in at least one dimension, as the entire universe. That
would make it rather hard to construct a time machine. :-) However,
neither conjecture has not yet been proven, and there's no other known
barriers to time travel in the context of modern physics (yes, I can
explain precisely what all that jargon means - but we're already a
little too far off-topic).

> Also, how far does this go? Can the compiler, having gone back in time,
> refuse to compile completely-valid programs based only on the fact that
> two years later you're going to invoke undefined behavior on a completely
> different program?

No. Because the standard does impose requirements on those valid
programs. Of course, the undefined behavior allowed by the standard
could include traveling back in time to change those programs so they
are no longer valid, or to change that compiler so it's no longer
conforming.
:-)

> Here's the same question without reference to time travel. If the
> program invokes undefined behavior, could a conforming compiler
> (with unusually bad QoI) erase part of the standard library, so
> that future compiles would fail?

I certainly hope so, because that's precisely what can happen (though
it's extremely unlikely) on some systems for certain kinds of undefined
behavior. The concept of "undefined behavior" was invented precisely to
allow such implementations despite the fact that they don't contain the
protections that would be required to absolutely prevent such a
consequence. That's because, on some systems, the required protections
would carry extraordinary performance costs (such as performing a
validity check on every pointer before making any use of it).

You say that all write permissions have been removed from both from the
library files and from the directory containing those files, and that
they all belong to 'root'? Well, the undefined behavior could take the
form of passing to the operating system information that convinces it
that 'root' has logged in with the correct password, and is changing
those file and directory permissions. I don't know how to do this; one
of those idiot who've forced up to put up firewalls all over the place
would have a better idea how it could happen. However, there's no
perfectly secure systems anywhere, and the worst-case consequences of,
for instance, writing beyond the end of an array can be almost
arbitrarily bad.

James Kanze

unread,
Oct 2, 2002, 7:51:09 AM10/2/02
to
an...@evo6.com (Andy Sawyer) wrote in message
news:<bs6ewe...@ender.evo6.com>...

> > Here's the same question without reference to time travel. If the
> > program invokes undefined behavior, could a conforming compiler
> > (with unusually bad QoI) erase part of the standard library, so that
> > future compiles would fail?

> Yes, that's absolutelty possible (if somewhat unlikly). "undefined
> behaviour" could (for example) include destruction of the media on
> which the compiler and library is stored. I doubt the vendor would
> stay in business for long though.

I wouldn't bet on it. I've actually used a compiler where this was
possible. Writing through an uninitialized pointer could cause the next
disk read to in fact reformat the hard disk. The odds were very much
against it, of course -- the uninitialized pointer had to contain just
the right (or wrong, depending on your point of view) address, and you
had to write just the write data, but it was possible.

The vendor, a company called Microsoft, is still around, and from what I
hear, not doing too badly. (Seriously, of course, if there is no
hardware protection, there is no hardware protection, writing through an
uninitialized pointer can modify the OS in any arbitrary way, and
there's not really much Microsoft, or any other vendor, can do about
it.)

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

---

Andy Sawyer

unread,
Oct 2, 2002, 8:21:41 AM10/2/02
to
ka...@gabi-soft.de (James Kanze) writes:

> an...@evo6.com (Andy Sawyer) wrote in message
> news:<bs6ewe...@ender.evo6.com>...
> > > Here's the same question without reference to time travel. If the
> > > program invokes undefined behavior, could a conforming compiler
> > > (with unusually bad QoI) erase part of the standard library, so that
> > > future compiles would fail?
>
> > Yes, that's absolutelty possible (if somewhat unlikly). "undefined
> > behaviour" could (for example) include destruction of the media on
> > which the compiler and library is stored. I doubt the vendor would
> > stay in business for long though.
>
> I wouldn't bet on it. I've actually used a compiler where this was
> possible.

I was thinking more in terms of physical destruction of the media,
rather than the loss of the data it contains, and also more in terms
of deliberate behaviour of the compiler/generated code rather than
accidental disaster - but you're entirely right. I had a similar
experience once - a colleague had modified a program which was part of
a suite our team was working on. During testing, this program modified
something somewhere in memory, which had the result that the next time
I created a directory (after the termination of the program in
question), the directory became both its own child and its own
parent. This had the rather interesting side-effect that whilst you
could chdir _into_ it, you couldn't change directory _out_ of it.

Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man

---

James Kanze

unread,
Oct 7, 2002, 5:47:28 PM10/7/02
to
an...@evo6.com (Andy Sawyer) wrote in message
news:<ptutxc...@ender.evo6.com>...
> ka...@gabi-soft.de (James Kanze) writes:

> > an...@evo6.com (Andy Sawyer) wrote in message
> > news:<bs6ewe...@ender.evo6.com>...
> > > > Here's the same question without reference to time travel. If
> > > > the program invokes undefined behavior, could a conforming
> > > > compiler (with unusually bad QoI) erase part of the standard
> > > > library, so that future compiles would fail?

> > > Yes, that's absolutelty possible (if somewhat unlikly). "undefined
> > > behaviour" could (for example) include destruction of the media on
> > > which the compiler and library is stored. I doubt the vendor would
> > > stay in business for long though.

> > I wouldn't bet on it. I've actually used a compiler where this was
> > possible.

> I was thinking more in terms of physical destruction of the media,

I don't think off hand that I've ever worked on a system which could
physically destroy a diskette, but once the undefined behavior starts
modifying the OS -- misconfiguring a CRT can cause it to go up in smoke
on a lot of machines. I've actually seen a PCB go up in smoke as a
result of a wrong configuration; admittedly, we changed the design as a
result so that it couldn't happen. And I think that you could get a
head crash (and thus really destroy the media) on some of your older
hard disks, by powering down the spindle without explicitly unloading
the heads.

The probability is small enough that I'm not too worried about it, but
presumably, if the modified OS starts sending just the right data out
over the network, you could end up breaking into some critical system,
generating some secret command, and launching a missle from a silo in
Nebraska. In that case, you will not only destroy the media, but
everything else in a 500 km radius.

When they say undefined behavior, they mean it.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

---

Andy Sawyer

unread,
Oct 8, 2002, 8:33:17 AM10/8/02
to
ka...@gabi-soft.de (James Kanze) writes:

> an...@evo6.com (Andy Sawyer) wrote in message

> news:<ptutxc...@ender.evo6.com>...


>
> > I was thinking more in terms of physical destruction of the media,
>

[...]


>
> I've actually seen a PCB go up in smoke as a result of a wrong
> configuration;

I got a blister from a static RAM (6116, IIRC. I probably still have
it somewhere...) and pulled the power before the board went up in
smole :-)

> When they say undefined behavior, they mean it.

Which was entirely my original point :-)

Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man

---

Balog Pal

unread,
Oct 8, 2002, 1:15:37 PM10/8/02
to
> > > Here's the same question without reference to time travel. If the
> > > program invokes undefined behavior, could a conforming compiler
> > > (with unusually bad QoI) erase part of the standard library, so that
> > > future compiles would fail?

> I wouldn't bet on it. I've actually used a compiler where this was


> possible. Writing through an uninitialized pointer could cause the next
> disk read to in fact reformat the hard disk. The odds were very much
> against it, of course

Back in tha days I used DOS as environment It was pretty easy to kill the
disk. And some ill-behaving programs actually did so. Writing through a
trash pointer could overwrite some data structures of the CACHE program.
Guess it wrote a pack of zeroes -- so a few moments later I found the master
boot record of the hard disk overwrtten with a random sector. :)
[fortunately I have a plenty of experience in restoring disk partitions and
FAT filesystems, so I lost nothing...]

NT never did something like that to me -- however just following the
'tutorial' of debugger on sparcstation/solaris made the system crash
completely -- and also killing a plenty of data on the harddisk. Files that
participated in the last compile, most of them used as read-only and owned
by root or someone. M$ has no monopoly on misbehavior.

Paul

James Kanze

unread,
Oct 9, 2002, 1:02:50 PM10/9/02
to
pa...@lib.hu ("Balog Pal") wrote in message
news:<3da3...@andromeda.datanet.hu>...

> > > > Here's the same question without reference to time travel. If
> > > > the program invokes undefined behavior, could a conforming
> > > > compiler (with unusually bad QoI) erase part of the standard
> > > > library, so that future compiles would fail?

> > I wouldn't bet on it. I've actually used a compiler where this was
> > possible. Writing through an uninitialized pointer could cause the
> > next disk read to in fact reformat the hard disk. The odds were
> > very much against it, of course

> Back in tha days I used DOS as environment It was pretty easy to kill
> the disk. And some ill-behaving programs actually did so. Writing
> through a trash pointer could overwrite some data structures of the
> CACHE program. Guess it wrote a pack of zeroes -- so a few moments
> later I found the master boot record of the hard disk overwrtten with
> a random sector. :) [fortunately I have a plenty of experience in
> restoring disk partitions and FAT filesystems, so I lost nothing...]

> NT never did something like that to me -- however just following the
> 'tutorial' of debugger on sparcstation/solaris made the system crash
> completely -- and also killing a plenty of data on the harddisk. Files
> that participated in the last compile, most of them used as read-only
> and owned by root or someone. M$ has no monopoly on misbehavior.

I wasn't trying to knock Microsoft. If the hardware doesn't support
memory protection, it's pretty hard to do otherwise, and I know of no OS
which offers much protection under such circumstances. And as you say,
even when the hardware protection is present, you're never safe from a
bug in the OS, or anywhere else -- the very first program I ever wrote
in C++ for a Sun machine caused a segment violation in kernel code. (My
impression is that modern Solaris or HP/UX are very robust, the Linux
and Windows 2000 are getting there, and acceptable for a lot of work,
but that Windows NT was still a bit flaky if the program had to run for
days on end -- but quite acceptable for client software if the user
rebooted each day.)

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

---

Allan W

unread,
Oct 9, 2002, 10:29:06 PM10/9/02
to
> > ka...@gabi-soft.de (James Kanze) writes:
> > > I've actually used a compiler where
[destruction of the media on which the compiler and library is stored]
> > > was possible.

> an...@evo6.com (Andy Sawyer) wrote


> > I was thinking more in terms of physical destruction of the media,

ka...@gabi-soft.de (James Kanze) wrote


> I don't think off hand that I've ever worked on a system which could

> physically destroy a diskette...

What about malfunctioning software permanently damaging a disk drive?

When the Commodore 64 was designed, they evidently considered a "disk
drive" to be an expense that few home users would care for. Once it
became obvious that this decision was bad, they did create a diskette
drive -- but to make it compatible with their original computer, they
connected it through the serial port. As far as I know, this became
the only 300-baud disk drive ever used. As a result, loading major
programs from floppy disk could easily take 5 to 10 minutes (until
various third-party "speed up" programs were available).

This same disk drive had another glitch. Although the normal ROM O/S
was very careful with the disk drive, machine-language programs (which
were "POKE"d into memory from the BASIC interpreter) could cause the
drive to step the heads past track 80. Some (not Commodore) considered
this a feature, because you could extend the amount of data stored on
a disk. However, if you stepped the heads too far, they would literally
fall into a groove that the motor could not pull them back out of.
You could say that this did NOT permanently damage the disk drive,
because it was easy to open the drive and move the heads back with your
finger -- but doing so would not only intimidating for home users, but
it would also void your warantee. I have no idea how much it would
cost to send the drive back to Commodore to move the heads back, but
I'm sure it wasn't cheap.

[Attempting to bring this back to topic] My point is, normally software
isn't able to damage hardware, other than perhaps wearing it out from
overuse -- but there are exceptions.

Perhaps another exception would be writing to CMOS, which could cause
your CPU to run too quickly (and therefore burn it out). On some
hardware with power supplies meant to work from either 110V or 220V, I
suspect (but don't know) that it could even cause the power supply to
change voltage.

0 new messages