Discussion:
If statement with initializer
(too old to reply)
Thiago Adams
2017-05-10 13:29:33 UTC
Permalink
C++ 17, has now a new if.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html

if ( for-init-statement condition ) statement

is equivalent to

{
for-init-statement
if ( condition ) statement
}

and

if ( for-init-statement condition ) statement else statement

is equivalent to

{
for-init-statement
if ( condition ) statement else statement
}

Would you like to see this if on C?
David Brown
2017-05-10 13:42:22 UTC
Permalink
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
and
if ( for-init-statement condition ) statement else statement
is equivalent to
{
for-init-statement
if ( condition ) statement else statement
}
Would you like to see this if on C?
I would rather see it in a manner that does not need the extra clause -
or at least, the extra clause should be optional.

In C++17, you can now write:

if (bool b = foo(); b) ...

as equivalent to:

{
bool b = foo();
if (b) ...
}

(Note the critical extra set of brackets.)

I think it would have been much nice if it had been simply:

if (bool b = foo()) ...


I would not mind if this came to C, but I think it is unlikely. The
change is useful in C++ because you sometimes want precise control of
when a variable goes out of scope and lifetime, and therefore gets
destroyed. In C, nothing special happens when a local variable goes out
of scope, so it matters little if its scope and lifetime is extended.
At most, it would be a syntactic convenience allowing you to re-use the
same identifier without using new sets of brackets.
Ben Bacarisse
2017-05-10 14:36:25 UTC
Permalink
David Brown <***@hesbynett.no> writes:
<snip>
Post by David Brown
Post by Thiago Adams
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
<snip>
Post by David Brown
Post by Thiago Adams
Would you like to see this if on C?
I would rather see it in a manner that does not need the extra clause -
or at least, the extra clause should be optional.
if (bool b = foo(); b) ...
{
bool b = foo();
if (b) ...
}
(Note the critical extra set of brackets.)
if (bool b = foo()) ...
But that would not serve all the intended purposes:

if (int n = expensive(); 2 < x && x < 17) ...
--
Ben.
David Brown
2017-05-10 15:23:41 UTC
Permalink
Post by Ben Bacarisse
<snip>
Post by David Brown
Post by Thiago Adams
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
<snip>
Post by David Brown
Post by Thiago Adams
Would you like to see this if on C?
I would rather see it in a manner that does not need the extra clause -
or at least, the extra clause should be optional.
if (bool b = foo(); b) ...
{
bool b = foo();
if (b) ...
}
(Note the critical extra set of brackets.)
if (bool b = foo()) ...
if (int n = expensive(); 2 < x && x < 17) ...
I assume you meant to write "if (int x = expensive(); 2 < x && x < 17)".

And in C++, you might well have a class object in the initialiser and
want to apply a method to it.

Yes, the second clause is sometimes needed - but often it is not, and I
think it would be nice if it were optional.
Ben Bacarisse
2017-05-10 15:40:37 UTC
Permalink
David Brown <***@hesbynett.no> writes:
<snip>
Post by David Brown
Yes, the second clause is sometimes needed - but often it is not, and I
think it would be nice if it were optional.
I misunderstood. I thought you didn't want it at all. Sorry.
--
Ben.
David Brown
2017-05-10 20:22:29 UTC
Permalink
Post by Ben Bacarisse
<snip>
Post by David Brown
Yes, the second clause is sometimes needed - but often it is not, and I
think it would be nice if it were optional.
I misunderstood. I thought you didn't want it at all. Sorry.
I would rather see it in a manner that does not need the extra clause -
or at least, the extra clause should be optional.
So I expressed myself rather badly there.

You have to listen to what I /mean/, not what I /say/ :-)
Thiago Adams
2017-05-10 13:44:02 UTC
Permalink
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Post by Thiago Adams
Would you like to see this if on C?
(switch also receive this upgrade)

Adding more ...

C++ 17 also have news on preprocessor.

__has_include

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0061r0.html

And a new assert with no message

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3928.pdf

static_assert ( constant-expression ) ;

One more:

Deprecate ++ on bool. (this could be applied to _Bool)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0002r1.html


Would you like to see these features on C?
David Brown
2017-05-10 14:38:41 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Post by Thiago Adams
Would you like to see this if on C?
(switch also receive this upgrade)
Adding more ...
C++ 17 also have news on preprocessor.
__has_include
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0061r0.html
Personally, I have no use for that. If I want to include a file, I do -
I don't have use-cases myself for files that might or might not be
available. If other people see it as a useful feature, that's fine.
Post by Thiago Adams
And a new assert with no message
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3928.pdf
static_assert ( constant-expression ) ;
That makes a lot of sense to me, and is a feature I would use.
Sometimes I want my static assertions to have explicit messages, but
more often it would be neater and shorter to have a simple failure message.
Post by Thiago Adams
Deprecate ++ on bool. (this could be applied to _Bool)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0002r1.html
I can't see any use for incrementing bool's (nor for many other
operators). So I see no problem in deprecating bool ++. However, other
people might have written code that uses it, and changes to C need to be
very conservative about breaking something that worked before.
Post by Thiago Adams
Would you like to see these features on C?
GOTHIER Nathan
2017-05-10 14:22:15 UTC
Permalink
On Wed, 10 May 2017 06:29:33 -0700 (PDT)
Post by Thiago Adams
Would you like to see this if on C?
No because C shouldn't deserve to be as bloated as C++. Once more Bjarne
STROUSTRUP has soiled the C name with his counterfeit language that should have
been named the STROUSTRUP language instead of C++ to trick new programmers with
bad concepts.
Thiago Adams
2017-05-10 14:29:57 UTC
Permalink
Post by GOTHIER Nathan
On Wed, 10 May 2017 06:29:33 -0700 (PDT)
Post by Thiago Adams
Would you like to see this if on C?
No because C shouldn't deserve to be as bloated as C++. Once more Bjarne
STROUSTRUP has soiled the C name with his counterfeit language that should have
been named the STROUSTRUP language instead of C++ to trick new programmers with
bad concepts.
Probably you are against the previous insertions at C as well, like _Staticassert and _Bool.
Am I right?
The language become bigger after that.
GOTHIER Nathan
2017-05-10 15:40:16 UTC
Permalink
On Wed, 10 May 2017 07:29:57 -0700 (PDT)
Post by Thiago Adams
Probably you are against the previous insertions at C as well, like _Staticassert and _Bool.
Am I right?
The language become bigger after that.
It is not a matter of size but conciseness.

That's why some programmers prefer C to the STROUSTRUP language.

Stacking flawed concepts doesn't make a good language. Likewise the nouveauté
is not synonym of efficiency and at some point the programmer have to use his
neurons to write good softwares.
s***@casperkitty.com
2017-05-10 15:48:54 UTC
Permalink
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
Would you like to see this if on C?
What would be the effect of:

typedef struct { int x; } foo;

extern void actOnFoo(foo *p);
extern void someFunction(void);

void test()
{
foo *p;
p = (foo*){1};
if (int temp = someFunction())
p = (foo*){temp};
actOnFoo(p);
}

If "temp" had been declared prior to the "if" within the outer scoping block,
the lifetime of the compound literal within the "if" statement would extend
to the end of the function. Adding a scoping block to contain "temp" would
limit the lifetime of the compound literal to that of "temp".

Personally, I think the lifetime rules for compound literals are silly, and
the lifetime should extend either until code exits the *function* wherein a
literal is defined or execution re-reaches the point where it is created
(whereupon the lifetime of the original would end, and that of a new compound
literal would begin), but with the rules as they are anything that would
implicitly add a new scoping block should be considered dangerous.
David Brown
2017-05-10 20:24:51 UTC
Permalink
Post by s***@casperkitty.com
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
Would you like to see this if on C?
typedef struct { int x; } foo;
extern void actOnFoo(foo *p);
extern void someFunction(void);
void test()
{
foo *p;
p = (foo*){1};
if (int temp = someFunction())
p = (foo*){temp};
actOnFoo(p);
}
What effect are you looking for? A compiler error? A failed code review?
s***@casperkitty.com
2017-05-10 20:29:51 UTC
Permalink
Post by David Brown
Post by s***@casperkitty.com
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
Would you like to see this if on C?
typedef struct { int x; } foo;
extern void actOnFoo(foo *p);
extern void someFunction(void);
void test()
{
foo *p;
p = &(foo){1};
if (int temp = someFunction())
p = &(foo){temp};
actOnFoo(p);
}
What effect are you looking for? A compiler error? A failed code review?
I slightly oopsed the syntax [hopefully corrected above]--basically the
question is whether declaring a variable within an "if" condition would
shorten the lifetime of a compound literal object used within the
controlled statement, so it ends at the end of the controlled statement
rather than at the end of the enclosing block.
David Brown
2017-05-10 21:27:39 UTC
Permalink
Post by s***@casperkitty.com
Post by David Brown
Post by s***@casperkitty.com
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
Would you like to see this if on C?
typedef struct { int x; } foo;
extern void actOnFoo(foo *p);
extern void someFunction(void);
void test()
{
foo *p;
p = &(foo){1};
if (int temp = someFunction())
p = &(foo){temp};
actOnFoo(p);
}
What effect are you looking for? A compiler error? A failed code review?
I slightly oopsed the syntax [hopefully corrected above]--basically the
(Please do not change quoted parts of a post - it makes it very hard to
follow. And you are still assigning the result of a void function to an
int.)
Post by s***@casperkitty.com
question is whether declaring a variable within an "if" condition would
shorten the lifetime of a compound literal object used within the
controlled statement, so it ends at the end of the controlled statement
rather than at the end of the enclosing block.
I believe the "if" statement now makes a new block - it acts as though
it were surrounded by brackets.
Thiago Adams
2017-05-10 16:40:20 UTC
Permalink
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
and
if ( for-init-statement condition ) statement else statement
is equivalent to
{
for-init-statement
if ( condition ) statement else statement
}
Would you like to see this if on C?
These samples look good for me:


if (Box* pBox = Shape_As_Box(pShape), pBox)
{
//pBox ...
}


if (FILE* file = fopen(""), file)
{
//file...
fclose(file);
}

if (Type* p = malloc(sizeof * p), p)
{
}
Ben Bacarisse
2017-05-10 18:15:49 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
<snip>
Post by Thiago Adams
Post by Thiago Adams
Would you like to see this if on C?
if (Box* pBox = Shape_As_Box(pShape), pBox)
{
//pBox ...
}
Are deliberately making it different to the C++ form or was the comma a
typo?

<snip>
--
Ben.
Thiago Adams
2017-05-10 18:22:53 UTC
Permalink
Post by Ben Bacarisse
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
<snip>
Post by Thiago Adams
Post by Thiago Adams
Would you like to see this if on C?
if (Box* pBox = Shape_As_Box(pShape), pBox)
{
//pBox ...
}
Are deliberately making it different to the C++ form or was the comma a
typo?
The comma was my mistake.
bartc
2017-05-10 17:06:30 UTC
Permalink
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
and
if ( for-init-statement condition ) statement else statement
is equivalent to
{
for-init-statement
if ( condition ) statement else statement
}
Would you like to see this if on C?
Not me. I prefer declarations all tucked away in a corner so they don't
clutter up the code.

People complain about Hungarian notation but this doesn't seem much
different.

Besides, this can be done now with {} either surrounding the if
statement (assuming the scope extends to the end of the second
statement), or inside the condition using the gcc extension.
--
bartc
Ben Bacarisse
2017-05-10 18:19:59 UTC
Permalink
Post by bartc
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
and
if ( for-init-statement condition ) statement else statement
is equivalent to
{
for-init-statement
if ( condition ) statement else statement
}
Would you like to see this if on C?
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.

<snip>
--
Ben.
bartc
2017-05-10 19:19:28 UTC
Permalink
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it might
have been declared somewhere in between.

Here's one example: https://pastebin.com/iVtbFN2U where most names are
declared at the start, but some are defined in situ which means you
can't just immediately go to the top and see a cast list of all the names.

Here's another example: https://pastebin.com/v4h6Aabx where nothing is
declared at the top other than parameter names.

And it uses one of those styles where variable names all tend to look
alike. But some of them are actually identical, which you don't know
until you've scanned the entire function (there are two zWhere's for
example, fortunately of the same type).
--
bartc
Thiago Adams
2017-05-10 20:21:02 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it might
have been declared somewhere in between.
Do you mean
int i;
if ()
{
int i; //like this ??
}
Ben Bacarisse
2017-05-10 21:16:55 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it
might have been declared somewhere in between.
When you just put all the declarations at the top of a function you have
to check every line for occurrences of every variable (if you are doing
any sort of semi-formal reasoning about your code), but both this and
your remark, whist being genuine problems with each approach, are
largely trivial in that there are simple tools to help in both cases.

It's hard to put into words why I find it so very much more comfortable
to do it my way. I suspect a lot of it comes down to the fact that we
think about code in very different ways, but here are a few thoughts
that come to mind:

Smaller scope tend to reduce the use of either indeterminate objects
or objects initialised with meaningless "place-holder" values.

They localise changes. If I alter the upper bound (or otherwise alter
the exit) of

for (int i = lo; i < f(lo); i++) result = g(i, result);

I know I can't be messing with any code that has assumed that i == f(lo)
below the loop.

This is most problematic when multiple people edit the code. With i
declared "up top" they may assume the value after the loop is deliberate
assured.

In effect you are able to write inline functions with some of the
encapsulation benefits the functions give you, without the limitations
of C's functions.
Post by bartc
Here's one example: https://pastebin.com/iVtbFN2U where most names are
declared at the start, but some are defined in situ which means you
can't just immediately go to the top and see a cast list of all the names.
Here's another example: https://pastebin.com/v4h6Aabx where nothing is
declared at the top other than parameter names.
And it uses one of those styles where variable names all tend to look
alike. But some of them are actually identical, which you don't know
until you've scanned the entire function (there are two zWhere's for
example, fortunately of the same type).
I don't know what I am to take form these examples.
--
Ben.
David Brown
2017-05-10 21:31:25 UTC
Permalink
Post by Ben Bacarisse
Post by bartc
Here's one example: https://pastebin.com/iVtbFN2U where most names are
declared at the start, but some are defined in situ which means you
can't just immediately go to the top and see a cast list of all the names.
Here's another example: https://pastebin.com/v4h6Aabx where nothing is
declared at the top other than parameter names.
And it uses one of those styles where variable names all tend to look
alike. But some of them are actually identical, which you don't know
until you've scanned the entire function (there are two zWhere's for
example, fortunately of the same type).
I don't know what I am to take form these examples.
As the saying in Norwegian goes, you are supposed to choose between the
plague or cholera.
bartc
2017-05-10 21:50:29 UTC
Permalink
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it
might have been declared somewhere in between.
When you just put all the declarations at the top of a function you have
to check every line for occurrences of every variable (if you are doing
any sort of semi-formal reasoning about your code), but both this and
your remark, whist being genuine problems with each approach, are
largely trivial in that there are simple tools to help in both cases.
I don't want to have to use tools just to understand code. (Otherwise
what's the point of a language having syntax? Just use some internal
format for source code, and rely on a tool for rendering in a syntax and
style of your choice.)
Post by Ben Bacarisse
It's hard to put into words why I find it so very much more comfortable
to do it my way. I suspect a lot of it comes down to the fact that we
think about code in very different ways, but here are a few thoughts
Smaller scope tend to reduce the use of either indeterminate objects
or objects initialised with meaningless "place-holder" values.
What happened to all the people telling us to keep functions to ten
lines or less? Then having multiple scopes within such a span would be
ludicrous.
Post by Ben Bacarisse
They localise changes. If I alter the upper bound (or otherwise alter
the exit) of
for (int i = lo; i < f(lo); i++) result = g(i, result);
I know I can't be messing with any code that has assumed that i == f(lo)
below the loop.
That's probably the only example where a localised loop index name can
make sense. In fact, here such a local index name is desirable, so you
don't even want to bother declaring it. [Not practical in C as there is
no official concept of a loop index variable]
Post by Ben Bacarisse
In effect you are able to write inline functions with some of the
encapsulation benefits the functions give you, without the limitations
of C's functions.
I don't get that. The local names in any function are already
encapsulated; it doesn't need further nested scopes, and it doesn't
matter if the function is inlined or not, as the local names will never
clash with any names at the call-site where it might be inlined.
Post by Ben Bacarisse
Post by bartc
Here's one example: https://pastebin.com/iVtbFN2U where most names are
Here's another example: https://pastebin.com/v4h6Aabx where nothing is
I don't know what I am to take form these examples.
It shows the practical problems of looking at a line of code and trying
to locate the corresponding declarations. When the declarations can be
anywhere within a function, and the same variable name is overloaded.
--
bartc
Ben Bacarisse
2017-05-11 00:15:59 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it
might have been declared somewhere in between.
When you just put all the declarations at the top of a function you have
to check every line for occurrences of every variable (if you are doing
any sort of semi-formal reasoning about your code), but both this and
your remark, whist being genuine problems with each approach, are
largely trivial in that there are simple tools to help in both cases.
I don't want to have to use tools just to understand code.
That's up to you but then you don't get any tools to help you see when
in this 300-line function i is mentioned. Both strategies have
Post by bartc
(Otherwise what's the point of a language having syntax? Just use some
internal format for source code, and rely on a tool for rendering in a
syntax and style of your choice.)
Post by Ben Bacarisse
It's hard to put into words why I find it so very much more comfortable
to do it my way. I suspect a lot of it comes down to the fact that we
think about code in very different ways, but here are a few thoughts
Smaller scope tend to reduce the use of either indeterminate objects
or objects initialised with meaningless "place-holder" values.
What happened to all the people telling us to keep functions to ten
lines or less? Then having multiple scopes within such a span would be
ludicrous.
Oh, sure. If your functions are small your scopes are small and then
every is happy, yes? I want small scopes not some particular for-loop
syntax. It's not always easy in C, because functions don't nest, but
where you can do it, it's the perfect strategy to get small scopes.

And you get the added advantage that you can have declarations anywhere
you like because, in a ten line function, you in your tool-less state
will still be able to find a declaration. In effect the issue
evaporates in languages where tiny functions are the norm.
Post by bartc
Post by Ben Bacarisse
They localise changes. If I alter the upper bound (or otherwise alter
the exit) of
for (int i = lo; i < f(lo); i++) result = g(i, result);
I know I can't be messing with any code that has assumed that i == f(lo)
below the loop.
That's probably the only example where a localised loop index name can
make sense. In fact, here such a local index name is desirable, so you
don't even want to bother declaring it. [Not practical in C as there
is no official concept of a loop index variable]
Obviously I disagree about this being the only case, but at least
there's one thing we do agree on. In fact two things: very short
functions and local for-loop declarations.

<snip>
Post by bartc
It shows the practical problems of looking at a line of code and
trying to locate the corresponding declarations. When the declarations
can be anywhere within a function, and the same variable name is
overloaded.
Sure. And they both illustrate the other problem of knowing where code
is making what assumptions about the values in these quasi-global
variables.
--
Ben.
bartc
2017-05-11 13:15:24 UTC
Permalink
Post by Ben Bacarisse
Post by bartc
What happened to all the people telling us to keep functions to ten
lines or less? Then having multiple scopes within such a span would be
ludicrous.
Oh, sure. If your functions are small your scopes are small and then
every is happy, yes? I want small scopes not some particular for-loop
syntax. It's not always easy in C, because functions don't nest, but
where you can do it, it's the perfect strategy to get small scopes.
And you get the added advantage that you can have declarations anywhere
you like because, in a ten line function, you in your tool-less state
will still be able to find a declaration. In effect the issue
evaporates in languages where tiny functions are the norm.
Then you will need special tools to find where all the functions are!

(Actually, my own language has nested functions (which I've never used),
partly through not bothering to prohibit them.

And it not only allows declarations anywhere (again by not enforcing a
boundary between them and statements), but they can be out-of-order. So
you could declare all your local variables at the end of a function if
you want!

[Not practical in C as it would require an extra pass, which I need
anyway to allow out-of-order functions and to eliminate forward
declarations of functions.]

However, it doesn't suffer so much from the same issues as C, as there
are no block-scopes, and any local name can only be declared once. So
once you've found the declaration, you can stop looking.

Furthermore, as code develops and blocks are added and removed, or a
name starts being used before its declaration, it's not necessary to
keep re-locating declarations to ensure a name is always declared before
use. [In C, a name might inadvertently be resolved to a more global one
if its declaration occurs later.])
--
bartc
s***@casperkitty.com
2017-05-11 15:17:08 UTC
Permalink
Post by bartc
And it not only allows declarations anywhere (again by not enforcing a
boundary between them and statements), but they can be out-of-order. So
you could declare all your local variables at the end of a function if
you want!
A lot of programs have a usage pattern that, for accurate description, would
require more control over scope/lifetime than C supports. For example, in
something like:

double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
double distance = sqrt(dx*dx+dy*dy);
double angle = atan2(dy,dx);

If code only needs to use dx and dy in the second line above, and nowhere
else, it would be helpful to be able to end their scope immediately after
it, but if scoping braces were used to end the scope of dx and dy they
would also end the scope of distance. Aside from the chicken-and-egg
problems of allowing programmers to use a new syntax without limiting the
range of tools they can use, perhaps it might be helpful to add an
"extern auto" qualifier which would cause an object declaration to take
effect in the enclosing scope, thus allowing:

{
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
extern auto double distance = sqrt(dx*dx+dy*dy);
extern auto double angle = atan2(dy,dx);
}

to create variables for use in the enclosing scope. An additional helpful
feature would be to say that an "extern auto" declaration without an
initialization would pass an already-declared block-local variable (which
might have been exported from an inner block) to the enclosing scope.

Most of the places where I've seen objects get declared mid-block would be
better accommodated by adding additional scoping blocks, if there were a
way to export variables from within them.
bartc
2017-05-11 18:00:06 UTC
Permalink
Post by s***@casperkitty.com
Post by bartc
And it not only allows declarations anywhere (again by not enforcing a
boundary between them and statements), but they can be out-of-order. So
you could declare all your local variables at the end of a function if
you want!
A lot of programs have a usage pattern that, for accurate description, would
require more control over scope/lifetime than C supports. For example, in
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
double distance = sqrt(dx*dx+dy*dy);
double angle = atan2(dy,dx);
If code only needs to use dx and dy in the second line above, and nowhere
else, it would be helpful to be able to end their scope immediately after
it,
Why? If they really are used nowhere else, then a smart compiler will
know that.

This doesn't seem to happen anywhere else, as at file-scope for example:
you declare functions g() and h() which are only used by f(); but g()
and h() stay available for the rest of the file.

I think there are already enough possibilities for scope inside
functions (so an infinite number of versions of the same identifier can
be used, and if that's not enough, you can use upper/lower case variations).

Outside a function, there are fewer possibilities: namely one for each
identifier. Despite the span of code being far bigger (an entire module
for local names, the entire program for global ones).

So it's unbalanced; we don't need even finer divisions of the namespace
inside a function or a block!
--
bartc
s***@casperkitty.com
2017-05-11 18:49:28 UTC
Permalink
Post by bartc
Post by s***@casperkitty.com
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
double distance = sqrt(dx*dx+dy*dy);
double angle = atan2(dy,dx);
If code only needs to use dx and dy in the second line above, and nowhere
else, it would be helpful to be able to end their scope immediately after
it,
Why? If they really are used nowhere else, then a smart compiler will
know that.
Sure the compiler will know it, but if code needs to use similar temporary
variables more than once, it will be necessary to either change the second
usage from a declaration to an assignment, add a standalone declaration and
change both usages to assignment, or tweak the second usage to use different
names from the first. By contrast, if the scopes were limited, then such
issues would be avoided.

In cases involving pointers, limiting variable scope would have other
advantages as well. Consider:

rectangle *rp = &someObject->bounds;
double objectX = (rp->left+rp->right) / 2;
double objectX = (rp->top+rp->bottom) / 2;
...
someObject = realloc(someObject, newSize);
if (!someObject) fatal_error();
...

Code like the above would leave a dangling pointer in scope. If rp
isn't going to be used after the computations of objectX and objectY,
the fact that it's left dangling after the realloc() would course be
no big deal, but if it rp is going to be used later on, it would be
necessary to reload it with &someObject->bounds. Expressly limiting
the scope would make it clear to anyone reading the code that there
was no dangling pointer "rp" since there would be no pointer "rp".
Post by bartc
I think there are already enough possibilities for scope inside
functions (so an infinite number of versions of the same identifier can
be used, and if that's not enough, you can use upper/lower case variations).
Those don't help if the *purpose* of a temporary variable is to set the
initialization value for something else, since ending the scope of the
temporaries would imply ending the scope of anything initialized therewith.
bartc
2017-05-11 19:51:05 UTC
Permalink
Post by s***@casperkitty.com
Post by bartc
Post by s***@casperkitty.com
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
double distance = sqrt(dx*dx+dy*dy);
double angle = atan2(dy,dx);
If code only needs to use dx and dy in the second line above, and nowhere
else, it would be helpful to be able to end their scope immediately after
it,
Why? If they really are used nowhere else, then a smart compiler will
know that.
Sure the compiler will know it, but if code needs to use similar temporary
variables more than once, it will be necessary to either change the second
usage from a declaration to an assignment, add a standalone declaration and
change both usages to assignment, or tweak the second usage to use different
names from the first. By contrast, if the scopes were limited, then such
issues would be avoided.
In cases involving pointers, limiting variable scope would have other
rectangle *rp = &someObject->bounds;
double objectX = (rp->left+rp->right) / 2;
double objectX = (rp->top+rp->bottom) / 2;
...
someObject = realloc(someObject, newSize);
if (!someObject) fatal_error();
...
Code like the above would leave a dangling pointer in scope. If rp
isn't going to be used after the computations of objectX and objectY,
the fact that it's left dangling after the realloc() would course be
no big deal, but if it rp is going to be used later on, it would be
necessary to reload it with &someObject->bounds.
This is general problem with using pointers in C programs.

When you have, say, a large tree full of pointers to elements of a
dynamic array, and you resize the array resulting in a new base address,
then all the thousands of pointers will be out of date.

By contrast, all non-static variables in functions should be considered
to be temporary working variables. Maybe you will detect the odd bug by
using the minimal possible scope envelope for each, but it's more likely
to make more work trying to program with and around such practices.
Lifetimes won't be in nice nested scopes but will overlap.


(This sounds a bit like the strict hierarchical import system on one of
my languages. It's hard to structure things to avoid mutual/circular
imports, and it restricts compilation order.

The next compiler will drop restrictions and life much easier.)
Post by s***@casperkitty.com
Post by bartc
I think there are already enough possibilities for scope inside
functions (so an infinite number of versions of the same identifier can
be used, and if that's not enough, you can use upper/lower case variations).
Those don't help if the *purpose* of a temporary variable is to set the
initialization value for something else, since ending the scope of the
temporaries would imply ending the scope of anything initialized therewith.
How about a special temporary variable, perhaps starting with "$", that
can only be used once? Your examples use them twice, meaning two
variables to replace rp for example. However source then starts to look
some compiler's intermediate code. HLLs are supposed to make life
simpler and take care of such details.
--
bartc
Ian Collins
2017-05-12 08:02:00 UTC
Permalink
Post by s***@casperkitty.com
Post by bartc
Post by s***@casperkitty.com
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
double distance = sqrt(dx*dx+dy*dy);
double angle = atan2(dy,dx);
If code only needs to use dx and dy in the second line above, and nowhere
else, it would be helpful to be able to end their scope immediately after
it,
Why? If they really are used nowhere else, then a smart compiler will
know that.
Sure the compiler will know it, but if code needs to use similar temporary
variables more than once, it will be necessary to either change the second
usage from a declaration to an assignment, add a standalone declaration and
change both usages to assignment, or tweak the second usage to use different
names from the first. By contrast, if the scopes were limited, then such
issues would be avoided.
If the function were a sensible length, such issues would be avoided.
--
Ian
Robert Wessel
2017-05-12 07:01:02 UTC
Permalink
Post by bartc
Post by s***@casperkitty.com
Post by bartc
And it not only allows declarations anywhere (again by not enforcing a
boundary between them and statements), but they can be out-of-order. So
you could declare all your local variables at the end of a function if
you want!
A lot of programs have a usage pattern that, for accurate description, would
require more control over scope/lifetime than C supports. For example, in
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
double distance = sqrt(dx*dx+dy*dy);
double angle = atan2(dy,dx);
If code only needs to use dx and dy in the second line above, and nowhere
else, it would be helpful to be able to end their scope immediately after
it,
Why? If they really are used nowhere else, then a smart compiler will
know that.
you declare functions g() and h() which are only used by f(); but g()
and h() stay available for the rest of the file.
I think there are already enough possibilities for scope inside
functions (so an infinite number of versions of the same identifier can
be used, and if that's not enough, you can use upper/lower case variations).
Outside a function, there are fewer possibilities: namely one for each
identifier. Despite the span of code being far bigger (an entire module
for local names, the entire program for global ones).
C++ classes provide an excellent intermediate scope for items. If
there were a major feature of C++ I'd want in C, it would be classes
(not inherence, overloading, templates...).
Post by bartc
So it's unbalanced; we don't need even finer divisions of the namespace
inside a function or a block!
This is really a bit of a tempest in a teapot. Smaller scopes within
a function is neither complicated for a compiler to implement, nor for
the programmer to understand. On the flip side, with reasonably sized
functions, the smaller scope only offers small advantages. OTOH, if
you have functions big enough that you *need* to reduce the scope of
variables, it's probably time to consider making them smaller.
David Brown
2017-05-12 10:16:40 UTC
Permalink
Post by s***@casperkitty.com
Post by bartc
And it not only allows declarations anywhere (again by not enforcing a
boundary between them and statements), but they can be out-of-order. So
you could declare all your local variables at the end of a function if
you want!
A lot of programs have a usage pattern that, for accurate description, would
require more control over scope/lifetime than C supports. For example, in
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
double distance = sqrt(dx*dx+dy*dy);
double angle = atan2(dy,dx);
If code only needs to use dx and dy in the second line above, and nowhere
else, it would be helpful to be able to end their scope immediately after
it, but if scoping braces were used to end the scope of dx and dy they
would also end the scope of distance. Aside from the chicken-and-egg
problems of allowing programmers to use a new syntax without limiting the
range of tools they can use, perhaps it might be helpful to add an
"extern auto" qualifier which would cause an object declaration to take
{
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
extern auto double distance = sqrt(dx*dx+dy*dy);
extern auto double angle = atan2(dy,dx);
}
to create variables for use in the enclosing scope. An additional helpful
feature would be to say that an "extern auto" declaration without an
initialization would pass an already-declared block-local variable (which
might have been exported from an inner block) to the enclosing scope.
Most of the places where I've seen objects get declared mid-block would be
better accommodated by adding additional scoping blocks, if there were a
way to export variables from within them.
I have occasionally thought it would be nice to do something like that.
I much prefer to define and initialise my variables where possible, and
not to define them until I have something useful to put in them. With
your syntax, this sequence:

bool valid = false;
double result;
if (x >= 0) {
result = sqrt(x);
valid = true;
}
if (valid) printf("%f\n", result);

could become:

bool valid = false;
if (x >= 0) {
extern auto double result = sqrt(x);
valid = true;
}
if (valid) printf("%f\n", result);

Still, I think the use of something like this, the small advantage it
gives, would not come close to outweighing the confusion the concept
would cause, the conflicts with C++ syntax, and the ugly syntax.


If I were to change something here, it would be to allow a new
definition within the same local scope to end the previous scope:

int a = f();
int b = g(a);
int a = h(b);

The first "a" would end its scope when the new "a" begins, and can have
a different type or the same type.

You could perhaps also end a scope early by making a new identifier of
type "void":

int a = 1;
{
int a = 2;
void a;
int b = a; // Gets 1 from the outside "a"
}

One problem about this is if you have:

int a = f();
int a = g(&a);

Should the address passed refer to the old "a" which would would exist
up until the assignment, or should it refer to the new "a" which would
exist from the second "int a" declaration?
bartc
2017-05-12 10:49:54 UTC
Permalink
Post by David Brown
Post by s***@casperkitty.com
{
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
extern auto double distance = sqrt(dx*dx+dy*dy);
extern auto double angle = atan2(dy,dx);
}
bool valid = false;
double result;
if (x >= 0) {
result = sqrt(x);
valid = true;
}
if (valid) printf("%f\n", result);
bool valid = false;
if (x >= 0) {
extern auto double result = sqrt(x);
valid = true;
}
if (valid) printf("%f\n", result);
Still, I think the use of something like this, the small advantage it
gives,
There's no advantage (from the point of view of someone reading the
code). It replaces two straightforward lines with one complicated one.
And the scope rules seem obscure.
Post by David Brown
If I were to change something here, it would be to allow a new
int a = f();
int b = g(a);
int a = h(b);
The first "a" would end its scope when the new "a" begins, and can have
a different type or the same type.
That's great. So instead of only having two possible instances of a name
"A" within a block (not counting struct tag versions and labels), we can
now have an unlimited number!
Post by David Brown
You could perhaps also end a scope early by making a new identifier of
int a = 1;
{
int a = 2;
void a;
int b = a; // Gets 1 from the outside "a"
}
OK, now we're getting there. We need a way of defining a name whose
scope is unbounded by any } (until it gets to the end of the function),
and is terminated at any arbitrary place by an explicit command such as
this.

So:

int A; // A1
{
int A; // A2
{ new int A; // A3, unbounded by }
}
A; // A3
end A; // ends A3, A2 now in scope
A; // A2
}
A; // A1

It would be absolutely chaotic!

Why this obsession with these tiny scopes? They are plenty of languages
with weird and wonderful ideas - no variables, no assignments, no
statements - so why inflict them on C?

(BTW here's how the above would look in any code I would write:

int A; // A1
{
{
}
A; // A1
A; // A1
}
A; // A1

Which one would simpler to understand (regarding which A is which) and
would be understood by a wider range of people?)
--
bartc
David Brown
2017-05-12 13:21:37 UTC
Permalink
Post by bartc
Post by David Brown
Post by s***@casperkitty.com
{
double dx=(x2-x1), dy=(y2-x1); // Used *only* in next two lines
extern auto double distance = sqrt(dx*dx+dy*dy);
extern auto double angle = atan2(dy,dx);
}
bool valid = false;
double result;
if (x >= 0) {
result = sqrt(x);
valid = true;
}
if (valid) printf("%f\n", result);
bool valid = false;
if (x >= 0) {
extern auto double result = sqrt(x);
valid = true;
}
if (valid) printf("%f\n", result);
Still, I think the use of something like this, the small advantage it
gives,
There's no advantage (from the point of view of someone reading the
code). It replaces two straightforward lines with one complicated one.
And the scope rules seem obscure.
You mean there is no advantage from /your/ point of view, and the scope
rules are obscure to /you/. We already know you have trouble with block
scopes, both with understanding how they work and why they are useful.
Clearly something extra on top of that is going to be worse for you.

The advantage is that it replaces the two actions "define a variable"
and "assign a value to the variable" with one action "define a variable
with a given initialisation". It also keeps the scope to a reasonable
minimum. A great many programmers think this is a good thing - I
believe you are an exception here with your conviction that declaring
everything at the start of a function is better.

And you snipped the rest of my comment "would not come close to
outweighing the confusion the concept would cause". I also think it
would make the code less clear.
Post by bartc
Post by David Brown
If I were to change something here, it would be to allow a new
int a = f();
int b = g(a);
int a = h(b);
The first "a" would end its scope when the new "a" begins, and can have
a different type or the same type.
That's great. So instead of only having two possible instances of a name
"A" within a block (not counting struct tag versions and labels), we can
now have an unlimited number!
Yes. It is not hard, but there are a few tricks you need to learn.

1. Keep your functions of a sensible size.
2. Use sensible names.
3. Learn to understand the difference between extreme examples, and
real-world code.
Post by bartc
Post by David Brown
You could perhaps also end a scope early by making a new identifier of
int a = 1;
{
int a = 2;
void a;
int b = a; // Gets 1 from the outside "a"
}
OK, now we're getting there. We need a way of defining a name whose
scope is unbounded by any } (until it gets to the end of the function),
and is terminated at any arbitrary place by an explicit command such as
this.
No, we don't. You are misunderstanding what I wrote - I was /not/
proposing an alternative syntax for Supercat's idea.
Post by bartc
int A; // A1
{
int A; // A2
{ new int A; // A3, unbounded by }
}
A; // A3
end A; // ends A3, A2 now in scope
A; // A2
}
A; // A1
It would be absolutely chaotic!
I don't know what you mean here, because you have completely
misunderstood what I wrote, and then added your own new keywords "new"
and "end".
Post by bartc
Why this obsession with these tiny scopes?
The obsession is with clear and easily understood code. If a variable
has a small scope, it is easy to see where it starts, what it does, and
where it ends. Writing large functions with big collections of variable
definitions at the start means you are jumping all over the function to
see what it does, or while writing it. It is even worse when your
language allows you to put the definition later on, after the variable
has been in use (as your language does, AFAIUI).


Look, in C you can declare variables inside a block, and their scope
exists from that point until the end of the block. You understand that,
right?

int a = 1;
if (a == 1) {
int a; // New a
int b; // Local b
a = 2; // The new a
foo(a); // a == 2 here
b = 3;
bar(a, b); // a == 2, b == 3
}
foobar(a); // Back to the old a == 1


And in C99, you can mix declarations and statements. This means you can
write:

int a = 1;
if (a == 1) {
int a = 2; // New a
foo(a); // a == 2 here
int b = 3; // Local b
bar(a, b); // a == 2, b == 3
}
foobar(a); // Back to the old a == 1

This is equivalent to:

int a = 1;
if (a == 1) {
int a; // New a
a = 2; // The new a
foo(a); // a == 2 here
{
int b; // Local b
b = 3;
bar(a, b); // a == 2, b == 3
} // end of scope for b
} // end of scope for "new" a
foobar(a); // Back to the old a == 1

Are you still following?

What I am suggesting is the ability to write:

int a = 1;
if (a == 1) {
int a = 2; // New a
foo(a); // a == 2 here
int b = 3; // Local b
// The scope for the new a (a == 2) ends here
int a = 4; // Yet another new a
bar(a, b); // a == 4, b == 3
}
foobar(a); // Back to the old a == 1

This would be equivalent to:

int a = 1;
if (a == 1) {
int a; // New a
a = 2; // The new a
foo(a); // a == 2 here
{
int b; // Local b
b = 3;
{
int a; // Yet another new a
a = 4; // The YAN a
bar(a, b); // a == 4, b == 3
} // end of scope for YAN a
} // end of scope for b
} // end of scope for "new" a
foobar(a); // Back to the old a == 1


Is that clear enough?
Post by bartc
They are plenty of languages
with weird and wonderful ideas - no variables, no assignments, no
statements - so why inflict them on C?
There are indeed plenty of languages with weird and wonderful ideas. I
don't know of any language that has /this/ particular idea, but it might
exist somewhere.

And note that this is all about /additions/ to C - I can't see why you
think anyone is trying to /remove/ something from it. Yes, there are
languages without variables, assignments or statements (basically, you'd
be looking at a pure functional language), but they would be completely
different languages.
Post by bartc
int A; // A1
{
{
}
A; // A1
A; // A1
}
A; // A1
Which one would simpler to understand (regarding which A is which) and
would be understood by a wider range of people?)
It does not do the same thing, and is therefore irrelevant.

(But see also the point I made above about understanding the difference
between examples and real-world code.)
bartc
2017-05-12 14:14:06 UTC
Permalink
Post by David Brown
Post by bartc
Why this obsession with these tiny scopes?
The obsession is with clear and easily understood code. If a variable
has a small scope, it is easy to see where it starts, what it does, and
where it ends.
It would have to be an extremely small scope for that. With real uses of
such block scopes (eg. see the pastebin examples I posted recently), the
code is chaotic, and finding the boundaries of a variable's scope is
harder. Not helped by using the same name for two instances of the
variable within a function.

Whereas with my variables, you /know/ they have function scope. You
/know/ there is at most one of each. And if functions are kept small as
you yourself suggest, then that is not a problem.

Writing large functions with big collections of variable
Post by David Brown
definitions at the start means you are jumping all over the function to
see what it does, or while writing it. It is even worse when your
language allows you to put the definition later on, after the variable
has been in use (as your language does, AFAIUI).
That is invaluable when you are adding a function. You don't need to
worry about whether references to the function are before or after the
place where you're going to put it, or both, and whether a forward
declaration is needed.

Within functions, out-of-order declarations are unusual for normal code
(sometimes used for temporary or test code).
Post by David Brown
int a = 1;
if (a == 1) {
int a = 2; // New a
foo(a); // a == 2 here
int b = 3; // Local b
// The scope for the new a (a == 2) ends here
int a = 4; // Yet another new a
A dangerous feature I think. Currently it's an error to redeclare a name
twice within a block. You're proposing to do away with that check.

I assume that the second 'a' can have a different type from the first.
But is the a==2 version still accessible, within the scope of a==4,
through a pointer for example? (In your equivalent version below, it is.)

If not then I can't see the advantage of this over just writing 'a=4'
instead of 'int a=4'. Or is this part of some campaign where you are
only allowed to assign to a variable once, or can only initialise it at
declaration (effectively doing away with assignment)?
Post by David Brown
bar(a, b); // a == 4, b == 3
}
foobar(a); // Back to the old a == 1
int a = 1;
if (a == 1) {
int a; // New a
a = 2; // The new a
foo(a); // a == 2 here
{
int b; // Local b
b = 3;
{
int a; // Yet another new a
a = 4; // The YAN a
bar(a, b); // a == 4, b == 3
} // end of scope for YAN a
} // end of scope for b
} // end of scope for "new" a
foobar(a); // Back to the old a == 1
Is that clear enough?
I can see it. But I'm struggling to see the benefit.

I can appreciate the advantages of more controlled scope on a larger
scale. If modules A and B want to share functions and variables, for
example, then those names will be accessible to C, D and E as well.

With some languages (a couple of mine for example), those names can be
kept private between A and B or least they will not clash with anything
exported by C or D.

But with your in-function examples, especially in real code with longer
names and more elaborate expressions, you're always going to be trying
to see what name is what.
--
bartc
David Brown
2017-05-12 15:04:42 UTC
Permalink
Post by bartc
Post by David Brown
Post by bartc
Why this obsession with these tiny scopes?
The obsession is with clear and easily understood code. If a variable
has a small scope, it is easy to see where it starts, what it does, and
where it ends.
It would have to be an extremely small scope for that. With real uses of
such block scopes (eg. see the pastebin examples I posted recently), the
code is chaotic, and finding the boundaries of a variable's scope is
harder. Not helped by using the same name for two instances of the
variable within a function.
The code you showed is an absolute mess. It may have come from a
popular open source project, but it is still a total disaster for
readability and maintainability. The second link, with smaller scopes
for variables, is marginally less bad - but it too has massive numbers
of variables declared in all the wrong places.

The standard since the dawn of time has been that if a function is too
big to fit comfortably in a screen on your editor, then it is probably
too big.

Now, in some code long functions can make sense. Typically that would
be a function where you simply have a long list of things to do, and the
use of parameters and/or some common local variables means it is easier
to have the bits sequentially in one function rather than splitting it
up and passing lots of data between the sub-functions. In such cases,
local variables with small block scopes is a massive win for readability.

And for more normal-sized functions, well, small block scopes are also a
massive win for readability.
Post by bartc
Whereas with my variables, you /know/ they have function scope.
(To save others the effort - only labels can have "function scope" in C.
You mean they have block scope in the outer block of the function.)
Post by bartc
You
/know/ there is at most one of each. And if functions are kept small as
you yourself suggest, then that is not a problem.
Yes, and you /know/ their definitions are separate from their uses so
that you don't know how they will be used when you define them, and you
don't know how their are defined when you use them. You /know/ you have
to jump back and forth in your editor when trying to find them or add
new variables, rather than seeing them a line or two away from where you
are. You /know/ that you are going to see a variable with a meaningless
name like "temp" used repeatedly for different purposes. You /know/
there are going to be left-overs as code changes, where the use of a
variable has been removed but its declaration is still there.

You know lots of things when you write functions that way.
Post by bartc
Writing large functions with big collections of variable
Post by David Brown
definitions at the start means you are jumping all over the function to
see what it does, or while writing it. It is even worse when your
language allows you to put the definition later on, after the variable
has been in use (as your language does, AFAIUI).
That is invaluable when you are adding a function. You don't need to
worry about whether references to the function are before or after the
place where you're going to put it, or both, and whether a forward
declaration is needed.
I don't worry - I just define my functions before I use them. Some
people prefer to declare their functions so that they can define them in
different orders - that works too, and I don't imagine they worry too
much either.

That said, I would not object to C being able to accept function
definitions within a translation unit in any order, without having
forward declarations. It would be fine for structs and unions too. But
allowing variables to be used before defining or declaring them is
asking for trouble, IMHO.
Post by bartc
Within functions, out-of-order declarations are unusual for normal code
(sometimes used for temporary or test code).
Post by David Brown
int a = 1;
if (a == 1) {
int a = 2; // New a
foo(a); // a == 2 here
int b = 3; // Local b
// The scope for the new a (a == 2) ends here
int a = 4; // Yet another new a
A dangerous feature I think. Currently it's an error to redeclare a name
twice within a block. You're proposing to do away with that check.
Yes, it is a new feature that I am proposing. It is not "doing away
with a check" - it is a new feature. Making a new definition with the
same name as an existing identifier is not doing away with a check, but
specifically ending the scope of the old identifier in this case. (That
makes it a little different from the translation into extra blocks.)

There are details to work out and specify in how this works - it could
be an issue if a reference to a variable is taken earlier on and that
variable is then replaced by a new one of the same name. Should the
lifetime of the old one carry on to the end of the block, or should it
stop at the declaration of the new one?
Post by bartc
I assume that the second 'a' can have a different type from the first.
Yes. (An alternative proposal would be to simply make the second
declaration redundant, and not introduce a new variable, but obviously
the type would have to be the same.)
Post by bartc
But is the a==2 version still accessible, within the scope of a==4,
through a pointer for example? (In your equivalent version below, it is.)
In the conversion below, it is still alive even though its scope is
hidden. I am in two minds about whether or not it should be that way,
or whether it should "die" when the new one takes effect. For C, there
is little disadvantage in letting it remain alive - if you don't access
it via a pointer, the compiler can see that it is dead and re-use the
space. For C++, it is a bit different - there is the question of when
the destructor is run. So this is a question that would have to be
considered and defined carefully.
Post by bartc
If not then I can't see the advantage of this over just writing 'a=4'
instead of 'int a=4'. Or is this part of some campaign where you are
only allowed to assign to a variable once, or can only initialise it at
declaration (effectively doing away with assignment)?
Different types would be allowed. Redefinition with the same type would
be mostly for convenience when moving code sections around or copying them.
Post by bartc
Post by David Brown
bar(a, b); // a == 4, b == 3
}
foobar(a); // Back to the old a == 1
int a = 1;
if (a == 1) {
int a; // New a
a = 2; // The new a
foo(a); // a == 2 here
{
int b; // Local b
b = 3;
{
int a; // Yet another new a
a = 4; // The YAN a
bar(a, b); // a == 4, b == 3
} // end of scope for YAN a
} // end of scope for b
} // end of scope for "new" a
foobar(a); // Back to the old a == 1
Is that clear enough?
I can see it. But I'm struggling to see the benefit.
I can appreciate the advantages of more controlled scope on a larger
scale. If modules A and B want to share functions and variables, for
example, then those names will be accessible to C, D and E as well.
That is a different matter entirely - and I agree that it would be nice
to have a solution to that. Namespaces (from C++) go some way to
solving that problem, and I see no reason why C could not copy that
feature from C++.
Post by bartc
With some languages (a couple of mine for example), those names can be
kept private between A and B or least they will not clash with anything
exported by C or D.
But with your in-function examples, especially in real code with longer
names and more elaborate expressions, you're always going to be trying
to see what name is what.
No, you would not.

If you actually tried working in a "small variable scope" manner, I
believe you would see its advantages. My proposal here just makes it a
little nicer.
s***@casperkitty.com
2017-05-12 15:27:52 UTC
Permalink
Post by bartc
Post by David Brown
If I were to change something here, it would be to allow a new
int a = f();
int b = g(a);
int a = h(b);
The first "a" would end its scope when the new "a" begins, and can have
a different type or the same type.
That's great. So instead of only having two possible instances of a name
"A" within a block (not counting struct tag versions and labels), we can
now have an unlimited number!
C presently limits the number of bindings a symbol can have within a block
to two, but allows a symbol to be associated at any point in the code with
with an arbitrary number of live objects within the current function
invocation context, even though only one is accessible.

Consider the code:

volatile int zzq;
void test(void)
{
int a=42;
int i=2;
do
{
zzq = a;
...
a=123456789;
zzq = a;
}
while(--i);
zzq = a;
}

If the code in the "..." is guaranteed not to prevent the "do" loop from
executing twice in normal fashion [i.e. it doesn't alter "i", nor "break",
nor anything like that] and doesn't write to zzq, what sequences of writes
to zzq might occur? Can you see how the sequence might be, e.g. {42,
123456792, 42, 123456792, 42}?

Having a guarantee that something like:

...
zzq = a;
} while(--i);
zzq = a;

could only be legal in cases where both "a" have the same meaning would seem
more helpful than having a guarantee that something like:

zzq = a;
...
zzq = a;
...
zzq = a;

would only be legal if at least two of the three uses of "a" have the same
meaning.
Thiago Adams
2017-05-11 12:03:16 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it
might have been declared somewhere in between.
When you just put all the declarations at the top of a function you have
to check every line for occurrences of every variable (if you are doing
any sort of semi-formal reasoning about your code), but both this and
your remark, whist being genuine problems with each approach, are
largely trivial in that there are simple tools to help in both cases.
I don't want to have to use tools just to understand code. (Otherwise
what's the point of a language having syntax? Just use some internal
format for source code, and rely on a tool for rendering in a syntax and
style of your choice.)
Post by Ben Bacarisse
It's hard to put into words why I find it so very much more comfortable
to do it my way. I suspect a lot of it comes down to the fact that we
think about code in very different ways, but here are a few thoughts
Smaller scope tend to reduce the use of either indeterminate objects
or objects initialised with meaningless "place-holder" values.
What happened to all the people telling us to keep functions to ten
lines or less? Then having multiple scopes within such a span would be
ludicrous.
Post by Ben Bacarisse
They localise changes. If I alter the upper bound (or otherwise alter
the exit) of
for (int i = lo; i < f(lo); i++) result = g(i, result);
I know I can't be messing with any code that has assumed that i == f(lo)
below the loop.
That's probably the only example where a localised loop index name can
make sense. In fact, here such a local index name is desirable, so you
don't even want to bother declaring it. [Not practical in C as there is
no official concept of a loop index variable]
How about const variables?
const int size = pStruct->Size;

Can this const be a tip for the
optimizer, or, in other words, can this style produce better code?

In my code, I use small scopes for variables,
and I initialize everything on declaration.
I try to create initialization that don't fail using
initializes. Sometimes I create a "empty" state for that.
But when I need a initialized state that can fail then I have
an unitized var.

Var var1;
if (Init(&var1)) { }


When I see:

int a;
int c;
int b;

a = ..;
b = ..;
c = a + b;

I do:

int a = ...;
int b = ... ;
int c = a + b;
bartc
2017-05-11 13:29:28 UTC
Permalink
Post by Thiago Adams
In my code, I use small scopes for variables,
and I initialize everything on declaration.
I try to create initialization that don't fail using
initializes. Sometimes I create a "empty" state for that.
But when I need a initialized state that can fail then I have
an unitized var.
Var var1;
if (Init(&var1)) { }
int a;
int c;
int b;
a = ..;
b = ..;
c = a + b;
int a = ...;
int b = ... ;
int c = a + b;
Well, it would be this:

<otherdecls>
int a,b,c;

<othercode>

a=X;
b=Y;
c=a+b;

The trouble is after changing it to:

<otherdecls>

<othercode>

int a=X;
int b=Y;
int c=a+b;

You then find you need to do something with a earlier on:

<otherdecls>

a=Z;
...

<othercode>

int a=X;
int b=Y;
int c=a+b;

Now a's declaration is in the wrong place! Worse, there might be another
a - of the wrong type - in an outer scope, and it will resolve to that.
Not a compile error, but it might work wrongly.

Also, you may decide that this last block needs to be conditional:

if (cond) {
int a=X;
int b=Y;
int c=a+b;
}

(or maybe there's an else part with an alternative initialiser, or maybe
sometimes a is defined in terms of b, and other times b is defined in
terms of a.)

Now you can't do this later:

if (cond) d=a-b;

as a and b are out of scope.

I can give dozens of examples; it just seems to me that these
tight-binding declarations are a strait-jacket. And in real code, things
will be considerably more muddled, with long, easy-to-confuse names, and
multiple instances of a, b and c.
--
bartc
Ian Collins
2017-05-12 08:04:54 UTC
Permalink
Post by Thiago Adams
Post by bartc
Post by Ben Bacarisse
They localise changes. If I alter the upper bound (or otherwise alter
the exit) of
for (int i = lo; i < f(lo); i++) result = g(i, result);
I know I can't be messing with any code that has assumed that i == f(lo)
below the loop.
That's probably the only example where a localised loop index name can
make sense. In fact, here such a local index name is desirable, so you
don't even want to bother declaring it. [Not practical in C as there is
no official concept of a loop index variable]
How about const variables?
const int size = pStruct->Size;
Can this const be a tip for the
optimizer, or, in other words, can this style produce better code?
Even if they don't, const variables are a compelling argument in favour
of declarations at the point of first use.
--
Ian
Patrick.Schluter
2017-05-11 19:56:31 UTC
Permalink
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it
might have been declared somewhere in between.
When you just put all the declarations at the top of a function you have
to check every line for occurrences of every variable (if you are doing
any sort of semi-formal reasoning about your code), but both this and
your remark, whist being genuine problems with each approach, are
largely trivial in that there are simple tools to help in both cases.
It's hard to put into words why I find it so very much more comfortable
to do it my way. I suspect a lot of it comes down to the fact that we
think about code in very different ways, but here are a few thoughts
I'm currently in the process of replacing systematically on our porject
the style of declaration, from the standard C way to the new C99 in-code
declarations. What I have notices during that process is that

- the code always gets shorter (1 line of declaration +1 line first
usage gets replaced by 1 line of declaration with initialisation.
- this often leads to some optimisations as very often the old
declarations initialised the variables for no reason.
- I've found several bugs in the code where variables got mixed up in
big functions.
- for loop declared variables allows to copy paste code more easily.
- refactoring long functions in to several smaller ones becomes order of
magnitude easier if you declare the variable where it is used. I was
surprized to see how often a variable was declared at the beginning and
only used twice at the end of the function in a very unlikely error path.

The funny thing is that doing that has brought the need for the if( with
declaration as the pattern of

type var = call();
if(var == somethin) callsomething(var);

is really very frequent.
Ben Bacarisse
2017-05-11 22:27:04 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't
clutter up
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
the rest of the code. That way I have smaller regions of code to
verify.
Post by Ben Bacarisse
Post by bartc
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it
might have been declared somewhere in between.
When you just put all the declarations at the top of a function you have
to check every line for occurrences of every variable (if you are doing
any sort of semi-formal reasoning about your code), but both this and
your remark, whist being genuine problems with each approach, are
largely trivial in that there are simple tools to help in both cases.
It's hard to put into words why I find it so very much more comfortable
to do it my way. I suspect a lot of it comes down to the fact that we
think about code in very different ways, but here are a few thoughts
I'm currently in the process of replacing systematically on our
porject the style of declaration, from the standard C way to the new
C99 in-code declarations. What I have notices during that process is
that
- the code always gets shorter (1 line of declaration +1 line first
usage gets replaced by 1 line of declaration with initialisation.
- this often leads to some optimisations as very often the old
declarations initialised the variables for no reason.
- I've found several bugs in the code where variables got mixed up in
big functions.
- for loop declared variables allows to copy paste code more easily.
- refactoring long functions in to several smaller ones becomes order
of magnitude easier if you declare the variable where it is used. I
was surprized to see how often a variable was declared at the
beginning and only used twice at the end of the function in a very
unlikely error path.
Interesting observations. Thanks.

I'm curious to know how you rate the original code quality and to know
what sort of average function size it has. The potential benefits might
depend to some extent on these.
Post by bartc
The funny thing is that doing that has brought the need for the if(
with declaration as the pattern of
type var = call();
if(var == somethin) callsomething(var);
is really very frequent.
Languages with anonymous functions get that (with scoping) for free of
course:

(var => if (var == something) callsomething(var))(call());

and many others have some form of 'let' or 'with' or 'where' to
introduce local bindings. Often these are just syntactic sugar for a
function call.
--
Ben.
bartc
2017-05-11 23:26:10 UTC
Permalink
Post by Ben Bacarisse
Post by Patrick.Schluter
I'm currently in the process of replacing systematically on our
porject the style of declaration, from the standard C way to the new
C99 in-code declarations. What I have notices during that process is
that
(I suspect any sort of systematic review will reduce the code size as
redundant parts of discovered. Maybe turning in-place declarations to
clustered ones will have done the same!)
Post by Ben Bacarisse
Post by Patrick.Schluter
- the code always gets shorter (1 line of declaration +1 line first
(Always?

int a,b,c; plus 3 lines of initialisation, would turn into

int a = ...
int b = ...
int c = ....

Four lines into three, rather than six lines into three. But these are
longer lines as the type is now duplicated.)
Post by Ben Bacarisse
Post by Patrick.Schluter
usage gets replaced by 1 line of declaration with initialisation.
- this often leads to some optimisations as very often the old
declarations initialised the variables for no reason.
- I've found several bugs in the code where variables got mixed up in
big functions.
(And you haven't yet found the ones that have been introduced!)
Post by Ben Bacarisse
Post by Patrick.Schluter
The funny thing is that doing that has brought the need for the if(
with declaration as the pattern of
type var = call();
if(var == somethin) callsomething(var);
is really very frequent.
Languages with anonymous functions get that (with scoping) for free of
(var => if (var == something) callsomething(var))(call());
and many others have some form of 'let' or 'with' or 'where' to
introduce local bindings. Often these are just syntactic sugar for a
function call.
You want a special variable such "_" or "$":

if ($ == something) callsomething($);

This can either be language supported (so is always available and always
assumes the type of the last assignment to it), or can be declared once
in a function then used as necessary (but each $ can only be of one type).

In this example, you are not really interested in 'var' other than as a
mechanism to carry over a temporary value to the expression, nor in the
type it needs to be.

So you don't particularly want a new feature just to declare a variable
that you don't really want either.
--
bartc
Ben Bacarisse
2017-05-12 00:16:14 UTC
Permalink
Post by Ben Bacarisse
Post by Patrick.Schluter
I'm currently in the process of replacing systematically on our
porject the style of declaration, from the standard C way to the new
C99 in-code declarations. What I have notices during that process is
that
(I suspect any sort of systematic review will reduce the code size as redundant parts of discovered. Maybe turning in-place declarations to clustered ones will have done the same!)
Post by Ben Bacarisse
Post by Patrick.Schluter
- the code always gets shorter (1 line of declaration +1 line first
(Always?
int a,b,c; plus 3 lines of initialisation, would turn into
int a = ...
int b = ...
int c = ....
Four lines into three, rather than six lines into three. But these are longer lines as the type is now duplicated.)
Post by Ben Bacarisse
Post by Patrick.Schluter
usage gets replaced by 1 line of declaration with initialisation.
- this often leads to some optimisations as very often the old
declarations initialised the variables for no reason.
- I've found several bugs in the code where variables got mixed up in
big functions.
(And you haven't yet found the ones that have been introduced!)
Post by Ben Bacarisse
Post by Patrick.Schluter
The funny thing is that doing that has brought the need for the if(
with declaration as the pattern of
type var = call();
if(var == somethin) callsomething(var);
is really very frequent.
Languages with anonymous functions get that (with scoping) for free of
(var => if (var == something) callsomething(var))(call());
and many others have some form of 'let' or 'with' or 'where' to
introduce local bindings. Often these are just syntactic sugar for a
function call.
No I don't. By all means tell me what *you* want -- it's seeing such
diverse options that makes Usenet interesting -- but I don't see how you
can possibly know what I want.
if ($ == something) call something($);
This can either be language supported (so is always available and
always assumes the type of the last assignment to it), or can be
declared once in a function then used as necessary (but each $ can
only be of one type).
I can think of at least three ways in which that hack offers less than I
what I want from a properly declared and scoped name in C.
In this example, you are not really interested in 'var' other than as
a mechanism to carry over a temporary value to the expression, nor in
the type it needs to be.
It's not my example. Patrick obviously chose deliberately generic
names. There are situations where I *am* interested in the name and/or
the type. And I am always interested in the scope.

<snip>
--
Ben.
bartc
2017-05-12 00:35:33 UTC
Permalink
Post by Ben Bacarisse
Post by Ben Bacarisse
Post by Patrick.Schluter
The funny thing is that doing that has brought the need for the if(
with declaration as the pattern of
type var = call();
if(var == somethin) callsomething(var);
is really very frequent.
Languages with anonymous functions get that (with scoping) for free of
(var => if (var == something) callsomething(var))(call());
and many others have some form of 'let' or 'with' or 'where' to
introduce local bindings. Often these are just syntactic sugar for a
function call.
No I don't. By all means tell me what *you* want -- it's seeing such
diverse options that makes Usenet interesting -- but I don't see how you
can possibly know what I want.
I put forward my proposal because I couldn't figure out yours. (Where do
you start? These things need to be obvious.)
Post by Ben Bacarisse
if ($ == something) call something($);
(Result of call() should be assigned to $ first.)
Post by Ben Bacarisse
I can think of at least three ways in which that hack offers less than I
what I want from a properly declared and scoped name in C.
In this example, you are not really interested in 'var' other than as
a mechanism to carry over a temporary value to the expression, nor in
the type it needs to be.
It's not my example. Patrick obviously chose deliberately generic
names. There are situations where I *am* interested in the name and/or
the type. And I am always interested in the scope.
No, this pattern is only about taking the result of one call and passing
it to another. If it wasn't for the conditional, it would simply be
written as:

callsomething(call())

No intermediate variable to be defined.
--
bartc
Ben Bacarisse
2017-05-12 00:58:04 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
Post by Ben Bacarisse
Post by Patrick.Schluter
The funny thing is that doing that has brought the need for the if(
with declaration as the pattern of
type var = call();
if(var == somethin) callsomething(var);
is really very frequent.
Languages with anonymous functions get that (with scoping) for free of
(var => if (var == something) callsomething(var))(call());
and many others have some form of 'let' or 'with' or 'where' to
introduce local bindings. Often these are just syntactic sugar for a
function call.
No I don't. By all means tell me what *you* want -- it's seeing such
diverse options that makes Usenet interesting -- but I don't see how you
can possibly know what I want.
I put forward my proposal because I couldn't figure out yours. (Where
do you start? These things need to be obvious.)
You could always ask, I suppose. Anyway, I have no proposal. I was
showing how parameter binding in other languages achieves the desired
effect.
Post by bartc
Post by Ben Bacarisse
if ($ == something) call something($);
(Result of call() should be assigned to $ first.)
Post by Ben Bacarisse
I can think of at least three ways in which that hack offers less than I
what I want from a properly declared and scoped name in C.
In this example, you are not really interested in 'var' other than as
a mechanism to carry over a temporary value to the expression, nor in
the type it needs to be.
It's not my example. Patrick obviously chose deliberately generic
names. There are situations where I *am* interested in the name and/or
the type. And I am always interested in the scope.
No,
What are you saying "no" to? You don't think there are situations where
I am interesting the name (so $ or _ would be poor choices)? Or you
don't think there are situations where I care about the type and simply
assigning $ or _ might not produce the desired result? Or maybe you
don't think I really do care about the scope which is why one universal
$ or _ is less than ideal?
Post by bartc
this pattern is only about taking the result of one call and
passing it to another.
Clearly it isn't.
Post by bartc
If it wasn't for the conditional, it would
callsomething(call())
No intermediate variable to be defined.
No I'm lost. In a discussion of scopes, what would be the point of an
example that did not have a named variable? There would have been
nothing to say if it weren't for the conditional.
--
Ben.
Patrick.Schluter
2017-05-12 20:36:23 UTC
Permalink
Post by Ben Bacarisse
Post by Ben Bacarisse
Post by Patrick.Schluter
The funny thing is that doing that has brought the need for the if(
with declaration as the pattern of
type var = call();
if(var == somethin) callsomething(var);
is really very frequent.
Languages with anonymous functions get that (with scoping) for free of
(var => if (var == something) callsomething(var))(call());
and many others have some form of 'let' or 'with' or 'where' to
introduce local bindings. Often these are just syntactic sugar for a
function call.
No I don't. By all means tell me what *you* want -- it's seeing such
diverse options that makes Usenet interesting -- but I don't see how you
can possibly know what I want.
if ($ == something) call something($);
This can either be language supported (so is always available and
always assumes the type of the last assignment to it), or can be
declared once in a function then used as necessary (but each $ can
only be of one type).
I can think of at least three ways in which that hack offers less than I
what I want from a properly declared and scoped name in C.
In this example, you are not really interested in 'var' other than as
a mechanism to carry over a temporary value to the expression, nor in
the type it needs to be.
It's not my example. Patrick obviously chose deliberately generic
names. There are situations where I *am* interested in the name and/or
the type. And I am always interested in the scope.
Indeed, I used generic names. Maybe if I had used the usual foo, bar and
foobar (or for the French toto, titi, tata) it would have been more obvious.
But to come back to what I meant. The pattern that came quit frequently
was the need to have a temporary variable holding the result of a call
because the value returned appears more than once in the if/else clause.
With pure function one can sometime get away with the repetition but
very often it is not possible. Here an example of what I mean.
int var = getc();
if(var == 'A') { ...use var... }
var not used anymore after that.

That pattern was not rare and several times I would have found it handy
to have something similar to the for(decls.... The same happens with
while(.) loops, but there it can sometimes be changed by using a for(
loop. Funnily, for do{}while() loop though, it's generally not that
useful as you can not use a variable declared inside the statement in
the condition as it is out of scope.

Just my observation after a few months of using that feature.
Patrick.Schluter
2017-05-12 20:19:47 UTC
Permalink
Post by bartc
Post by Patrick.Schluter
I'm currently in the process of replacing systematically on our
porject the style of declaration, from the standard C way to the new
C99 in-code declarations. What I have notices during that process is
that
(I suspect any sort of systematic review will reduce the code size as
redundant parts of discovered. Maybe turning in-place declarations to
clustered ones will have done the same!)
As I said in the answer to Ben Bacarisse, it's partially true but a good
part comes from the declaration close to where it's used. At the
beginning I was myself very sceptic of the benefits (I used to criticize
C++ for that) but the more I did it the more I saw the advantages. Of
course, one has to be careful as it is possible to introduce new bugs
but in general, my experience has been very positive.
Post by bartc
Post by Patrick.Schluter
- the code always gets shorter (1 line of declaration +1 line first
(Always?
int a,b,c; plus 3 lines of initialisation, would turn into
int a = ...
int b = ...
int c = ....
int a=..., b=..., c=...;

but granted, always is a bit exagerated.
Post by bartc
Four lines into three, rather than six lines into three. But these are
longer lines as the type is now duplicated.)
Post by Patrick.Schluter
usage gets replaced by 1 line of declaration with initialisation.
- this often leads to some optimisations as very often the old
declarations initialised the variables for no reason.
- I've found several bugs in the code where variables got mixed up in
big functions.
(And you haven't yet found the ones that have been introduced!)
Patrick.Schluter
2017-05-12 20:06:18 UTC
Permalink
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't
clutter up
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
the rest of the code. That way I have smaller regions of code to
verify.
Post by Ben Bacarisse
Post by bartc
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it
might have been declared somewhere in between.
When you just put all the declarations at the top of a function you have
to check every line for occurrences of every variable (if you are doing
any sort of semi-formal reasoning about your code), but both this and
your remark, whist being genuine problems with each approach, are
largely trivial in that there are simple tools to help in both cases.
It's hard to put into words why I find it so very much more comfortable
to do it my way. I suspect a lot of it comes down to the fact that we
think about code in very different ways, but here are a few thoughts
I'm currently in the process of replacing systematically on our
porject the style of declaration, from the standard C way to the new
C99 in-code declarations. What I have notices during that process is
that
- the code always gets shorter (1 line of declaration +1 line first
usage gets replaced by 1 line of declaration with initialisation.
- this often leads to some optimisations as very often the old
declarations initialised the variables for no reason.
- I've found several bugs in the code where variables got mixed up in
big functions.
- for loop declared variables allows to copy paste code more easily.
- refactoring long functions in to several smaller ones becomes order
of magnitude easier if you declare the variable where it is used. I
was surprized to see how often a variable was declared at the
beginning and only used twice at the end of the function in a very
unlikely error path.
Interesting observations. Thanks.
I'm curious to know how you rate the original code quality and to know
what sort of average function size it has. The potential benefits might
depend to some extent on these.
The original code was not really good to begin with. The initial
developpers had the tendency to write really big convoluted functions
which did several unrelated things. A part of the code enhancement comes
from the moving of the declarations but granted, some of it comes only
because doing that refactoring make me read the code more thoroughly.
Similarly, documenting with doxygen also often trigger rewrites because
trying to understand the parameters to explain them uncovers better ways
to organise code.
So, the gain comes partially from the moving of declaration but often
only because of simple review.
Post by Ben Bacarisse
Post by bartc
The funny thing is that doing that has brought the need for the if(
with declaration as the pattern of
type var = call();
if(var == somethin) callsomething(var);
is really very frequent.
Languages with anonymous functions get that (with scoping) for free of
(var => if (var == something) callsomething(var))(call());
and many others have some form of 'let' or 'with' or 'where' to
introduce local bindings. Often these are just syntactic sugar for a
function call.
GOTHIER Nathan
2017-05-12 00:09:28 UTC
Permalink
On Thu, 11 May 2017 21:56:31 +0200
Post by Patrick.Schluter
I'm currently in the process of replacing systematically on our porject
the style of declaration, from the standard C way to the new C99 in-code
declarations. What I have notices during that process is that
Please define what's standard C for you since C99 is standard... Once more,
could you provide some snippets to be more explicit about your concept.
Patrick.Schluter
2017-05-12 20:38:14 UTC
Permalink
Post by GOTHIER Nathan
On Thu, 11 May 2017 21:56:31 +0200
Post by Patrick.Schluter
I'm currently in the process of replacing systematically on our porject
the style of declaration, from the standard C way to the new C99 in-code
declarations. What I have notices during that process is that
Please define what's standard C for you since C99 is standard... Once more,
could you provide some snippets to be more explicit about your concept.
the old K&R and C89 way. Wasn't it obvious from the context?
James R. Kuyper
2017-05-12 21:15:56 UTC
Permalink
Post by Patrick.Schluter
Post by GOTHIER Nathan
On Thu, 11 May 2017 21:56:31 +0200
Post by Patrick.Schluter
I'm currently in the process of replacing systematically on our porject
the style of declaration, from the standard C way to the new C99 in-code
declarations. What I have notices during that process is that
Please define what's standard C for you since C99 is standard... Once more,
could you provide some snippets to be more explicit about your concept.
the old K&R and C89 way. Wasn't it obvious from the context?
No, it isn't. In context, I'd obviously expect "standard C" to refer to
C2011, which has been the current C standard for six years now. This is
clearly in conflict with your use of the term "new" in the above
message, which is what leads to questions about what you actually meant
by the term.
s***@casperkitty.com
2017-05-12 22:10:43 UTC
Permalink
Post by James R. Kuyper
No, it isn't. In context, I'd obviously expect "standard C" to refer to
C2011, which has been the current C standard for six years now. This is
clearly in conflict with your use of the term "new" in the above
message, which is what leads to questions about what you actually meant
by the term.
The phrase "Standard C" should be stricken from the lexicon unless or until
the Committee decides via some means to ensure that every program whose
meaning is defined by some version of the Standard will have that same
meaning defined by all future versions of the Standard. Many standards
are able to accomplish such a thing via use of version headers in files.
If an HTML file starts with a header that identifies it as conforming to a
particular version of the HTML standard, the meaning of any directives
within it will not change even if later standards define those directives
differently. Unfortunately, C99 fails to define the behavior of some source
texts whose behavior was unambiguously defined in C89, and fails to provide
any reasonable means by which those source texts could be adapted to have
defined behavior in all the cases where they had previously.
Robert Wessel
2017-05-13 05:02:43 UTC
Permalink
Post by s***@casperkitty.com
Post by James R. Kuyper
No, it isn't. In context, I'd obviously expect "standard C" to refer to
C2011, which has been the current C standard for six years now. This is
clearly in conflict with your use of the term "new" in the above
message, which is what leads to questions about what you actually meant
by the term.
The phrase "Standard C" should be stricken from the lexicon unless or until
the Committee decides via some means to ensure that every program whose
meaning is defined by some version of the Standard will have that same
meaning defined by all future versions of the Standard. Many standards
are able to accomplish such a thing via use of version headers in files.
If an HTML file starts with a header that identifies it as conforming to a
particular version of the HTML standard, the meaning of any directives
within it will not change even if later standards define those directives
differently. Unfortunately, C99 fails to define the behavior of some source
texts whose behavior was unambiguously defined in C89, and fails to provide
any reasonable means by which those source texts could be adapted to have
defined behavior in all the cases where they had previously.
That would preclude things even as simple as the addition of new
keywords to the language. Nor does the history of language standards
does not offer evidence that such an approach is realistic. IOW,
you're arguing for complete stagnation. Which actually appears to be
what you want, weren't you the one arguing that the C74 documentation
expresses the "real" ideals of C? (If that wasn't you, I apologize).

I'm reminded of the post Cobol-74 (eventually '85) committee that was
so tied by users refusing to accept even minor incompatibilities (at
one point Traveler's Insurance was threatening to sue the committee
because of the conversion cost they thought they were going to incur),
that it took them the better part of a decade to get the standard
knocked out.

In any event, the usual approach is for compiler vendors to offer both
a "old" and "new" mode of operation. That seems to work well enough.
GOTHIER Nathan
2017-05-12 22:59:44 UTC
Permalink
On Fri, 12 May 2017 22:38:14 +0200
Post by Patrick.Schluter
the old K&R and C89 way. Wasn't it obvious from the context?
I assumed C89 from the context only because that's the first burocratic and the
most commonly supported definition by compilers. However C has many definitions
and your sentence is ambiguous assuming C99 isn't formally defined by the ISO
committee.
Robert Wessel
2017-05-13 05:04:11 UTC
Permalink
On Sat, 13 May 2017 00:59:44 +0200, GOTHIER Nathan
Post by GOTHIER Nathan
On Fri, 12 May 2017 22:38:14 +0200
Post by Patrick.Schluter
the old K&R and C89 way. Wasn't it obvious from the context?
I assumed C89 from the context only because that's the first burocratic and the
most commonly supported definition by compilers. However C has many definitions
and your sentence is ambiguous assuming C99 isn't formally defined by the ISO
committee.
C99 was defined in standard ISO/IEC 9899:1999.

Alan Mackenzie
2017-05-12 16:25:26 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
Post by bartc
Not me. I prefer declarations all tucked away in a corner so they
don't clutter up the code.
I prefer to have my scopes all tucked away so the names don't clutter up
the rest of the code. That way I have smaller regions of code to verify.
Then it means having to analyse every line back to the start of the
function to find the declaration of some variable. Just in case it might
have been declared somewhere in between.
With the right tool, i.e. an editor that highlights declarations, this
is not an onerous task.

[ .... ]
Post by bartc
--
bartc
--
Alan Mackenzie (Nuremberg, Germany).
j***@gmail.com
2017-05-10 23:45:46 UTC
Permalink
Post by bartc
Post by Thiago Adams
C++ 17, has now a new if.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html
if ( for-init-statement condition ) statement
is equivalent to
{
for-init-statement
if ( condition ) statement
}
and
if ( for-init-statement condition ) statement else statement
is equivalent to
{
for-init-statement
if ( condition ) statement else statement
}
Would you like to see this if on C?
Not me. I prefer declarations all tucked away in a corner so they don't
clutter up the code.
People complain about Hungarian notation but this doesn't seem much
different.
Besides, this can be done now with {} either surrounding the if
statement (assuming the scope extends to the end of the second
statement), or inside the condition using the gcc extension.
--
bartc
{ int ch;
if ( ( ch = getchar() ) == EOF )
break;
...
buffer[ i++ ] = ch;
...
}

As opposed to

if ( getchar() == EOF ) { ... }

If I'm going to go to the trouble of explicitly saving a result, I think I want the result.

If I want to throw it away, I want to throw it away.

On the for loop, providing explicit loop variables does make the syntax useful.
--
Joel Rees

Ranting randomly:
http://reiisi.blogspot.com
Thiago Adams
2017-05-11 12:07:17 UTC
Permalink
Post by Thiago Adams
C++ 17, has now a new if.
[...]
One more:

Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf

int i = 1'000'000;

What I find weird is that the position of ' is not verified.

"An integer literal is a sequence of digits that has no period or exponent part, with optional
separating single quotes that are ignored when determining its value"
Thiago Adams
2017-05-11 12:10:05 UTC
Permalink
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Binary Literals in the C++ Core Language
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf

int i = 0b1100;

(I liked this)
David Brown
2017-05-11 12:29:17 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Binary Literals in the C++ Core Language
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf
int i = 0b1100;
(I liked this)
Many compilers support that as an extension (in C and C++). Indeed, C++
picked it up as a feature that existing tools had supported for years,
users found useful, and there were no conflicts with anything else in
the language. So it was a cheap and easy addition to the C++ standards.

Apparently in the C world, we are supposed to define our own macros of
various levels of ugliness and odd restrictions, and use them. Since it
is /possible/ to use macros to write binary literals, it does not need
to be added to the language.


Yes, /I/ would like to see it added to C - and I truly believe it would
have negligible costs. I appreciate that one of the aims of C is to
keep the language small and stable, and let C++ be the relative with all
the latest bells and whistles. But this would be a couple of paragraphs
to add to the standard - and /nothing/ to change in the major compiler
implementations.

Binary constants are easier to write when there is a digit separator.
The choice of ' is not pretty, but all the better alternatives have
disadvantages. I'd be happy to see that in C too, and would use it
occasionally.

Both these changes are zero cost to the user - the don't affect existing
correct code, they don't introduce new ways to get things wrong, they
can be safely ignored if you don't need them, and they are easily
understood when you see them for the first time.
Keith Thompson
2017-05-11 16:10:45 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
What I find weird is that the position of ' is not verified.
Verified how?
Post by Thiago Adams
"An integer literal is a sequence of digits that has no period or
exponent part, with optional separating single quotes that are ignored
when determining its value"
Separating every 3 digits, counting from the low-order digit, is not the
only possible pattern. I believe that a different convention is used in
India (I don't remember the details). In a context where the
conventional 3-digit grouping is desirable, any deviation should be
reasonably obvious to the reader.

And grouping by 4 digits is likely to be common for hexadecimal and
binary.

(I personally wish that the syntax had used underscores, but that was
precluded by C++ user-defined literals.)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Thiago Adams
2017-05-11 16:49:51 UTC
Permalink
Post by Keith Thompson
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
What I find weird is that the position of ' is not verified.
Verified how?
Post by Thiago Adams
"An integer literal is a sequence of digits that has no period or
exponent part, with optional separating single quotes that are ignored
when determining its value"
Separating every 3 digits, counting from the low-order digit, is not the
only possible pattern. I believe that a different convention is used in
India (I don't remember the details). In a context where the
conventional 3-digit grouping is desirable, any deviation should be
reasonably obvious to the reader.
And grouping by 4 digits is likely to be common for hexadecimal and
binary.
(I personally wish that the syntax had used underscores, but that was
precluded by C++ user-defined literals.)
Yes, 3-digit grouping.
I guess the motivation was avoid mistakes.

If is just to see better, why not give the job for text editors?
They can create some distinction on rendering.
bartc
2017-05-11 17:51:15 UTC
Permalink
Post by Thiago Adams
Yes, 3-digit grouping.
I guess the motivation was avoid mistakes.
If is just to see better, why not give the job for text editors?
They can create some distinction on rendering.
That doesn't really work. There are a million different editors and
syntax highlighters. The few I've tried will not automatically insert
separators on numbers. It would create problems anyway on mono-spaced
fonts as things will no longer line up. And sometimes you want
separators, and sometimes you don't. Or in a different pattern.

But if the language allows you to, then you can add explicit separators
and EVERY editor will display them. And exactly where you want them.

So I might want to write a binary number like this: 2x10'110'001 so that
the fields match some format. (Or it might be 0b in C.)
Post by Thiago Adams
I guess the motivation was avoid mistakes.
Yes, in writing the numbers in the first place. How will an editor know
when to insert the separators as you write 1,234,567? Assuming you
start writing from left to right:

You enter so far: The editor shows:

1 1
12 12
123 123
1234 1'234
12345 12,345

Now it's out of sync for a couple of characters, which will be
confusing. Much easier to do it 'manually'.
--
bartc
Thiago Adams
2017-05-11 18:19:50 UTC
Permalink
Post by bartc
Post by Thiago Adams
Yes, 3-digit grouping.
I guess the motivation was avoid mistakes.
If is just to see better, why not give the job for text editors?
They can create some distinction on rendering.
That doesn't really work. There are a million different editors and
syntax highlighters. The few I've tried will not automatically insert
separators on numbers. It would create problems anyway on mono-spaced
fonts as things will no longer line up. And sometimes you want
separators, and sometimes you don't. Or in a different pattern.
But if the language allows you to, then you can add explicit separators
and EVERY editor will display them. And exactly where you want them.
My idea was to group using colors.
How uses an source editor without colors today? (I am afraid to ask :D)

I don't think this digit groups are bad, but maybe they
are not too good to add to the language.
Scott Lurndal
2017-05-11 18:31:24 UTC
Permalink
Post by Thiago Adams
Post by bartc
Post by Thiago Adams
Yes, 3-digit grouping.
I guess the motivation was avoid mistakes.
If is just to see better, why not give the job for text editors?
They can create some distinction on rendering.
That doesn't really work. There are a million different editors and
syntax highlighters. The few I've tried will not automatically insert
separators on numbers. It would create problems anyway on mono-spaced
fonts as things will no longer line up. And sometimes you want
separators, and sometimes you don't. Or in a different pattern.
But if the language allows you to, then you can add explicit separators
and EVERY editor will display them. And exactly where you want them.
My idea was to group using colors.
How uses an source editor without colors today? (I am afraid to ask :D)
I would say a large fraction of programmers don't use
source editors with colors _all the time_. Particularly
folks who still use vi (as opposed to vim).

Verilog number formats:

[<sign>][<size-in-bits>]'<base><digits>

where base is b (2), o(8), d(10), h(16). Digits can be grouped with underscore.
The digit 'z' indicates a high-impedence signal, while 'x' indicates unknown/dont-care

sample:
8'hA0 (8-bit decimal value 160)
64'h1234_5678_9abc_def0

und so weiter.
Keith Thompson
2017-05-11 18:59:10 UTC
Permalink
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
What I find weird is that the position of ' is not verified.
Verified how?
Post by Thiago Adams
"An integer literal is a sequence of digits that has no period or
exponent part, with optional separating single quotes that are ignored
when determining its value"
Separating every 3 digits, counting from the low-order digit, is not the
only possible pattern. I believe that a different convention is used in
India (I don't remember the details). In a context where the
conventional 3-digit grouping is desirable, any deviation should be
reasonably obvious to the reader.
And grouping by 4 digits is likely to be common for hexadecimal and
binary.
(I personally wish that the syntax had used underscores, but that was
precluded by C++ user-defined literals.)
Yes, 3-digit grouping.
I guess the motivation was avoid mistakes.
If is just to see better, why not give the job for text editors?
They can create some distinction on rendering.
Not everyone uses highlighting text editors.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
David Kleinecke
2017-05-11 19:58:08 UTC
Permalink
Post by Keith Thompson
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
What I find weird is that the position of ' is not verified.
Verified how?
Post by Thiago Adams
"An integer literal is a sequence of digits that has no period or
exponent part, with optional separating single quotes that are ignored
when determining its value"
Separating every 3 digits, counting from the low-order digit, is not the
only possible pattern. I believe that a different convention is used in
India (I don't remember the details). In a context where the
conventional 3-digit grouping is desirable, any deviation should be
reasonably obvious to the reader.
And grouping by 4 digits is likely to be common for hexadecimal and
binary.
(I personally wish that the syntax had used underscores, but that was
precluded by C++ user-defined literals.)
Yes, 3-digit grouping.
I guess the motivation was avoid mistakes.
If is just to see better, why not give the job for text editors?
They can create some distinction on rendering.
Not everyone uses highlighting text editors.
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
bartc
2017-05-11 20:18:17 UTC
Permalink
Post by David Kleinecke
Post by Keith Thompson
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
What I find weird is that the position of ' is not verified.
Verified how?
Post by Thiago Adams
"An integer literal is a sequence of digits that has no period or
exponent part, with optional separating single quotes that are ignored
when determining its value"
Separating every 3 digits, counting from the low-order digit, is not the
only possible pattern. I believe that a different convention is used in
India (I don't remember the details). In a context where the
conventional 3-digit grouping is desirable, any deviation should be
reasonably obvious to the reader.
And grouping by 4 digits is likely to be common for hexadecimal and
binary.
(I personally wish that the syntax had used underscores, but that was
precluded by C++ user-defined literals.)
Yes, 3-digit grouping.
I guess the motivation was avoid mistakes.
If is just to see better, why not give the job for text editors?
They can create some distinction on rendering.
Not everyone uses highlighting text editors.
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
I would have thought that it needed to recognise and expand macros too.
But I'm not sure that's possible because that can depend on conditional
code.

And not all conditions are known because some are external so the editor
won't know about them. (They might be in a header the editor has no
access to, or it hasn't been created yet, or they are a compiler option.)
--
bartc
Thiago Adams
2017-05-11 20:45:56 UTC
Permalink
On Thursday, May 11, 2017 at 4:58:15 PM UTC-3, David Kleinecke wrote:
[...]
Post by David Kleinecke
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
Yes they do this and much more.
Ian Collins
2017-05-12 08:08:44 UTC
Permalink
Post by David Kleinecke
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
You haven't looked very hard then!
--
Ian
Malcolm McLean
2017-05-12 08:37:01 UTC
Permalink
Post by Ian Collins
Post by David Kleinecke
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
You haven't looked very hard then!
XCode's editor does a full semantic pass over C++ source.
You even have smart autocomplete - type structure variable,
and dot, and a list of members pops up.
bartc
2017-05-12 11:08:10 UTC
Permalink
Post by Malcolm McLean
Post by Ian Collins
Post by David Kleinecke
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
You haven't looked very hard then!
XCode's editor does a full semantic pass over C++ source.
You even have smart autocomplete - type structure variable,
and dot, and a list of members pops up.
That's XCode.

What about a thousand other products that don't do that?

You can't decide whether or not to add a language feature based on the
capabilities of a handful of smart editors.

That fact is that if I upload any C code to pastebin or github now, they
won't insert separators in my numbers, even if the tool I use myself
does so (it doesn't).

Sometime this is about making things easier for other people. If every
shared fragment of C also came with a working XCode renderer so everyone
could view the code in the same way, that would be great. But that isn't
yet the case.

You would hope however that every text viewer could show ASCII.
--
bartc
David Brown
2017-05-12 13:31:27 UTC
Permalink
Post by bartc
Post by Malcolm McLean
Post by Ian Collins
Post by David Kleinecke
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
You haven't looked very hard then!
XCode's editor does a full semantic pass over C++ source.
You even have smart autocomplete - type structure variable,
and dot, and a list of members pops up.
That's XCode.
What about a thousand other products that don't do that?
What about the dozens of other editors that /do/ have something similar?
The ones that most professional programmers use all the time (Eclipse,
MSVS, Netbeans, emacs, vim, CLion, jedit, programmer's notepad,
notepad++, etc.) have excellent C syntax highlighting. I can't tell you
off-hand if they /all/ highlight typedef names, but I expect they do.
Post by bartc
You can't decide whether or not to add a language feature based on the
capabilities of a handful of smart editors.
"Add a language feature"? How long has C had typedef? 40 years?

And if you are working as a programmer and don't have a decent editor,
it is /your/ fault.
Post by bartc
That fact is that if I upload any C code to pastebin or github now, they
won't insert separators in my numbers, even if the tool I use myself
does so (it doesn't).
I believe you have got your Usenet sub-threads mixed up. The issue here
is David K's absurd idea that there are no editors that highlight
typedef names.

Syntax highlighting of new features /is/ an issue - you are right there.
In particular, when adding a new language feature it is helpful if
existing popular editors do not mark it as a syntax error.

If ' were added to C as a digit separator, it would probably not take
long before leading editors and websites accepted it - after all, they
accept it in C++.
Post by bartc
Sometime this is about making things easier for other people. If every
shared fragment of C also came with a working XCode renderer so everyone
could view the code in the same way, that would be great. But that isn't
yet the case.
You would hope however that every text viewer could show ASCII.
Do you know of any that can't?
Malcolm McLean
2017-05-12 14:03:44 UTC
Permalink
Post by David Brown
And if you are working as a programmer and don't have a decent editor,
it is /your/ fault.
Not always.
For example I'm paying around with someone else's C interpreter at the
moment (for a new language). So I have to enter C source for it to interpret
somehow, which is easiest as embedded string literals. Needless to say, the
editor won't offer editing support for code in strings.
Post by David Brown
Post by bartc
That fact is that if I upload any C code to pastebin or github now, they
won't insert separators in my numbers, even if the tool I use myself
does so (it doesn't).
Syntax highlighting of new features /is/ an issue - you are right there.
In particular, when adding a new language feature it is helpful if
existing popular editors do not mark it as a syntax error.
That's a real problem. So too when there's a bug in the editor's parser,
as happens a bit with XCode.
bartc
2017-05-12 14:21:33 UTC
Permalink
Post by David Brown
Post by bartc
You would hope however that every text viewer could show ASCII.
Do you know of any that can't?
I mention that because I've used displays that were upper case, so a..z,
{ and }, and some punctuation would be missing. A bit of a problem for C
source.

They've always managed "$" however.
--
bartc
David Brown
2017-05-12 15:06:19 UTC
Permalink
Post by bartc
Post by David Brown
Post by bartc
You would hope however that every text viewer could show ASCII.
Do you know of any that can't?
I mention that because I've used displays that were upper case, so a..z,
{ and }, and some punctuation would be missing. A bit of a problem for C
source.
From what century?

I have used displays that could not use colour syntax highlighting
because they were black and white - but I don't consider it a big
problem these days.
Post by bartc
They've always managed "$" however.
bartc
2017-05-12 15:36:43 UTC
Permalink
Post by David Brown
Post by bartc
Post by David Brown
Post by bartc
You would hope however that every text viewer could show ASCII.
Do you know of any that can't?
I mention that because I've used displays that were upper case, so a..z,
{ and }, and some punctuation would be missing. A bit of a problem for C
source.
From what century?
Twentieth. More recently than when C was created anyway. In 1976 I was
using ASR33s for example.

Ancient stuff but then people are always going on about some feature of
C being that way otherwise it wouldn't work on hardware that's been
obsolete for decades.
Post by David Brown
I have used displays that could not use colour syntax highlighting
because they were black and white - but I don't consider it a big
problem these days.
That must have been a binary black and white video board I guess; the
display itself was probably monochrome. (I used to watch snooker on my
9" green-screen NEC monitor and it was easy to see which ball was which.)
--
bartc
David Kleinecke
2017-05-12 18:58:39 UTC
Permalink
Post by David Brown
I believe you have got your Usenet sub-threads mixed up. The issue here
is David K's absurd idea that there are no editors that highlight
typedef names.
You are treating me as having far too much poser. All I
said was I didn't know of any.

That is your cue to make me better informed. I don't pretend
to know everything. All I knew about XCode was that it was an
Apple-oriented product. I still don't take Apple seriously.
David Brown
2017-05-12 10:34:12 UTC
Permalink
Post by David Kleinecke
Post by Keith Thompson
Not everyone uses highlighting text editors.
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
Even if it were true that there are few editors that highlight typedef
names (and it is not true), there are a great many other things that a
highlighting editor helps with. Typedef highlighting is only one of
many things.
David Kleinecke
2017-05-12 18:48:17 UTC
Permalink
Post by David Brown
Post by David Kleinecke
Post by Keith Thompson
Not everyone uses highlighting text editors.
A highlighting editor for C is essentially useless unless
it can recognize and highlight typedef names. That seems to
be something it would be possible to do. But I know of no
editor that does.
Even if it were true that there are few editors that highlight typedef
names (and it is not true), there are a great many other things that a
highlighting editor helps with. Typedef highlighting is only one of
many things.
The only other thing I find helpful is highlighting
comments. I admit to mostly using gedit as my editor.

I might make use of a highlighting of every identifier
that was not yet declared. But that would seem to imply
an editor setup where both the .c and .h were being
written at the same time.
Ian Collins
2017-05-12 19:41:48 UTC
Permalink
Post by David Kleinecke
Post by David Brown
Even if it were true that there are few editors that highlight typedef
names (and it is not true), there are a great many other things that a
highlighting editor helps with. Typedef highlighting is only one of
many things.
The only other thing I find helpful is highlighting
comments. I admit to mostly using gedit as my editor.
I might make use of a highlighting of every identifier
that was not yet declared. But that would seem to imply
an editor setup where both the .c and .h were being
written at the same time.
Most IDE based editors have some form of code assistance which uses
background compilation to do such things.
--
Ian
David Kleinecke
2017-05-13 00:38:21 UTC
Permalink
Post by Ian Collins
Post by David Kleinecke
Post by David Brown
Even if it were true that there are few editors that highlight typedef
names (and it is not true), there are a great many other things that a
highlighting editor helps with. Typedef highlighting is only one of
many things.
The only other thing I find helpful is highlighting
comments. I admit to mostly using gedit as my editor.
I might make use of a highlighting of every identifier
that was not yet declared. But that would seem to imply
an editor setup where both the .c and .h were being
written at the same time.
Most IDE based editors have some form of code assistance which uses
background compilation to do such things.
The only IDE I have installed is Geany and it doesn't
highlight (unless it does and I have turned it off). I
haven't found an IDE that I like better than not using an
IDE.
GOTHIER Nathan
2017-05-12 23:23:10 UTC
Permalink
On Fri, 12 May 2017 11:48:17 -0700 (PDT)
Post by David Kleinecke
The only other thing I find helpful is highlighting
comments. I admit to mostly using gedit as my editor.
I think the most helpful tool for C programmers is a good comprehension of the
language concepts. Any kind of calligraphic effect is only a distraction that
prevent programmers to adopt a good code design.

IMHO the "beauty" of the code doesn't lie in the shape of characters but
similarly to electronic circuits in the efficiency of the architecture.
Robert Wessel
2017-05-11 18:49:33 UTC
Permalink
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
What I find weird is that the position of ' is not verified.
Probably because the world does not use digit group marks
consistently. Convention in India, for example, is to put a mark
before the rightmost group of three digits, but then another before
each additional *pair* of digits. IOW: "12,34,56,789". It also is
common to use groups of size other than three for other bases - groups
of two or four for hex, four for binary. So I suspect the simplest
thing was just to let them be used any way.
Patrick.Schluter
2017-05-11 19:57:21 UTC
Permalink
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Hey, another thing C++ copies from D without attribution (D uses _ to
group digits).
Post by Robert Wessel
Post by Thiago Adams
What I find weird is that the position of ' is not verified.
Probably because the world does not use digit group marks
consistently. Convention in India, for example, is to put a mark
before the rightmost group of three digits, but then another before
each additional *pair* of digits. IOW: "12,34,56,789". It also is
common to use groups of size other than three for other bases - groups
of two or four for hex, four for binary. So I suspect the simplest
thing was just to let them be used any way.
In hex one would prefer to group by 4 or 2 for example.
Keith Thompson
2017-05-11 20:11:28 UTC
Permalink
Post by Patrick.Schluter
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Hey, another thing C++ copies from D without attribution (D uses _ to
group digits).
Ada has done so since 1983, probably earlier. (The first preliminary
Ada standard was published in 1979; I don't remember whether it had
underscores as digit separators.) I don't know whether Ada was the
first language to do something like this, but I doubt it. It's fairly
clearly based on the use of underscores in identifiers, which is
certainly older than that.

The idea of a digit separator is obvious enough that there's no need to
assume it was copied without attribution from some specific language.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Patrick.Schluter
2017-05-11 20:21:30 UTC
Permalink
Post by Keith Thompson
Post by Patrick.Schluter
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Hey, another thing C++ copies from D without attribution (D uses _ to
group digits).
Ada has done so since 1983, probably earlier. (The first preliminary
Ada standard was published in 1979; I don't remember whether it had
underscores as digit separators.) I don't know whether Ada was the
first language to do something like this, but I doubt it. It's fairly
clearly based on the use of underscores in identifiers, which is
certainly older than that.
The idea of a digit separator is obvious enough that there's no need to
assume it was copied without attribution from some specific language.
[...]
The thing is that quite some new features in C++ were inspired by D.
constexpr if being the most obvious one (that one is even provable to be
coming from D's "static if" because it was initially proposed by Walter
Bright and Andrei Alexandrescu for C++0x but rejected and then adopted
later under another name).
Thiago Adams
2017-05-11 20:56:52 UTC
Permalink
On Thursday, May 11, 2017 at 5:21:31 PM UTC-3, Patrick.Schluter wrote:
[...]
Post by Patrick.Schluter
The thing is that quite some new features in C++ were inspired by D.
constexpr if being the most obvious one (that one is even provable to be
coming from D's "static if" because it was initially proposed by Walter
Bright and Andrei Alexandrescu for C++0x but rejected and then adopted
later under another name).
I remember that.
The constexpr if is different from original static if.
I guess (not sure) that the difference is that constexpr must
be a valid code.
And the static if was "walk to the next closing } "

static if could be used for structs.

struct X
{
static if (size(x) == 1)
{
int i;
}
}

static if is similar of #if with compiler information.
But the #if can go anywhere.
David Brown
2017-05-12 10:42:14 UTC
Permalink
Post by Patrick.Schluter
Post by Keith Thompson
Post by Patrick.Schluter
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Hey, another thing C++ copies from D without attribution (D uses _ to
group digits).
Ada has done so since 1983, probably earlier. (The first preliminary
Ada standard was published in 1979; I don't remember whether it had
underscores as digit separators.) I don't know whether Ada was the
first language to do something like this, but I doubt it. It's fairly
clearly based on the use of underscores in identifiers, which is
certainly older than that.
The idea of a digit separator is obvious enough that there's no need to
assume it was copied without attribution from some specific language.
[...]
The thing is that quite some new features in C++ were inspired by D.
constexpr if being the most obvious one (that one is even provable to be
coming from D's "static if" because it was initially proposed by Walter
Bright and Andrei Alexandrescu for C++0x but rejected and then adopted
later under another name).
Even in that case, there is no reason to claim that it "comes from D".
Static or compile-time conditionals are not a fantastic invention of D -
they are an obvious and natural extension of C++'s moves to doing more
work at compile time rather than run time. It's just C pre-processor
#if, modernised to C++. About the only D thing about it is that some D
experts found that feature useful in D, wanted it in C++, and happened
to be in the position to do something about it (unlike the millions of
other C++ programmers who have wanted the same feature for years despite
never having seen D).
Robert Wessel
2017-05-11 20:44:26 UTC
Permalink
Post by Keith Thompson
Post by Patrick.Schluter
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Hey, another thing C++ copies from D without attribution (D uses _ to
group digits).
Ada has done so since 1983, probably earlier. (The first preliminary
Ada standard was published in 1979; I don't remember whether it had
underscores as digit separators.) I don't know whether Ada was the
first language to do something like this, but I doubt it. It's fairly
clearly based on the use of underscores in identifiers, which is
certainly older than that.
I think it dates to (at least) Algol 68, at least in the modes which
support larger character sets.
Ben Bacarisse
2017-05-11 22:13:24 UTC
Permalink
Post by Keith Thompson
Post by Patrick.Schluter
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Hey, another thing C++ copies from D without attribution (D uses _ to
group digits).
Ada has done so since 1983, probably earlier. (The first preliminary
Ada standard was published in 1979; I don't remember whether it had
underscores as digit separators.)
I have an Ada Reference Manual (in book form) dated 1980. I think it is
the first but it certainly includes digit separators.

<snip>
--
Ben.
Scott Lurndal
2017-05-12 16:16:02 UTC
Permalink
Post by Patrick.Schluter
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Hey, another thing C++ copies from D without attribution (D uses _ to
group digits).
Using grouping characters is much older than D. Verilog, for example,
uses _ to group digits.
David Brown
2017-05-12 10:35:59 UTC
Permalink
Post by Robert Wessel
On Thu, 11 May 2017 05:07:17 -0700 (PDT), Thiago Adams
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
What I find weird is that the position of ' is not verified.
Probably because the world does not use digit group marks
consistently. Convention in India, for example, is to put a mark
before the rightmost group of three digits, but then another before
each additional *pair* of digits. IOW: "12,34,56,789". It also is
common to use groups of size other than three for other bases - groups
of two or four for hex, four for binary. So I suspect the simplest
thing was just to let them be used any way.
Also, you may well have other reasons for wanting to pick different
grouping, such as 2017'05'12 for writing a date as an integer.
Richard Heathfield
2017-05-12 10:41:29 UTC
Permalink
On 12/05/17 11:35, David Brown wrote:
<snip>
Post by David Brown
Also, you may well have other reasons for wanting to pick different
grouping, such as 2017'05'12 for writing a date as an integer.
Why not just write it as 2457886 ?
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
David Brown
2017-05-12 15:27:46 UTC
Permalink
Post by Ben Bacarisse
<snip>
Post by David Brown
Also, you may well have other reasons for wanting to pick different
grouping, such as 2017'05'12 for writing a date as an integer.
Why not just write it as 2457886 ?
I am afraid I can't figure that one out. You'll have to give me a hint.
Robert Wessel
2017-05-12 15:57:21 UTC
Permalink
On Fri, 12 May 2017 17:27:46 +0200, David Brown
Post by David Brown
Post by Ben Bacarisse
<snip>
Post by David Brown
Also, you may well have other reasons for wanting to pick different
grouping, such as 2017'05'12 for writing a date as an integer.
Why not just write it as 2457886 ?
I am afraid I can't figure that one out. You'll have to give me a hint.
It's today's Julian day number.
j***@gmail.com
2017-05-12 13:55:17 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
C++ 17, has now a new if.
[...]
Single-Quotation-Mark as a Digit Separator
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
int i = 1'000'000;
Comma (US and, I think, UK), period (some parts of Europe), and space
have other meaning in C.
Post by Thiago Adams
What I find weird is that the position of ' is not verified.
Well, it's mostly decoration, kind of like syntactic sugar.
Post by Thiago Adams
"An integer literal is a sequence of digits that has no period or exponent part, with optional
separating single quotes that are ignored when determining its value"
There are contexts in which you might prefer other groupings

These might be useful for reference, from Wikipedia:

https://en.wikipedia.org/wiki/Integer_literal#Digit_separators

https://en.wikipedia.org/wiki/Decimal_mark#Digit_grouping

https://en.wikipedia.org/wiki/Indian_numbering_system#Use_of_separators

--
Joel Rees

Delusions of being a novelist:
http://reiisi.blogspot.com/p/novels-i-am-writing.html
Loading...