Discussion:
Default initialization list {default}
(too old to reply)
Thiago Adams
2016-09-29 16:51:28 UTC
Permalink
I have a suggestion to add into the C language.
How to submit this suggestion for the standard?


Basically is to add {default} initialization:

struct X x = {default};

It differ from {} because we can define what is default.


How?

In enuns:

enum E {default A, B};

In structs/unions

struct Z
{
_Bool b = true;
};

struct X
{
enum E e;
void (*F)(); //NULL by default
int * p; //NULL by default
int n; //0 by default
int i = 1;
struct Point { int x = 0; int y = 0; } point;
struct Z z;
};



Then:

struct X x = {default};

is equivalent to:

struct X x = {A, NULL, NULL, 0, 1, {0,0}, true };

the compiler will generate this initialization for us
{A , NULL, 0, 1, {0,0}, true }

(struct X) {default}
also works
Kaz Kylheku
2016-09-29 17:15:04 UTC
Permalink
Post by Thiago Adams
(struct X) {default}
also works
I would just make it

x = default;

and allow:

x = default { ... }

i.e. allow it to be followed by an ordinary initializer which
overrides the defaults.

struct X x = default {B, .i = 2}

then generates:

{B , NULL, 0, 2, {0,0}, true }

and of course non-constant expressions can be used.

Under this syntax, it it is easier to blend a #define-d initializer
that excludes "default" with default:

#default X_INITIALIZER { ... }

struct X x = default X_INITIALIZER;

if default has to go into the braces, we have extra work.

Something more general would be to allow multiple braced initializers,
any of which may be "default":

struct X x = { whatever } default { whatever else };

each initializer establishes values for those members which are
not overridden by later initializers to the right. (However, all
non-constant initializing expressions are evaluated, whether or not they
are used, and let there be a darned sequence point between successive
elements in this sequence.
--
TXR Programming Lanuage: http://nongnu.org/txr
Music DIY Mailing List: http://www.kylheku.com/diy
ADA MP-1 Mailing List: http://www.kylheku.com/mp1
Thiago Adams
2016-09-29 17:21:17 UTC
Permalink
Post by Kaz Kylheku
Post by Thiago Adams
(struct X) {default}
also works
I would just make it
x = default;
x = default { ... }
i.e. allow it to be followed by an ordinary initializer which
overrides the defaults.
struct X x = default {B, .i = 2}
{B , NULL, 0, 2, {0,0}, true }
and of course non-constant expressions can be used.
Under this syntax, it it is easier to blend a #define-d initializer
#default X_INITIALIZER { ... }
struct X x = default X_INITIALIZER;
if default has to go into the braces, we have extra work.
Something more general would be to allow multiple braced initializers,
struct X x = { whatever } default { whatever else };
each initializer establishes values for those members which are
not overridden by later initializers to the right. (However, all
non-constant initializing expressions are evaluated, whether or not they
are used, and let there be a darned sequence point between successive
elements in this sequence.
I agree. It's even better.
How can we move with this suggestion?
Kaz Kylheku
2016-09-29 18:10:22 UTC
Permalink
Post by Thiago Adams
I agree. It's even better.
How can we move with this suggestionait
Hack it into GCC as a GNU C dialect feature.

Because this introduces an interpretation to what is now bad syntax,
it's a conforming extension, provided a diagnostic is emitted.
You can arrange so that only "gcc -pedantic" warns when it is used.
Thiago Adams
2016-09-29 20:25:56 UTC
Permalink
Post by Kaz Kylheku
Post by Thiago Adams
(struct X) {default}
also works
I would just make it
x = default;
And how about to make it invisible?

struct X
{
int x = 1;
int y = 2;
};

X x;
//x.x == 1, x.y == 2

This code would be "C/C++" at the same time.


Maybe an option to turn it off.

X x = void;
Thiago Adams
2016-09-30 11:35:18 UTC
Permalink
Post by Kaz Kylheku
Post by Thiago Adams
(struct X) {default}
also works
I would just make it
x = default;
x = default { ... }
i.e. allow it to be followed by an ordinary initializer which
overrides the defaults.
struct X x = default {B, .i = 2}
And how about?
struct X x = {default, B, .i = 2}

and then

struct { default, .other = {default, .other2 = 1} }
Thiago Adams
2016-11-21 13:19:18 UTC
Permalink
Post by Thiago Adams
Post by Kaz Kylheku
Post by Thiago Adams
(struct X) {default}
also works
I would just make it
x = default;
x = default { ... }
i.e. allow it to be followed by an ordinary initializer which
overrides the defaults.
struct X x = default {B, .i = 2}
And how about?
struct X x = {default, B, .i = 2}
and then
struct { default, .other = {default, .other2 = 1} }
I still considering the possibilities and I think the syntax should be the normal {}.


struct X
{
int x;
int y;
};

struct X x = {}; //x ==0 ,y ==0


struct X
{
int x = 1;
int y = 2;
};

struct X x = {}; //x ==1 ,y ==2


struct X
{
int x = 1;
int y = 2;
};

struct X x; //initialization not used
BartC
2016-11-21 14:24:54 UTC
Permalink
Post by Thiago Adams
I still considering the possibilities and I think the syntax should be the normal {}.
struct X
{
int x;
int y;
};
struct X x = {}; //x ==0 ,y ==0
struct X
{
int x = 1;
int y = 2;
};
struct X x = {}; //x ==1 ,y ==2
struct X
{
int x = 1;
int y = 2;
};
struct X x; //initialization not used
I think you may be overloading X and x a little!

I haven't followed the thread so maybe the following observations have
already been made.

You define a struct with default values for elements, but then allow a
struct instance to be created without initialisation. That is, with
undefined values. That would make the definition a little misleading.

But, where someone does want to implicitly initialise such a struct to
its default values (where the actual values may be hidden away in a
header or behind conditional macros), how does it work here:

struct X x[1000] = {};

Will all 1000 structs be initialised to 1,2? Suppose the values are
constant expressions defined earlier on; could those values be different
in different modules?

Can values be normal runtime expressions? (In which case, what happens
in the array example above when one of the values is rand(); are all
values the same, or different?)

Take this new struct:

struct Z
{
struct X a,b,c,d,e;
}

Will this initialise those X structs:

struct Z z = {};
struct z a[1000] = {};

How about:

struct Z z = {{},,,{}};

Will only .a and .d be initialised?

What about this:

struct X x = malloc(sizeof(x));

How do I initialised x to the default values of struct X?

What happens when a struct has 100 elements and only 7 of those elements
have initial values?
--
Bartc
BartC
2016-11-21 14:33:39 UTC
Permalink
Post by BartC
struct X x = malloc(sizeof(x));
How do I initialised x to the default values of struct X?
That should be struct X* x and *x.
Thiago Adams
2016-11-21 16:06:30 UTC
Permalink
Post by BartC
Post by Thiago Adams
I still considering the possibilities and I think the syntax should be the normal {}.
struct X
{
int x;
int y;
};
struct X x = {}; //x ==0 ,y ==0
struct X
{
int x = 1;
int y = 2;
};
struct X x = {}; //x ==1 ,y ==2
struct X
{
int x = 1;
int y = 2;
};
struct X x; //initialization not used
I think you may be overloading X and x a little!
I haven't followed the thread so maybe the following observations have
already been made.
You define a struct with default values for elements, but then allow a
struct instance to be created without initialisation. That is, with
undefined values. That would make the definition a little misleading.
Default values may be used, if the default-initialization {} is used.

Point pt = {3 , 4} //other initialization
Point pt = {}; //default initializers used
Point pt; //not used

They initializes are not something intrinsically associated with each instance of the type.
Post by BartC
But, where someone does want to implicitly initialise such a struct to
its default values (where the actual values may be hidden away in a
struct X x[1000] = {};
Will all 1000 structs be initialised to 1,2?
Yes, otherwise you can do:
struct X x[1000] ;

Suppose the values are
Post by BartC
constant expressions defined earlier on; could those values be different
in different modules?
I didn't understand the question.
But if the compiler finds two definitions of the struct with different values then the programmer did a mistake. I guess each translation unit will use the struct it found.
Post by BartC
Can values be normal runtime expressions? (In which case, what happens
in the array example above when one of the values is rand(); are all
values the same, or different?)
At the struct definition only constant expressions.
Post by BartC
struct Z
{
struct X a,b,c,d,e;
}
struct Z z = {};
struct z a[1000] = {};
struct Z z = {{},,,{}};
Will only .a and .d be initialised?
Everything.
Post by BartC
struct X* x = malloc(sizeof(*x));
How do I initialised x to the default values of struct X?
What happens when a struct has 100 elements and only 7 of those elements
have initial values?
This case is not covered.
This would require a "new" operator that does:

X * x = malloc(sizeof *x);
if (x) *x = (X){};

X * x = new X;

The new operator would also require some type-associated custom memory allocator. Or the custom allocation would have to be optionally provided.

X * x = new (_MyCustomAllocator) X;

--

I will put the motivation again:

I think the best way to initialize structs is using a macro "init".
This is how my code looks today:

struct Point { int x; int y; };
#define POINT_INIT { 0, 0 }

struct Line
{
struct Point start;
struct Point end;
};
#define LINE_INIT { POINT_INIT, POINT_INIT }

With this feature I would remove these macros.
BartC
2016-11-21 21:35:03 UTC
Permalink
Post by Thiago Adams
Post by BartC
Post by Thiago Adams
struct X
{
int x = 1;
int y = 2;
};
struct X x; //initialization not used
You define a struct with default values for elements, but then allow a
struct instance to be created without initialisation. That is, with
undefined values. That would make the definition a little misleading.
I think the best way to initialize structs is using a macro "init".
struct Point { int x; int y; };
#define POINT_INIT { 0, 0 }
struct Line
{
struct Point start;
struct Point end;
};
#define LINE_INIT { POINT_INIT, POINT_INIT }
With this feature I would remove these macros.
Well it would be done like this (sans struct tags as I don't like those):

typedef struct {int x,y;} Point;
Point point_init = {0,0};

Point origin = point_init;

which you propose to replace with:

typedef struct {int x = 0, y = 0;} Point;

Point origin = {};

But with the problems that have been suggested, where a Point instance
might be thought to be initialised when it isn't. Also that {} doesn't
really suggest a default; a keyword is better, but then that's not far
off using 'point_init'.

Also, with 'point_init', this allows the defaults, or selected parts of
the defaults, to picked up anywhere.

When it comes to a Line struct, that runs into problems with the current
method:

typedef struct {Point p,q;} Line;
Line line_init = {point_init, point_init};

because 'point_init' is not a compile-type expression. But wouldn't that
also be a problem with your proposal:

typedef struct {Point p = point_init, q = point_init;} Line;

As you said initialisers must be constant expressions?
--
Bartc
Thiago Adams
2016-11-22 10:56:52 UTC
Permalink
Post by BartC
Post by Thiago Adams
Post by BartC
Post by Thiago Adams
struct X
{
int x = 1;
int y = 2;
};
struct X x; //initialization not used
You define a struct with default values for elements, but then allow a
struct instance to be created without initialisation. That is, with
undefined values. That would make the definition a little misleading.
I think the best way to initialize structs is using a macro "init".
struct Point { int x; int y; };
#define POINT_INIT { 0, 0 }
struct Line
{
struct Point start;
struct Point end;
};
#define LINE_INIT { POINT_INIT, POINT_INIT }
With this feature I would remove these macros.
typedef struct {int x,y;} Point;
Point point_init = {0,0};
Point origin = point_init;
typedef struct {int x = 0, y = 0;} Point;
Point origin = {};
But with the problems that have been suggested, where a Point instance
might be thought to be initialised when it isn't. Also that {} doesn't
really suggest a default; a keyword is better, but then that's not far
off using 'point_init'.
The syntax could be = {default}, = default
Post by BartC
Also, with 'point_init', this allows the defaults, or selected parts of
the defaults, to picked up anywhere.
When it comes to a Line struct, that runs into problems with the current
typedef struct {Point p,q;} Line;
Line line_init = {point_init, point_init};
because 'point_init' is not a compile-type expression. But wouldn't that
typedef struct {Point p = point_init, q = point_init;} Line;
As you said initialisers must be constant expressions?
The problem with point_init variables are many.
You cannot compose and you have to type more because you need a declaration and instantiation of the variable.
Because of these problems I use MACRO_INIT in my code.

More specifically, an initializer it not a constant expression.
It should be another initializer.

Sample:

struct Point
{
int x =1;
int y =2;
};

struct Line
{
struct Point start;
struct Point end = {.x = 3 , .y = 4};
};

Some options for syntax

//visible initialization

struct Line line = {};
struct Line line = {...};
struct Line line = {auto};
struct Line line = {default};
struct Line line = default;
struct Line line = {{default}, {default}};
struct Line line = {default, default};



//disable the end initialization
struct Line line = {{.x = 1, .y = 2}, {void}};


struct Line line = {void};
struct Line line = void;

//hidden initialization
struct Line line;


But, I'm not sure if dynamic initialization should be allowed.

I think one simple rule can be created.
The rule is : The compiler does a copy paste from the struct variable initializer into the point of instantiation.

Empty initializer will use zero.


struct Point
{
int x =1;
int y =2;
};

struct Line
{
struct Point start;
struct Point end = {.x = 3 , .y = 4};
};

struct Line line = {default};
What it does? Just copy and paste the initializers
struct Line line = {{.x = 1, .y = 2}, .x = 3, .y = 4};


This idea already have a hidden initialization
See "start"

struct Line
{
struct Point start;
struct Point end = {.x = 3 , .y = 4};
};

So, one option could be

struct Line
{
struct Point start = {default};
struct Point end = {.x = 3 , .y = 4};
};


The another option could be just accept hidden initializers.

struct Line
{
struct Point start;
struct Point end = {.x = 3 , .y = 4};
};

//both line.start and line are using hidden initialization
struct Line line;

The thirty option could be allow hidden only inside the struct.
Kaz Kylheku
2016-11-21 16:31:50 UTC
Permalink
Post by Thiago Adams
struct X
{
int x = 1;
int y = 2;
};
struct X x; //initialization not used
I would say, misfeature. If the struct has this extension,
initialization should always be used.

Just like in C++, when a constructor is defined on a struct,
it is then constructed via that constructor.

The unsafe behavior of not initializing should
occur only for classic C struct types not defined with this
syntax, or else there should be some special initializer
which explicitly suppresses the use of the default initializers.

struct X x = void; // suppress use of initializers

at file scope this means all zeros, and in automatic
storage, it means uninitialied; i.e. traditional C behavior.

Otherwise what you're doing is deliberately ignoring
the initialization that the programmer clearly requested
by adding = 1 and = 2.

The request to have the object initialized should not
have to be repeated in two or more places in order
to be honored.

Morons have to be given a request two or more times before
it sinks in; don't make the language into a moron.
Thiago Adams
2016-11-21 17:19:21 UTC
Permalink
Post by Kaz Kylheku
Post by Thiago Adams
struct X
{
int x = 1;
int y = 2;
};
struct X x; //initialization not used
I would say, misfeature. If the struct has this extension,
initialization should always be used.
Just like in C++, when a constructor is defined on a struct,
it is then constructed via that constructor.
The unsafe behavior of not initializing should
occur only for classic C struct types not defined with this
syntax, or else there should be some special initializer
which explicitly suppresses the use of the default initializers.
struct X x = void; // suppress use of initializers
at file scope this means all zeros, and in automatic
storage, it means uninitialied; i.e. traditional C behavior.
Otherwise what you're doing is deliberately ignoring
the initialization that the programmer clearly requested
by adding = 1 and = 2.
The request to have the object initialized should not
have to be repeated in two or more places in order
to be honored.
Morons have to be given a request two or more times before
it sinks in; don't make the language into a moron.
I not sure about this.
The good thing it would not break existing code , because the existing code doesn't have initializers.

But if you add initilizers in existing code then you have to review all instantiations.

Z z;
// not necessary anymore because someone add initialization
z.i = 1;

When reviewing a new code:

Z z;
printf("%d", z.i); //is z initialized?


Z z = {};
printf("%d", z.i); //ok, without to see Z , unless i is not an int.
Hans-Bernhard Bröker
2016-11-21 19:24:06 UTC
Permalink
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type

struct X x = {};

?
Thiago Adams
2016-11-21 19:37:36 UTC
Permalink
Post by Hans-Bernhard Bröker
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type
struct X x = {};
?
The behavior of previous code will not change, unless someone add a initializer inside the struct X.
Keith Thompson
2016-11-21 19:40:56 UTC
Permalink
Post by Hans-Bernhard Bröker
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type
struct X x = {};
?
Because it's a syntax error?

Though it is supported as an extension by gcc, and perhaps by some other
compilers.
--
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"
Hans-Bernhard Bröker
2016-11-21 20:35:58 UTC
Permalink
Post by Keith Thompson
Post by Hans-Bernhard Bröker
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type
struct X x = {};
?
Because it's a syntax error?
Ah yes, right. Sorry for the confusion.

But still, treating '{}' differently from an absent initalizer would
create even more confusion. E.g. what about

struct X {
int i=5;
}

struct Y {
int j;
struct X s;
}

struct Y y = {0};

Would this initialize y.s.i to 5, or to 0? And why?
Thiago Adams
2016-11-22 11:10:31 UTC
Permalink
Post by Hans-Bernhard Bröker
Post by Keith Thompson
Post by Hans-Bernhard Bröker
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type
struct X x = {};
?
Because it's a syntax error?
Ah yes, right. Sorry for the confusion.
But still, treating '{}' differently from an absent initalizer would
create even more confusion. E.g. what about
struct X {
int i=5;
}
struct Y {
int j;
struct X s;
}
struct Y y = {0};
Would this initialize y.s.i to 5, or to 0? And why?
struct Y y = {0};

Same of


struct Y y = { .j = 0 , .s = { .i = 5 }};

Why?
I think the copy-paste-initializer rule can be simple.
Thiago Adams
2016-11-23 11:24:20 UTC
Permalink
Post by Hans-Bernhard Bröker
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type
struct X x = {};
?
The other reason for {} syntax is because it's already valid in C++.

#include <iostream>

using namespace std;

struct Point
{
int x = 1;
int y = 2;
};

int main()
{
//Point pt = {}; //ok
//Point pt{}; //ok
Point pt; //ok


Point pt = {1, 2}; //not ok
/*
could not convert '{1, 2}' from '<brace-enclosed initializer list>' to 'Point'
*/

//Point pt {1, 2}; //not ok

cout << " " << pt.x << " " << pt.y << endl;

return 0;
}
Thiago Adams
2016-11-22 11:36:46 UTC
Permalink
Post by Hans-Bernhard Bröker
Post by Keith Thompson
Post by Hans-Bernhard Bröker
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type
struct X x = {};
?
Because it's a syntax error?
Ah yes, right. Sorry for the confusion.
But still, treating '{}' differently from an absent initalizer would
create even more confusion. E.g. what about
I think all the possibilities should be considered with no rush.
The first target should be made the designated initializers simple and general.

For me, it's clear that the default initialization is something related with the type. In most cases we will not initialize the variable by instance basis.

StringStream stream = {.pos = 0, .line = 0, .col = 0 ....etc}

It's clear that many variables of the type StringStream will have the same initialization. So the default values is something you want to put together with the type definition.
The best current approach in my view is to use a macro. So many of the facilities of designed initializers are hidden. Having a designated initializer is also to avoid bugs, but the initialization together with the variable is even safer and easy to maintain,

typedef struct { ..... } StringStream;
#define STRING_STREAM_INIT { ... }

With the default initializer suggestion we just add a little job to the compiler and the result is the simplification and safe code (no mistaken initialization)

I also think other options should be considered.

For instance, give the enum the default value.

enum E { default A = 1 , B, C};

enum E e; //A
enum E e = {default}; //more explicit alternative

struct X
{
enum E e; //A
};

This one is less useful

typedef int Line = 1;
James R. Kuyper
2016-11-21 19:41:03 UTC
Permalink
Post by Hans-Bernhard Bröker
Post by Thiago Adams
The good thing it would not break existing code , because the existing code doesn't have initializers.
What makes you think existing code has no lines of the type
struct X x = {};
The fact that it's a syntax error. The grammar for an initializer is
(6.7.9p1):

initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }

initializer-list:
designationopt initializer
initializer-list , designationopt initializer

Brackets are allowed in an initializer only if they contain an
initializer list, and initializer lists must always contain at least one
initializer.
Thiago Adams
2017-07-10 17:23:44 UTC
Permalink
On Monday, November 21, 2016 at 11:19:21 AM UTC-2, Thiago Adams wrote:

[...]
Post by Thiago Adams
I still considering the possibilities and I think the syntax should be the normal {}.
struct X
{
int x;
int y;
};
struct X x = {}; //x ==0 ,y ==0
struct X
{
int x = 1;
int y = 2;
};
struct X x = {}; //x ==1 ,y ==2
struct X
{
int x = 1;
int y = 2;
};
struct X x; //initialization not used
I realize one detail about the data member initialization.
Using designated initializers we can use non constant expressions.

So the design question is if struct member initializer should allow
non constant initializers or not?

struct Point
{
int i = f();
};


int main() {
struct Point point = {};
//same as
//struct Point point = { .i = f() };
//or compile error?
}

In my opinion it's safer and more explicit if the struct data member initialization allows only constant initialization.

I have implemented a compiler that generates C code to test.



Tim Rentsch
2016-09-30 17:01:14 UTC
Permalink
Post by Thiago Adams
I have a suggestion to add into the C language.
How to submit this suggestion for the standard?
If you want to have a chance of getting something accepted,
you should:

One: decide in detail what you want the feature to be;

Two: get the feature working solidly in some C compiler (ie,
as an extension);

Three: get a fair-sized group of people using the feature in
actual code, and iterate back to One based on their
feedback; and then

Four: after the above steps are complete, get in touch with
one of the main contacts for WG14, and ask them how
you should go about submitting a proposal for a language
addition.
jacob navia
2016-10-12 21:00:05 UTC
Permalink
Post by Thiago Adams
I have a suggestion to add into the C language.
How to submit this suggestion for the standard?
struct X x = {default};
It differ from {} because we can define what is default.
How?
enum E {default A, B};
In structs/unions
struct Z
{
_Bool b = true;
};
struct X
{
enum E e;
void (*F)(); //NULL by default
int * p; //NULL by default
int n; //0 by default
int i = 1;
struct Point { int x = 0; int y = 0; } point;
struct Z z;
};
struct X x = {default};
struct X x = {A, NULL, NULL, 0, 1, {0,0}, true };
the compiler will generate this initialization for us
{A , NULL, 0, 1, {0,0}, true }
(struct X) {default}
also works
struct X
{
enum E e;
void (*F)(); //NULL by default
int * p; //NULL by default
int n; //0 by default
int i = 1;
struct Point { int x = 0; int y = 0; } point;
struct Z z;
};
Then you add:

Struct x DefaultX = {A, NULL, NULL, 0, 1, {0,0}, true };

Then:

int main(void) {
Struct X x = DefaultX;

you see?

The same effect without any language extensions. Now, any language
extension can repeat another construct, in principle your extension
should work too.

There is a need to make useful sentences use standard abreviations, for
instance. Language extensions aren't a bad idea. For instance we could
say that any program writing:

#include <stdheaders.h>

should be preloaded with all headers that are defined in the C language
standard. All standard vocabulary should be preloaded (if the user
wishes of course, since he writes or not that sentence)

But that is a different kind of language extension.

You can do the same thing with the pre-processor, by the way:

#define DefaultX {A, NULL, NULL, 0, 1, {0,0}, true }

Note that the preprocessor could generate several copies unless the
compiler realizes that all those DefaultX are the same and optimizes
space. If you use the C language version above, you avoid that possible
pitfall and you make things clearer.

Using default values
--------------------

Using the code above (either the proposed extension or the existing C
solution), we can setup the initial value for any structure we want. The
compiler will generate code to copy the initial value of the structure
from a defined address.

What if you want to start some code at startup of the structure? Using
allocation, for instance could be one of the things you would like to
see done.

You replace the copy by a function call, for instance. Whatever fits
your needs. C is a rich language, you can do what you want.
Jakob Bohm
2016-10-13 16:18:39 UTC
Permalink
Post by jacob navia
Post by Thiago Adams
I have a suggestion to add into the C language.
How to submit this suggestion for the standard?
struct X x = {default};
It differ from {} because we can define what is default.
How?
enum E {default A, B};
In structs/unions
struct Z
{
_Bool b = true;
};
struct X
{
enum E e;
void (*F)(); //NULL by default
int * p; //NULL by default
int n; //0 by default
int i = 1;
struct Point { int x = 0; int y = 0; } point;
struct Z z;
};
struct X x = {default};
struct X x = {A, NULL, NULL, 0, 1, {0,0}, true };
the compiler will generate this initialization for us
{A , NULL, 0, 1, {0,0}, true }
(struct X) {default}
also works
struct X
{
enum E e;
void (*F)(); //NULL by default
int * p; //NULL by default
int n; //0 by default
int i = 1;
struct Point { int x = 0; int y = 0; } point;
struct Z z;
};
Struct x DefaultX = {A, NULL, NULL, 0, 1, {0,0}, true };
int main(void) {
Struct X x = DefaultX;
Note that this is subtly different from having a language construct for
a nonzero default constant initializer. The code you propose does a
dynamic copy from a global variable (which would probably be declared
const), whereas the proposal directs the compiler to initialize x
inline using constants.

Your define alternative below is more closely equivalent to the
proposal, and is the traditional way to do this.

What is missing from both your alternatives is a way to do the
following:

static const struct X y = { default, i:2 };

Which would (in most implementations) place the resulting slightly
non-default structure value y in a read-only shareable memory area,
rather than a writable memory area. This could potentially be done
with less convenient constructs like this:

#define DefaultX_i(i) {A, NULL, NULL, 0, i, {0,0}, true }
#define DefaultX DefaultX(1)

static const struct X y = DefaultX_i(2);
Post by jacob navia
you see?
The same effect without any language extensions. Now, any language
extension can repeat another construct, in principle your extension
should work too.
...
#define DefaultX {A, NULL, NULL, 0, 1, {0,0}, true }
Note that the preprocessor could generate several copies unless the
compiler realizes that all those DefaultX are the same and optimizes
space. If you use the C language version above, you avoid that possible
pitfall and you make things clearer.
Using default values
--------------------
Using the code above (either the proposed extension or the existing C
solution), we can setup the initial value for any structure we want. The
compiler will generate code to copy the initial value of the structure
from a defined address.
What if you want to start some code at startup of the structure? Using
allocation, for instance could be one of the things you would like to
see done.
You replace the copy by a function call, for instance. Whatever fits
your needs. C is a rich language, you can do what you want.
Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
jacob navia
2016-10-13 21:24:29 UTC
Permalink
Post by Jakob Bohm
Note that this is subtly different from having a language construct for
a nonzero default constant initializer. The code you propose does a
dynamic copy from a global variable (which would probably be declared
const), whereas the proposal directs the compiler to initialize x
inline using constants.
Look, sometimes is better to generate
mov $35,SomeAddres+0
mov $57,SomeAddress+4

etc...

Than
memcpy(dst,src)

or even an inline version of memcpy.

I do always a dynamic copy, since it is less instructions and maybe
faster, it depends on the structure length.

From a software point of view, this is not that important. Now, if you
want to do a modified default (all values by default except this one)
you can write a corresponding function that makes a copy of the default
and modifies one field, before returning the result upwards.

You can chain any number of functions that way. And with today's
machines, that is surely not really a bottleneck.
Jakob Bohm
2016-10-13 21:43:14 UTC
Permalink
Post by jacob navia
Post by Jakob Bohm
Note that this is subtly different from having a language construct for
a nonzero default constant initializer. The code you propose does a
dynamic copy from a global variable (which would probably be declared
const), whereas the proposal directs the compiler to initialize x
inline using constants.
Look, sometimes is better to generate
mov $35,SomeAddres+0
mov $57,SomeAddress+4
etc...
Than
memcpy(dst,src)
or even an inline version of memcpy.
I do always a dynamic copy, since it is less instructions and maybe
faster, it depends on the structure length.
From a software point of view, this is not that important. Now, if you
want to do a modified default (all values by default except this one)
you can write a corresponding function that makes a copy of the default
and modifies one field, before returning the result upwards.
You can chain any number of functions that way. And with today's
machines, that is surely not really a bottleneck.
Did you understand my other comments about constness of the initialized
structure?

Do you understand the difference between an actual static const object
and a const pointer to some java-style dynamically initialized object?

Do you understand the execution order difference between constant
initialization of (non necessarily const) objects of static duration,
and calculated dynamic initialization of such objects?

Those are things that matter in complex programs, in programs that want
the security benefit of hardware enforced constness, and in memory-
constrained systems such as microcontrollers.

Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
jacob navia
2016-10-14 09:50:58 UTC
Permalink
Post by Jakob Bohm
Did you understand my other comments about constness of the initialized
structure?
The source default structure could be made const. Great, and even I can
understand that.

But maybe not, if you want to modify the default according to some
program state, for instance.

So what?
Post by Jakob Bohm
Do you understand the difference between an actual static const object
and a const pointer to some java-style dynamically initialized object?
Some compilers will generate a copy when you write:

void fn(void)
{
Struct X x = { ... };

some others will not and generate a series of move instructions. So
what? And please stop it with nonsense comments about java! What has
java to do here?
Post by Jakob Bohm
Do you understand the execution order difference between constant
initialization of (non necessarily const) objects of static duration,
and calculated dynamic initialization of such objects?
As I told you before that difference is completely negligible in todays
machines. My Raspberry pi 3 has a 64 bit CPU and 1G RAM. Note that a
copy is much faster than memberwise initialization if the structure is
large.
Post by Jakob Bohm
Those are things that matter in complex programs, in programs that want
the security benefit of hardware enforced constness, and in memory-
constrained systems such as microcontrollers.
Sure. If your application requires it, use ROM. So what? I do not see
how it makes a difference in other applications that run in embedded
systems of today where those considerations have little importance.
Post by Jakob Bohm
Enjoy
Difficult to enjoy your answers since you take a patronizing tone that
is difficult to deal with.
Post by Jakob Bohm
Jakob
Jakob Bohm
2016-10-14 11:31:07 UTC
Permalink
Post by jacob navia
Post by Jakob Bohm
Did you understand my other comments about constness of the initialized
structure?
The source default structure could be made const. Great, and even I can
understand that.
But maybe not, if you want to modify the default according to some
program state, for instance.
So what?
Post by Jakob Bohm
Do you understand the difference between an actual static const object
and a const pointer to some java-style dynamically initialized object?
void fn(void)
{
Struct X x = { ... };
some others will not and generate a series of move instructions. So
what? And please stop it with nonsense comments about java! What has
java to do here?
Post by Jakob Bohm
Do you understand the execution order difference between constant
initialization of (non necessarily const) objects of static duration,
and calculated dynamic initialization of such objects?
As I told you before that difference is completely negligible in todays
machines. My Raspberry pi 3 has a 64 bit CPU and 1G RAM. Note that a
copy is much faster than memberwise initialization if the structure is
large.
For objects of static duration, most C compilers will generate the
structure at compile time and put the initial value directly in the
program file, either in the writable data segment or the read-only data
segment. This applies to just about any architecture that has any kind
of memory protection, such as x86 (except real mode DOS), x64, ARM,
MIPS etc. etc. This is a basic feature of most program file formats
such as ELF, COFF, Mach, PE, NE, LX etc.
Post by jacob navia
Post by Jakob Bohm
Those are things that matter in complex programs, in programs that want
the security benefit of hardware enforced constness, and in memory-
constrained systems such as microcontrollers.
Sure. If your application requires it, use ROM. So what? I do not see
how it makes a difference in other applications that run in embedded
systems of today where those considerations have little importance.
Again, not just talking about ROM, but also about the fact that most
modern big OSes (Linux, Windows, Mac OS, etc.) load the read-only data
section as a simple read-only mmap() of the relevant part of the
program file, while the writable data section is either copied to
per-process memory of made as a copy-on-write mmap(). The hardware
enforcement is done by the CPUs memory management hardware, which is
controlled by the OS.
Post by jacob navia
Post by Jakob Bohm
Enjoy
Difficult to enjoy your answers since you take a patronizing tone that
is difficult to deal with.
Your post completely missed the point. That's why I answered like that.


Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
s***@casperkitty.com
2016-10-14 14:27:40 UTC
Permalink
Post by Jakob Bohm
For objects of static duration, most C compilers will generate the
structure at compile time and put the initial value directly in the
program file, either in the writable data segment or the read-only data
segment. This applies to just about any architecture that has any kind
of memory protection, such as x86 (except real mode DOS), x64, ARM,
MIPS etc. etc. This is a basic feature of most program file formats
such as ELF, COFF, Mach, PE, NE, LX etc.
One advantage of the older (<4.0) real-mode DOS Turbo Pascal was that they
would put constant data in the code segment rather than the data segment.
Since there was a significant cost adder for accessing anything that isn't
in the code segment, primary data segment, or stack segment, small programs
could sometimes get a big performance boost by keeping some of their tables
out of the data segment. I've never seen a C compiler for the PC that could
take advantage of data accessible using the code-segment register, however.
Kaz Kylheku
2016-10-14 15:11:31 UTC
Permalink
Post by jacob navia
some others will not and generate a series of move instructions. So
what? And please stop it with nonsense comments about java! What has
java to do here?
Java is relevant if features are proposed which resemble Java semantics,
because it contributes a field-tested implementation model (or perhaps
more than one) for those features. Some aspects of that model or its
ramifications could be valid in a different context.
Thiago Adams
2016-10-14 11:53:00 UTC
Permalink
Post by jacob navia
Post by Thiago Adams
I have a suggestion to add into the C language.
How to submit this suggestion for the standard?
struct X x = {default};
It differ from {} because we can define what is default.
How?
enum E {default A, B};
In structs/unions
struct Z
{
_Bool b = true;
};
struct X
{
enum E e;
void (*F)(); //NULL by default
int * p; //NULL by default
int n; //0 by default
int i = 1;
struct Point { int x = 0; int y = 0; } point;
struct Z z;
};
struct X x = {default};
struct X x = {A, NULL, NULL, 0, 1, {0,0}, true };
the compiler will generate this initialization for us
{A , NULL, 0, 1, {0,0}, true }
(struct X) {default}
also works
struct X
{
enum E e;
void (*F)(); //NULL by default
int * p; //NULL by default
int n; //0 by default
int i = 1;
struct Point { int x = 0; int y = 0; } point;
struct Z z;
};
Struct x DefaultX = {A, NULL, NULL, 0, 1, {0,0}, true };
int main(void) {
Struct X x = DefaultX;
you see?
I am using the MACRO_INIT.

Without a macro we lose the ability to compose

struct Point { int x; int y; };
#define POINT_INIT { 0, 0 }
const struct Point POINT_INIT2 = { 0.0 };

struct Line
{
struct Point start;
struct Point end;
};
#define LINE_INIT { POINT_INIT, POINT_INIT } //ok
const struct Line LINE_INIT2 = { POINT_INIT2, POINT_INIT2 }; //ERROR

I think the solution proposed would be better than macro because:

- You have a good place to initialize.
If you delete the variable from struct you don't need to update the macro init.
- You save a macro name
- You give compiler information associated with the type
- The compiler will compose the DEFAULT_INIT for you. Less code to see.

The implementation doesn't seems difficult to do, but I don't have any experience in modify the GCC compiler.
luserdroog
2016-11-21 18:58:41 UTC
Permalink
Post by Thiago Adams
I have a suggestion to add into the C language.
How to submit this suggestion for the standard?
struct X x = {default};
It differ from {} because we can define what is default.
I think something like this behavior is simple enough
with existing constructs. You can make a const "template"
object and initialize normally from the template.

const struct X X_default = { 0, 0 };
struct X x = X_default;

The part that's less simple, and where I'd like more help
from the language is chaining-up init_module() functions
so the other functions in a module can trust that their
supports are in place. Something like C++ class initializers,
but don't do it like that. Something like the dll_init()
function that always runs when loaded.

With this sort of help, you use libraries like fontconfig
without having to create the top-level library object.
Hans-Bernhard Bröker
2016-11-21 19:46:30 UTC
Permalink
Post by luserdroog
I think something like this behavior is simple enough
with existing constructs. You can make a const "template"
object and initialize normally from the template.
const struct X X_default = { 0, 0 };
struct X x = X_default;
That may be possible in C++, but in C it's not -- at least not if 'x'
has static storage duration. Initializers for static objects must be
compile-time constants; 'const' qualified variables don't qualify for that.
luserdroog
2016-11-25 03:58:52 UTC
Permalink
Post by Hans-Bernhard Bröker
Post by luserdroog
I think something like this behavior is simple enough
with existing constructs. You can make a const "template"
object and initialize normally from the template.
const struct X X_default = { 0, 0 };
struct X x = X_default;
That may be possible in C++, but in C it's not -- at least not if 'x'
has static storage duration. Initializers for static objects must be
compile-time constants; 'const' qualified variables don't qualify for that.
Well, they ought to! Why the heck not?
Jakob Bohm
2016-11-25 06:00:36 UTC
Permalink
Post by luserdroog
Post by Hans-Bernhard Bröker
Post by luserdroog
I think something like this behavior is simple enough
with existing constructs. You can make a const "template"
object and initialize normally from the template.
const struct X X_default = { 0, 0 };
struct X x = X_default;
That may be possible in C++, but in C it's not -- at least not if 'x'
has static storage duration. Initializers for static objects must be
compile-time constants; 'const' qualified variables don't qualify for that.
Well, they ought to! Why the heck not?
Fundamentally, static initialization is done by actually emitting the
data bytes, ready to use, as part of the resulting program file. This
is one of the strong benefits of C over languages such as Java.

The downside of this is that the values of initialized variables with
static duration cannot depend on any kind of runtime calculation,
except that values of pointer types may contain the addresses of other
objects with static duration.

It so happens, that example above instructs the compiler to generate
code which copies the value of one (read only) variable as the
initialization value for another variable. Under the fundamental rules
of C, there is nothing preventing the initial value of X_default from
being located in another source file not seen during the compilation of
the definition of the the variable x. Therefore, typical real world C
compilers cannot be sure to see the values to emit for x during the
compiler run that needs to emit those values.

Note that the C keyword "const" really means "readonly", and was
originally proposed under that name. The keyword only has a
superficial similarity to actual compile time constants as found in
languages such as Pascal. In C compile time constants are written
using the preprocessor #define syntax, not the const type modifier.

C++ is quite a different beast, as it has a standard mechanism for
running code (constructors etc.) during program startup before the
actual "main" program body. This mechanism, which has some important
overhead, allows the above syntax to be compiled and implemented in all
the corner cases, by falling back to running variable copying code
during program startup in the cases where that code cannot be optimized
into static C style initialization. Unfortunately many C++ compilers
fall back to startup execution of constructor code even when they could
and should have emitted initialized variables.

Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
Keith Thompson
2016-11-25 07:40:21 UTC
Permalink
Post by Jakob Bohm
Post by luserdroog
Post by Hans-Bernhard Bröker
Post by luserdroog
I think something like this behavior is simple enough
with existing constructs. You can make a const "template"
object and initialize normally from the template.
const struct X X_default = { 0, 0 };
struct X x = X_default;
That may be possible in C++, but in C it's not -- at least not if 'x'
has static storage duration. Initializers for static objects must be
compile-time constants; 'const' qualified variables don't qualify for that.
Well, they ought to! Why the heck not?
Fundamentally, static initialization is done by actually emitting the
data bytes, ready to use, as part of the resulting program file. This
is one of the strong benefits of C over languages such as Java.
The downside of this is that the values of initialized variables with
static duration cannot depend on any kind of runtime calculation,
except that values of pointer types may contain the addresses of other
objects with static duration.
It so happens, that example above instructs the compiler to generate
code which copies the value of one (read only) variable as the
initialization value for another variable. Under the fundamental rules
of C, there is nothing preventing the initial value of X_default from
being located in another source file not seen during the compilation of
the definition of the the variable x. Therefore, typical real world C
compilers cannot be sure to see the values to emit for x during the
compiler run that needs to emit those values.
Note that the C keyword "const" really means "readonly", and was
originally proposed under that name. The keyword only has a
superficial similarity to actual compile time constants as found in
languages such as Pascal. In C compile time constants are written
using the preprocessor #define syntax, not the const type modifier.
C++ is quite a different beast, as it has a standard mechanism for
running code (constructors etc.) during program startup before the
actual "main" program body. This mechanism, which has some important
overhead, allows the above syntax to be compiled and implemented in all
the corner cases, by falling back to running variable copying code
during program startup in the cases where that code cannot be optimized
into static C style initialization. Unfortunately many C++ compilers
fall back to startup execution of constructor code even when they could
and should have emitted initialized variables.
In this particular context, C++ isn't all that different. In C++ as in
C, "const" means "read-only", and "constant" is a distinct concept.
In both languages, you can write:
const int r = rand();
but the expression r is not a constant expression (it can't be).

The difference is that C++ has a special-case rule that, given
const some_type obj = expr;
makes `obj` a constant expression *if and only if* expr is a constant
expression.
--
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"
BartC
2016-11-25 12:33:00 UTC
Permalink
Post by luserdroog
Post by Hans-Bernhard Bröker
Post by luserdroog
I think something like this behavior is simple enough
with existing constructs. You can make a const "template"
object and initialize normally from the template.
const struct X X_default = { 0, 0 };
struct X x = X_default;
That may be possible in C++, but in C it's not -- at least not if 'x'
has static storage duration. Initializers for static objects must be
compile-time constants; 'const' qualified variables don't qualify for that.
Well, they ought to! Why the heck not?
'const' is an can of worms in C. This might seem obvious:

const int a = 23;

switch (x) {
case a:
....
static int y[a];


The value of 'a' must be a compile-time constant so that the compiler
knows what code to emit, or how much space to reserve for y. But what
about this:

const int a = f();

switch (x) {
case a:
....
static int y[a]


Now it won't know until runtime! And it might be that the evaluation of
f() is somehow dependent on sizeof(y), or there are interdependencies
between static data modules that now rely on order of initialisation.

Easier then to have the rule that a const value doesn't count as a
compile-time constant rather then 'it depends'. So in C you'd have to
use one of:

enum {a=23};
#define a 23

But this doesn't help when the const object you're trying to define is a
simple scalar.
--
Bartc
Loading...