Left shift

  • Thread starter Christian Christmann
  • Start date
J

Jerry Coffin

Section 4: "An expression e can be implicitly converted to
a type T if and only if the declaration T t = e is well-formed".

That doesn't mention anything about "compile time".

[ ... ]
However, one could argue that evaluating the constant expression at
runtime and issuing a runtime error ("dynamic type mismatch", or
some such) would be a correct implementation.

One certainly could. I believe one would have exceptional difficulty
finding anything to the contrary in the standard.
I'm not sure if that's a valid argument, but it's certainly an
unattractive solution.

I'm pretty sure it is a valid argument. IMO, when C++ is implemented as
a compiler, it's better for as many errors as possible to prevent
compilation, rather than resulting in runtime errors. That, however, is
a personal opinion about quality of implementation -- while I'm fairly
sure some parts of the standard were written to allow and perhaps even
subtly encourage it, I don't believe it's a requirement.

As far as being unattractive: it depends. I can think of some fair
reasons for using a C++ interpreter, and an interpreter more or less
eliminates the whole concept of "compile time"...
 
K

Kai-Uwe Bux

Jerry said:
Section 4: "An expression e can be implicitly converted to
a type T if and only if the declaration T t = e is well-formed".

That doesn't mention anything about "compile time".

[ ... ]
However, one could argue that evaluating the constant expression at
runtime and issuing a runtime error ("dynamic type mismatch", or
some such) would be a correct implementation.

One certainly could. I believe one would have exceptional difficulty
finding anything to the contrary in the standard.
I'm not sure if that's a valid argument, but it's certainly an
unattractive solution.

I'm pretty sure it is a valid argument. IMO, when C++ is implemented as
a compiler, it's better for as many errors as possible to prevent
compilation, rather than resulting in runtime errors. That, however, is
a personal opinion about quality of implementation -- while I'm fairly
sure some parts of the standard were written to allow and perhaps even
subtly encourage it, I don't believe it's a requirement.

Hm, I am not sure. [1.4/2] says:

Although this International Standard states only requirements on C++
implementations, those requirements are often easier to understand if they
are phrased as requirements on programs, parts of programs, or execution
of programs. Such requirements have the following meaning:

? If a program contains no violations of the rules in this International
Standard, a conforming implementation shall, within its resource limits,
accept and correctly execute3) that program.
? If a program contains a violation of any diagnosable rule, a conforming
implementation shall issue at least one diagnostic message, except that
? If a program contains a violation of a rule for which no diagnostic is
required, this International Standard places no requirement on
implementations with respect to that program.

Now, I would maintain that it is the "implementation" which is required to
issue a diagnostic message of a diagnosable rule and not the program during
its execution. Thus, if the implementation is a compiler (so that it is
observable whether the implementation or the program issues the message),
diagnostics for diagnosable rules have to be issued by the compiler. At
least that is how I read the second item in the list.

In particular: if I compile a program but never run it, a successful compile
without diagnostics should mean that the program satisfies all diagnosable
rules for which diagnostics are not explicitly waived.
As far as being unattractive: it depends. I can think of some fair
reasons for using a C++ interpreter, and an interpreter more or less
eliminates the whole concept of "compile time"...

True, and in that case, you cannot really observe whether the implementation
or the program issues the diagnostics. However, the standard says it should
be the implementation.


Best

Kai-Uwe Bux
 
J

Jerry Coffin

[ ... diagnosing at compile time rather than execution time: ]
Hm, I am not sure. [1.4/2] says:

[ ... ]
? If a program contains no violations of the rules in this International
Standard, a conforming implementation shall, within its resource limits,
accept and correctly execute3) that program.

[ ... ]
Now, I would maintain that it is the "implementation" which is required to
issue a diagnostic message of a diagnosable rule and not the program during
its execution.

I've re-quoted part of your quote from the standard above. This makes it
quite clear that it is the implementation that executes the program --
as such, things that are part of the implementation can quite reasonably
happen at execution time.
 
S

Steve Pope

Jerry Coffin said:
(e-mail address removed) says...
That doesn't mention anything about "compile time".
One certainly could. I believe one would have exceptional difficulty
finding anything to the contrary in the standard.
I'm pretty sure it is a valid argument.

Okay, I now agree with your position -- the constant evaluation
can occur at runtime if a resulting type mismatch causes a
runtime error.

Had you said this in the first place, rather than making
misleading arguments about undefined behavior that completely
missed the point, we would have been in agreement far sooner.

Steve
 
J

Jerry Coffin

[email protected] says... said:
Had you said this in the first place, rather than making
misleading arguments about undefined behavior that completely
missed the point, we would have been in agreement far sooner.

I certainly didn't intend anything I said to be misleading.

The original piece of code included undefined behavior -- and I'm
reasonably convinced that undefined behavior "trumps" nearly anything
else -- undefined behavior removes the requirement for a diagnostic
(along with all other requirements).

The more recent bit of code you posted did not include undefined
behavior -- and in its absence, I'm reasonably certain a diagnostic is
required.
 
K

Kai-Uwe Bux

Jerry said:
[ ... diagnosing at compile time rather than execution time: ]
Hm, I am not sure. [1.4/2] says:

[ ... ]
? If a program contains no violations of the rules in this
International
Standard, a conforming implementation shall, within its resource
limits, accept and correctly execute3) that program.

[ ... ]
Now, I would maintain that it is the "implementation" which is required
to issue a diagnostic message of a diagnosable rule and not the program
during its execution.

I've re-quoted part of your quote from the standard above. This makes it
quite clear that it is the implementation that executes the program --
as such, things that are part of the implementation can quite reasonably
happen at execution time.

The sentence that you emphasized only deals with programs that contain no
violations of any diagnosable rules and only requires that those programs
be executed. The sentence does not apply at all to programs that violate
any diagnosable rule and neither gives any license nor any requirement for
what an implementation is supposed to do about those programs.

Now, as far as the execution of programs that violate rules is concerned,
you will find relevant language in [1.4/8]:

A conforming implementation may have extensions (including additional
library functions), provided they do not alter the behavior of any
well-formed program. Implementations are required to diagnose programs
that use such extensions that are ill-formed according to this
International Standard. Having done so, however, they can compile and
execute such programs.

Note that the standard demands that the diagnostics are given *before* the
program is executed ("Having done so").

Thus, although

int* p;
p = 1;

is ill-formed an implementation may take the license to compile and execute
a program containing those line (as an extension), but it is required to
flag the error beforehand.


Best

Kai-Uwe Bux
 
J

Jerry Coffin

[ ... ]
A conforming implementation may have extensions (including additional
library functions), provided they do not alter the behavior of any
well-formed program. Implementations are required to diagnose programs
that use such extensions that are ill-formed according to this
International Standard. Having done so, however, they can compile and
execute such programs.

Note that the standard demands that the diagnostics are given *before* the
program is executed ("Having done so").

By this reading, it's also required to issue the diagnostic *before*
compiling the program. Given that it's normally the compiler the issues
such diagnostics, I think you're reading more into it than is really
there...
 
K

Kai-Uwe Bux

Jerry said:
[ ... ]
A conforming implementation may have extensions (including additional
library functions), provided they do not alter the behavior of any
well-formed program. Implementations are required to diagnose programs
that use such extensions that are ill-formed according to this
International Standard. Having done so, however, they can compile and
execute such programs.

Note that the standard demands that the diagnostics are given *before*
the program is executed ("Having done so").

By this reading, it's also required to issue the diagnostic *before*
compiling the program. Given that it's normally the compiler the issues
such diagnostics, I think you're reading more into it than is really
there...

I in this context, I would read compiling as "producing the executable". I
agree that the language could be more decisive, however I think, the intent
or at least the desire for compile-time diagnostics is clear.

Also, consider the case where a program is not run (e.g., intermediate
stages in debugging where you just compile to check whether you introduced
typos). Where do you find the language in the standard that waives the
required diagnostics, i.e., where do you find that diagnostics is only
required *if* the program is actually run?

Finally, what about programs like this:

#include <iostream>

int main ( void ) {
int i = 0;
int * p = 0;
if ( std::cin >> i ) {
p = 1;
}
}

This program is ill-formed, however, a naive run-time check will only flag
that for certain inputs. I think the standard does not give license to only
flag those ill-formed lines that are executed for a particular input.


Best

Kai-Uwe Bux
 
S

Steve Pope

Kai-Uwe Bux said:
Finally, what about programs like this:

#include <iostream>

int main ( void ) {
int i = 0;
int * p = 0;
if ( std::cin >> i ) {
p = 1;
}
}
This program is ill-formed, however, a naive run-time check
will only flag that for certain inputs. I think the standard
does not give license to only flag those ill-formed lines that
are executed for a particular input.

A good way to resolve this, but one I don't see in the standard,
is not to allow partial execution of any ill-formed program.
If that is not in the standard, perhaps it is a deliberate omission
to allow interpreters.

Another possibility is that any ability to partially execute an
ill-formed program constitutes a "language extension" and the rules
you quoted previously apply.

Steve
 
J

Jerry Coffin

[ ... ]
I in this context, I would read compiling as "producing the executable". I
agree that the language could be more decisive, however I think, the intent
or at least the desire for compile-time diagnostics is clear.

In $1.9/1, they say:

This International Standard places no requirement on the
structure of conforming implementations. In particular,
they need not copy or emulate the structure of the abstract
machine. Rather, conforming implementations are required to
emulate (only) the observable behavior of the abstract
machine as explained below.

My guess is that it's a relatively simple situation: most of the authors
are sufficiently accustomed to a compiler type of implementation that
they more or less take it for granted in their writing, even though they
clearly don't intend that it be a requirement.

[ ... ]
This program is ill-formed, however, a naive run-time check will only flag
that for certain inputs. I think the standard does not give license to only
flag those ill-formed lines that are executed for a particular input.

I think from a viewpoint of conformance, this is almost entirely a QOI
issue. The requirement is ($1.4/2):

If a program contains a violation of any diagnosable rule,
a conforming implementation shall issue at least one
diagnostic message, except that If a program contains a
violation of a rule for which no diagnostic is required,
this International Standard places no requirement on
implementations with respect to that program.

Strictly from a viewpoint of conforming, that's trivial to meet: simply
issue a diagnostic before commencing interpretation of anything. If you
wanted to conform without modifying your code, change the documentation
to say your copyright notice was a "diagnostic" and you'd be done.

I'll openly admit that's probably not what anybody wanted or intended,
but I can't think of any part of the standad it'd violate either...
 
K

Kai-Uwe Bux

Jerry said:
[ ... ]
I in this context, I would read compiling as "producing the executable".
I agree that the language could be more decisive, however I think, the
intent or at least the desire for compile-time diagnostics is clear.

In $1.9/1, they say:

This International Standard places no requirement on the
structure of conforming implementations. In particular,
they need not copy or emulate the structure of the abstract
machine. Rather, conforming implementations are required to
emulate (only) the observable behavior of the abstract
machine as explained below.

My guess is that it's a relatively simple situation: most of the authors
are sufficiently accustomed to a compiler type of implementation that
they more or less take it for granted in their writing, even though they
clearly don't intend that it be a requirement.

I don't see how that quote says anything about whether interpreters are
allowed. It seems to be more concerned to give an explicit license to
compile C++ into native code instead of compiling it into some
pseudo-machine language for an emulator of the abstract machine.

I agree, though, that this quote does state that code generation can be
trivial (the identity map on the program) provided execution is done by an
interpreting engine. That, however, is inconsequential for whether
diagnostics are do be issued before execution or may be postponed until
run-time.
[ ... ]
This program is ill-formed, however, a naive run-time check will only
flag that for certain inputs. I think the standard does not give license
to only flag those ill-formed lines that are executed for a particular
input.

I think from a viewpoint of conformance, this is almost entirely a QOI
issue. The requirement is ($1.4/2):

If a program contains a violation of any diagnosable rule,
a conforming implementation shall issue at least one
diagnostic message, except that If a program contains a
violation of a rule for which no diagnostic is required,
this International Standard places no requirement on
implementations with respect to that program.

Strictly from a viewpoint of conforming, that's trivial to meet: simply
issue a diagnostic before commencing interpretation of anything. If you
wanted to conform without modifying your code, change the documentation
to say your copyright notice was a "diagnostic" and you'd be done.

I agree. Note that in this implementation you do not even need to issue any
further diagnostics at run-time. You can just execute

int* p = 1;

in any way you like (as an extension).
I'll openly admit that's probably not what anybody wanted or intended,
but I can't think of any part of the standad it'd violate either...

True, if you put a catch all error message up front, you are free do do
whatever you please as long as you correctly execute conforming programs.

Still, a C++ interpreter (in the usual sense of the word: something that
reads a program line by line, executes what is to be executed and complains
about errors along the way) would not qualify as a conforming
interpretation. That does not mean that such C++ interpreters are a bad
thing. It just means that they are not conforming. (And it also means that
from a few successful runs of a program in an interpreter, you cannot
deduce that the program is well-formed; if a conforming compiler succeeds
without diagnostics, you have some assurance.)


Best

Kai-Uwe Bux
 
J

Jerry Coffin

[ ... ]
I don't see how that quote says anything about whether interpreters are
allowed.

It seems to be that "interpreter" describes the structure of an
implementation. To repeat: "This International Standard places no
requirement on the structure of conforming implementations."

I don't see how that could be read as anything short of explicit
permission for an implementation to be an interpreter.
It seems to be more concerned to give an explicit license to
compile C++ into native code instead of compiling it into some
pseudo-machine language for an emulator of the abstract machine.

It explicitly places NO requirement on the structure of a conforming
implementation. How can that possibly be read as limiting the range of
possible implementations in any way?
I agree. Note that in this implementation you do not even need to issue any
further diagnostics at run-time. You can just execute

int* p = 1;

in any way you like (as an extension).

I agree.
Still, a C++ interpreter (in the usual sense of the word: something that
reads a program line by line, executes what is to be executed and complains
about errors along the way) would not qualify as a conforming
interpretation.

I still really don't agree in this respect. When you read "Having done
so, however, they can compile and execute such programs." as meaning
"the diagnostic must take place before execution, but can take place
during or after compilation" it sounds extremely strained to me --
you're taking exactly the same words to specify extremely tight
sequencing requirements in one part, but virtually no sequencing
requirements in the other part.

It seems to me that when the exact same words are applied to two things
(compilation and execution) they have to be applied in the same way to
both. If this is taken as meaning that any required diagnostic must be
issued before execution begins, then it also requires that it be issued
before compilation begins. If it means it can be issued sometime during
compilation, then it also means it can be issued sometime during
execution.
 
K

Kai-Uwe Bux

Jerry said:
[ ... ]
I don't see how that quote says anything about whether interpreters are
allowed.

It seems to be that "interpreter" describes the structure of an
implementation. To repeat: "This International Standard places no
requirement on the structure of conforming implementations."

I don't see how that could be read as anything short of explicit
permission for an implementation to be an interpreter.

Interpreters (in the traditional meaning of the term) could be ruled out by
requirements of the standard upon the *behavior* and not upon the
*structure* of an implementation.

It explicitly places NO requirement on the structure of a conforming
implementation. How can that possibly be read as limiting the range of
possible implementations in any way?

I guess, I was not clear about this. I think we are in agreement here. I
already said, in the part you snipped,

In other words an interpreter is clearly a possible structure for an
implementation.

However, whether the implementation has to issue all required diagnostics
independently of whether a program is executed or whether it is allowed to
issue some of those diagnostics while the program is running and maybe even
only when flow control takes certain paths, this question is about behavior
not structure; and the standard clearly imposes restrictions on the
behavior of conforming implementations.

So even an interpreter could be required to perform static analysis of a
program before execution (or at least independently of execution) so that
an ill-formed program will be diagnosed as such even if the path of
execution never hits upon the ill-formed line. I think that the standard
actually requires that explicitly when it asks that for every ill-formed
program there has to be at least one diagnostic message. (We already agree
in the next paragraph that this is easy to satisfy: however an interpreter
in the traditional sense would not do so.)

I agree.


I still really don't agree in this respect. When you read "Having done
so, however, they can compile and execute such programs." as meaning
"the diagnostic must take place before execution, but can take place
during or after compilation" it sounds extremely strained to me --
you're taking exactly the same words to specify extremely tight
sequencing requirements in one part, but virtually no sequencing
requirements in the other part.

I already provided a reading of "compilation" that does not run into this
kind of problem (namely compilation=code generation). It is a good principle
to interpret terms so that the provisions of the standard come out
meaningfully. The reading I propose does that.

However, I admit that this reading is called into question by the
admissibility of non-compiling implementations. Note, however, that the
possibility of non-compiling implementations makes it somewhat hard to take
the term "compilation" in this paragraph too serious at all. That, however,
does not apply to the term "execution". (I am not inclined to
treat "compile and execute" as a compound phrase: for one, it is clearly
possible that the implementation compiles a program but does not execute
it; for a second reason, refer to the my response to the next paragraph.)
It seems to me that when the exact same words are applied to two things
(compilation and execution) they have to be applied in the same way to
both. If this is taken as meaning that any required diagnostic must be
issued before execution begins, then it also requires that it be issued
before compilation begins. If it means it can be issued sometime during
compilation, then it also means it can be issued sometime during
execution.

I admit that this is a possible interpretation. However, it throws the
words "Having done so, ..." right out of the window. And I think, the
rational you provide is shaky: you want to apply the phrase "Having done
so, however, they can do X" equally to "compile " and to "execute".
However, you end up not applying the phrase at all -- you end up ignoring
it. All that because your reading of "compile" renders a part of the
provision unenforcible.

I disagree with this approach: One of the principles in interpreting
normative materials such as laws or contracts is that the inapplicability
of one provision does not, in itself, void any other. Even if there are
compelling reasons to read the term "compilation" in a way that makes it
impossible to issue diagnostics before, then this renders only a certain
normative aspect of this clause non-sensical. Any other aspect of this
clause should be unaffected: and it *is* possible to issue diagnostics
before execution regardless of how you read the term "compilation". The
idea behind this hermeneutic guideline is to preserve as much of the
normative force of the wording as possible.


Best

Kai-Uwe Bux
 
J

Jerry Coffin

[ ... ]
I already provided a reading of "compilation" that does not run into this
kind of problem (namely compilation=code generation).

Except that 1) we both know that's NOT what compile really means, and 2)
it still wouldn't work that way. For example, if you call a function but
never define it, that isn't actually diagnosed until the very end of
_linking_, which normally follows code generation. Therefore, we can't
even treat it as code generation -- we have to treat it as the final
step of linking.

By the time you're done, you've simply played a nice little word game in
which you define before as "before the end of" for one term, but as
"before the beginning of" for the other.

This seems to me a simple situation where you've pre-decided the
outcome, and you're re-defining things as much as necessary to fit that
conclusion.
It is a good principle
to interpret terms so that the provisions of the standard come out
meaningfully. The reading I propose does that.

Your reading still renders the past tense part of "having done that"
meaningless -- the compile and link process has to run virtually to
completion before some required diagnostics can be issued (short of the
previously mentioned cheat of simply issuing some "diagnostic" at the
very beginning of every attempt, which applies equally to interpreters
and compilers).

The fact of the matter is that no matter what words you use to try to
change it, you're still reading it as saying that before means "before
the beginning of" in one case, and "before the end of" in the other. I
maintain that if you're going to read it as "before the end of" in one
case, that it must also mean "before the end of" in the other case as
well.

To me, it looks like you started with a particular conclusion, and
you're willing to re-define some thing things and ignore others
completely to support the conclusion you want. I have little doubt you
see my position similarly. I think each of us understands the other's
position, and simply disagree as to the wisdom of drawing one conclusion
vs. another from the same data (which I think we can also agree is
somewhat ambiguous about the point we're discussing).

That being the case, unless the data changes (e.g. different wording in
the new C++ standard), I see little point in continuing the discussion.
I think we've reached the point at which we're clearly going to disagree
on this point, and our only choice is whether to do so in a friendly or
unfriendly fashion; personally, I'd rather discontinue the discussion
rather than let it degenerate into something unfriendly.
 
K

Kai-Uwe Bux

Jerry said:
[ ... ]
I already provided a reading of "compilation" that does not run into this
kind of problem (namely compilation=code generation).

Except that 1) we both know that's NOT what compile really means, and 2)
it still wouldn't work that way. For example, if you call a function but
never define it, that isn't actually diagnosed until the very end of
_linking_, which normally follows code generation. Therefore, we can't
even treat it as code generation -- we have to treat it as the final
step of linking.

Ah, you are right: I didn't think about linking.
By the time you're done, you've simply played a nice little word game in
which you define before as "before the end of" for one term, but as
"before the beginning of" for the other.

This seems to me a simple situation where you've pre-decided the
outcome, and you're re-defining things as much as necessary to fit that
conclusion.


Your reading still renders the past tense part of "having done that"
meaningless -- the compile and link process has to run virtually to
completion before some required diagnostics can be issued (short of the
previously mentioned cheat of simply issuing some "diagnostic" at the
very beginning of every attempt, which applies equally to interpreters
and compilers).

The fact of the matter is that no matter what words you use to try to
change it, you're still reading it as saying that before means "before
the beginning of" in one case, and "before the end of" in the other. I
maintain that if you're going to read it as "before the end of" in one
case, that it must also mean "before the end of" in the other case as
well.

Ok, I agree that compilation after diagnostics does not fly.
To me, it looks like you started with a particular conclusion, and
you're willing to re-define some thing things and ignore others
completely to support the conclusion you want. I have little doubt you
see my position similarly. I think each of us understands the other's
position, and simply disagree as to the wisdom of drawing one conclusion
vs. another from the same data (which I think we can also agree is
somewhat ambiguous about the point we're discussing).

Yes, we can agree on that. This is not the first time that the standard is a
little wanting with regard to clarity.
That being the case, unless the data changes (e.g. different wording in
the new C++ standard), I see little point in continuing the discussion.
I think we've reached the point at which we're clearly going to disagree
on this point, and our only choice is whether to do so in a friendly or
unfriendly fashion; personally, I'd rather discontinue the discussion
rather than let it degenerate into something unfriendly.

During this whole discussion, I never had the feeling that we were in danger
of getting unfriendly. I also share your feeling that we will have to just
disagree. Let's abandon this thread. Thanks a lot for this exchange.


Best

Kai-Uwe Bux
 
S

Steve Pope

Jerry Coffin said:
To me, it looks like you started with a particular conclusion, and
you're willing to re-define some thing things and ignore others
completely to support the conclusion you want. I have little doubt you
see my position similarly. I think each of us understands the other's
position, and simply disagree as to the wisdom of drawing one conclusion
vs. another from the same data (which I think we can also agree is
somewhat ambiguous about the point we're discussing).
That being the case, unless the data changes (e.g. different wording in
the new C++ standard), I see little point in continuing the discussion.
I think we've reached the point at which we're clearly going to disagree
on this point, and our only choice is whether to do so in a friendly or
unfriendly fashion; personally, I'd rather discontinue the discussion
rather than let it degenerate into something unfriendly.


Your posts on this thread have not been "unfriendly" (in my view),
they have just been slow to consider as a serious question
that leaving the evaluation of this particular form of ill-formed
program to runtime might be incorrect.

Here, "incorrect" means not just conformance to the standard,
but also conformance to engineering best practices as applied to
language translators.

I offered up the question because I believe it to be meaningful
to language implementors and users.

Steve
 
J

Jerry Coffin

[email protected] says... said:
Here, "incorrect" means not just conformance to the standard,
but also conformance to engineering best practices as applied to
language translators.

If there was ever a mention of correctness beyond conformance, I missed
it. I completely agree that it's by far best for problems to be
diagnosed as early as possible.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top