A C without void*

A

Anders Wegge Keller

Keith Thompson said:
Adding a depth argument, in my opinion, would have been a really bad
way to implement multi-level breaks. It would make far more sense
for continue and break to take a *label* as an optional argument.
(There's ample precedent for that in other languages.)

What would be the difference between break and goto be in a case like
this:

int foo (int bar) {

int q, i, x;

for (q = 0 ; q < bar ; q++) {
breakout:
for (i = 0 ; i < bar*q ; i++) {
for (x = 0 ; x < q ; x++) {
if ((x / q) % i == 42) {
goto breakout;
}
}
}
/* It would be clearer to have the label here, but otherwise? */
}

return x % i;
}

Yes, I know that this probably won't compile. I've just cooked it up
in my mail client, but that's beside the point. I just wanted to add
some semblance to a real function.
 
B

Ben Bacarisse

Spiros Bousbouras said:
It wouldn't be ideal but I wouldn't call it "really bad". There would
be a potential for bugs but one can have much more insidious bugs in C.
I agree it would make more sense to have labeled loop statements but
for that you would have to change the syntax of for , while , etc.
which would break existing code.

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i < n; i++)
for (int j = i; i < n; j++)
if (A[j] == target)
break outer;

<snip>
 
B

Ben Bacarisse

Anders Wegge Keller said:
What would be the difference between break and goto be in a case like
this:

int foo (int bar) {

int q, i, x;

for (q = 0 ; q < bar ; q++) {
breakout:
for (i = 0 ; i < bar*q ; i++) {
for (x = 0 ; x < q ; x++) {
if ((x / q) % i == 42) {
goto breakout;
}
}
}
/* It would be clearer to have the label here, but otherwise? */
}

return x % i;
}

The goto will restart the 'i' loop without any change to 'q'. With a
proposed labeled break in place of the goto would terminate both the 'x'
and the 'i' loop and move on to the next value of 'q'.
Yes, I know that this probably won't compile.

It compiles just fine, as it happens.

<snip>
 
S

Spiros Bousbouras

Spiros Bousbouras said:
It wouldn't be ideal but I wouldn't call it "really bad". There would
be a potential for bugs but one can have much more insidious bugs in C.
I agree it would make more sense to have labeled loop statements but
for that you would have to change the syntax of for , while , etc.
which would break existing code.

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i < n; i++)
for (int j = i; i < n; j++)
if (A[j] == target)
break outer;


And I take it that "continue outer" would evaluate i++ and then i < n ,
is that the idea ? But what rule is being used to associate a specific
label with a loop ? For example would

outer:
for (int i = 0; i < n; i++)
for (int j = i; i < n; j++)
if (A[j] == target)
continue outer;

also supposed to work ?
 
A

Anders Wegge Keller

Ben Bacarisse said:
The goto will restart the 'i' loop without any change to 'q'. With
a proposed labeled break in place of the goto would terminate both
the 'x' and the 'i' loop and move on to the next value of 'q'.

Ooops. That would (could at least) cause an endless loop in this
case.
 
K

Keith Thompson

Anders Wegge Keller said:
What would be the difference between break and goto be in a case like
this:

int foo (int bar) {

int q, i, x;

for (q = 0 ; q < bar ; q++) {
breakout:
for (i = 0 ; i < bar*q ; i++) {
for (x = 0 ; x < q ; x++) {
if ((x / q) % i == 42) {
goto breakout;
}
}
}
/* It would be clearer to have the label here, but otherwise? */
}

return x % i;
}

Yes, I know that this probably won't compile. I've just cooked it up
in my mail client, but that's beside the point. I just wanted to add
some semblance to a real function.

The idea of a labeled break (or continue, but I'll set that aside
for brevity) is that the label is the name of the loop, not (just)
the name of a specific point in the code. "break foo" and "continue
foo" branch to two different places, but both use the same name to
refer to the loop.

For example:

OUTER:
while (cond) {
INNER:
while (cond) {
if (done_with_inner) {
break INNER; /* could be just "break;" */
}
if (done_with_outer) {
break OUTER;
}
}
}

A goto statement equivalent to "break OUTER;" would have to branch to a
label *following* the outer loop. Furthermore, it would be illegal
(well, a constraint violation) if "OUTER" were not a label that applies
to a loop enclosing the break statement.

This proposal re-uses the existing label syntax. (Perl does the same
thing.)

Another possibility might be to create a new label syntax to be used
only for loops. I don't necessarily suggest using "::" for this, but
if I did, the above would look like:

OUTER::
while (cond) {
INNER::
while (cond) {
if (done_with_inner) {
break INNER; /* could be just "break;" */
}
if (done_with_outer) {
break OUTER;
}
}
}

Then "goto OUTER;" or "goto INNER;" would not be permitted. Ada does
this; it uses the (deliberately ugly) syntax "<<identifier>>" for
labels that can be targets of goto statements, and "identifier:"
for names of loops and blocks.

If this were to be added to C, I'd be ok with re-using the existing
label syntax. As I said, Perl does this, and it doesn't seem to
cause any confusion. (I don't recall ever writing a goto in Perl,
aside from some small test programs.)
 
B

Ben Bacarisse

Spiros Bousbouras said:
So the committee introduced a new pointer type out of the blue. Wow ,
that's a bold move. Certainly bolder than adding a depth argument to
continue or break which was not done. From the C99 rationale:

6.8.6.2 The continue statement

The C89 Committee rejected proposed enhancements to continue
and break which would allow specification of an iteration
statement other than the immediately enclosing one on grounds
of insufficient prior art.

Adding a depth argument, in my opinion, would have been a really bad
way to implement multi-level breaks. It would make far more sense
for continue and break to take a *label* as an optional argument.
(There's ample precedent for that in other languages.)

It wouldn't be ideal but I wouldn't call it "really bad". There would
be a potential for bugs but one can have much more insidious bugs in C.
I agree it would make more sense to have labeled loop statements but
for that you would have to change the syntax of for , while , etc.
which would break existing code.

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i < n; i++)
for (int j = i; i < n; j++)
if (A[j] == target)
break outer;


And I take it that "continue outer" would evaluate i++ and then i < n ,
is that the idea ?
Yes.

But what rule is being used to associate a specific
label with a loop ? For example would

outer:
for (int i = 0; i < n; i++)
for (int j = i; i < n; j++)
if (A[j] == target)
continue outer;

also supposed to work ?


Yes, you've just altered the white space (unless I've missed the point
you are making). Statements can have labels and thus iteration
statements can have labels. The rule is that break x and continue x are
only valid when x is the label of an iteration statement (technically "a
label of" since statements can have several labels).
 
R

robertwessel2

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:
  outer: for (int i = 0; i < n; i++)
             for (int j = i; i < n; j++)
                 if (A[j] == target)
                      break outer;


And I take it that "continue outer" would evaluate i++ and then i < n ,
is that the idea ? But what rule is being used to associate a specific
label with a loop ? For example would

outer:
for (int i = 0; i < n; i++)
    for (int j = i; i < n; j++)
        if (A[j] == target)
            continue outer;

also supposed to work ?


No rule change required. The label is an optional prefix to a
statement anyway, it is *not* a standalone item. For example, you
cannot have a label just before a closing brace, unless you toss a
empty statement (";") after it.

This has always been my proposal anyway. If the for/while/do/break
has a label, it can be referenced by a break/continue nested within
it. No backwards compatibility issues, no broken code…
 
K

Keith Thompson

Spiros Bousbouras said:
On Tue, 22 Mar 2011 21:40:31 +0000
The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i < n; i++)
for (int j = i; i < n; j++)
if (A[j] == target)
break outer;


And I take it that "continue outer" would evaluate i++ and then i < n ,
is that the idea ? But what rule is being used to associate a specific
label with a loop ? For example would

outer:
for (int i = 0; i < n; i++)
for (int j = i; i < n; j++)
if (A[j] == target)
continue outer;

also supposed to work ?


Certainly. A label is (already) associated with a particular statement.
In the proposal (at least in mine), if the statement is a loop
(an iteration statement), then a continue or break within the loop
can use the label to specify that loop.
 
S

Spiros Bousbouras

The idea of a labeled break (or continue, but I'll set that aside
for brevity) is that the label is the name of the loop, not (just)
the name of a specific point in the code. "break foo" and "continue
foo" branch to two different places, but both use the same name to
refer to the loop.

For example:

OUTER:
while (cond) {
INNER:
while (cond) {
if (done_with_inner) {
break INNER; /* could be just "break;" */
}
if (done_with_outer) {
break OUTER;
}
}
}

A goto statement equivalent to "break OUTER;" would have to branch to a
label *following* the outer loop. Furthermore, it would be illegal
(well, a constraint violation) if "OUTER" were not a label that applies
to a loop enclosing the break statement.

This proposal re-uses the existing label syntax. (Perl does the same
thing.)

Another possibility might be to create a new label syntax to be used
only for loops. I don't necessarily suggest using "::" for this, but
if I did, the above would look like:

OUTER::
while (cond) {
INNER::
while (cond) {
if (done_with_inner) {
break INNER; /* could be just "break;" */
}
if (done_with_outer) {
break OUTER;
}
}
}

Then "goto OUTER;" or "goto INNER;" would not be permitted.

I like this the best. I think it's cleaner to have a separate syntax
for goto labels and loop labels.

[...]
 
S

Spiros Bousbouras

I like this the best. I think it's cleaner to have a separate syntax
for goto labels and loop labels.

Forgot to say that I don't think it would be hard to implement either.
 
E

Eric Sosman

Some questions are more useful if they are open ended.

Yah. But "Imagine something different. In what way would
it be inferior to what is?" isn't just open-ended, it's empty.
 
E

Eric Sosman

[...]
This has always been my proposal anyway. If the for/while/do/break
has a label, it can be referenced by a break/continue nested within
it. No backwards compatibility issues, no broken code…

This is how Java has chosen to do it. I think it works well for
continue, but not so well for (the far more common) break:

label: <--+
for (i = 0; i < N; ++i) { |
blah |
blah |
blah |
while (whatever) { |
blah |
blah |
blah |
if (astonished) |
break label; |
blah |
blah |
blah |
} |
blah |
blah |
blah |
} |
// <-- THIS is where the break takes us, but the label is --+

"How do I get to East Vasilboro?"
"Do you know the road that goes by the hardware store?"
"Sure! It's *that* way, right?"
"Right. Don't take that road."
 
R

robertwessel2

Perhaps not cleaner, just more explicit. The problem with explicit is
sometimes you want to conflate the names.

        outer:for() { if (x) continue outer; else goto outer; }

If you couldn't conflate, you end up with

        restart:
        outer:for() { if (x) continue outer; else goto restart; }

I'm not sure that's cleaner. Sometimes clean means putting disparate things
into a single box. If someone is interested in the box, they can
investigate. Otherwise, using a single box for every little item is just
clutter.


Labels, and things referring to them (gotos or the hypothetical break/
continue extensions), should be used sparingly anyway, so such cases
should be relatively rare. That being said, I don't thing either of
your examples is particularly unclear.
 
T

Thomas Richter

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i< n; i++)
for (int j = i; i< n; j++)
if (A[j] == target)
break outer;


Sorry, but I don't see the benefit of this. After all, there *is*
already a statement in the C language that does exactly that. It is
called "goto", and it solves exactly this situation.

So long,
Thomas
 
B

Ben Bacarisse

Thomas Richter said:
The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i< n; i++)
for (int j = i; i< n; j++)
if (A[j] == target)
break outer;


[This example is useless, of course. Rather than just type I should
not have made i and j local to the loops.]
Sorry, but I don't see the benefit of this. After all, there *is*
already a statement in the C language that does exactly that. It is
called "goto", and it solves exactly this situation.

It doesn't solve *exactly* this problem -- at least not in exactly the
same way. A jump to a label just outside the loop is slightly more
fragile in that you won't be told if you jump to the wrong label or if
the label gets moved so that it is no longer just after a loop. These
are not big issues, but then neither is (I imagine) the cost of
implementing a labeled break and continue.

There are also a couple minor syntactic advantages: you can't label a
closing brace so you will sometimes have to write 'label:;}' which is
slightly ugly and, in the unlikely event that you want to both continue
and to break a loop, you will need two labels:

cont_outer:;
}
break_outer:;

I don't count any of these to be powerfully strong advantages, but they
have to be weighed against what is probably a minor cost.
 
K

Keith Thompson

Thomas Richter said:
The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i< n; i++)
for (int j = i; i< n; j++)
if (A[j] == target)
break outer;


Sorry, but I don't see the benefit of this. After all, there *is*
already a statement in the C language that does exactly that. It is
called "goto", and it solves exactly this situation.


Considered harmful.

The current break and continue statements can also be replaced
by goto. For that matter, all control statements can be replaced
by goto and if.
 
L

lawrence.jones

Spiros Bousbouras said:
Not at all , I was merely expressing surprise that they made the bold
change despite lack of prior art but not the relatively timid change
which they justified on the basis of insufficient prior art.

The Rationale is not entirely complete. There was a clear need for a
generic pointer type, particularly with the more stringent type checking
that function prototypes provide, whereas there was already a perefectly
acceptable way to break or continue nested loops using goto.
 
K

Keith Thompson

Sherm Pendley said:
Keith Thompson said:
Thomas Richter said:
On 22.03.2011 22:40, Ben Bacarisse wrote:

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:

outer: for (int i = 0; i< n; i++)
for (int j = i; i< n; j++)
if (A[j] == target)
break outer;

Sorry, but I don't see the benefit of this. After all, there *is*
already a statement in the C language that does exactly that. It is
called "goto", and it solves exactly this situation.


Considered harmful.


Any tool can be harmful when misused. The solution for that is to avoid
misusing the tool, not to throw it away.


I don't suggest throwing away the tool (i.e., removing goto from
the language). My point is that the existence of a tool (goto)
that can be used to implement multi-level break is not a strong
argument against introducing a new (and IMHO better) tool for the
same purpose.

If you were designing a C-like language from scratch, would you
provide a single-level break but not a multi-level break? If so,
why is the former good and the latter bad? The "just use goto
(carefully)" argument applies equally to both.
 
S

Spiros Bousbouras

Yah. But "Imagine something different. In what way would
it be inferior to what is?" isn't just open-ended, it's empty.

You can lead a horse to water but you can't climb a ladder holding a
bell in each hand.
 

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

Forum statistics

Threads
474,091
Messages
2,570,604
Members
47,224
Latest member
Gwen068088

Latest Threads

Top