Structs cannot contain explicit parameterless constructors

  • Thread starter Thread starter Ole Nielsby
  • Start date Start date
O

Ole Nielsby

Why is this?

I've stumbled on this restriction more than once, and I'd
like to know the philosophy behind it if there is one. I figure
I'd be less prone to make this error if I knew the reason.

Let me mention two cases where I wanted parameterless
struct constructors but could not get them.

1st, I needed sortable identity stamps on certain classes of
objects. I cooked this up:

struct IdentityStamp
{
public IdentityStamp()
{
lock (locker) this.stamp = seed++;
}
public readonly long stamp;
private static object locker = new object();
private static long seed = 0;
}

but it didn't compile and I had to change it, to
introduce an essentially unneeded parameter in
the constructor. I can't figure out why this had to
be so...
 
Ole Nielsby said:
Why is this?

I've stumbled on this restriction more than once, and I'd
like to know the philosophy behind it if there is one. I figure
I'd be less prone to make this error if I knew the reason.

Let me mention two cases where I wanted parameterless
struct constructors but could not get them.

1st, I needed sortable identity stamps on certain classes of
objects. I cooked this up:

struct IdentityStamp
{
public IdentityStamp()
{
lock (locker) this.stamp = seed++;
}
public readonly long stamp;
private static object locker = new object();
private static long seed = 0;
}

but it didn't compile and I had to change it, to
introduce an essentially unneeded parameter in
the constructor. I can't figure out why this had to
be so...

Excerpt from http://www.codeproject.com/csharp/structs_in_csharp.asp:


"Although the CLR allows it, C# does not allow structs to have a default
parameterless constructor. The reason is that, for a value type, compilers
by default neither generate a default constructor, nor do they generate a
call to the default constructor. So, even if you happened to define a
default constructor, it will not be called and that will only confuse you.
To avoid such problems, the C# compiler disallows definition of a default
constructor by the user. And because it doesn't generate a default
constructor, you can't initialize fields when defining them, ..."

HTH,
Mythran
 
Mythran said:
I've stumbled on this restriction more than once, and I'd
like to know the philosophy behind it [...]

Excerpt from http://www.codeproject.com/csharp/structs_in_csharp.asp:

"Although the CLR allows it, C# does not allow structs to
have a default parameterless constructor. The reason is that,
for a value type, compilers by default neither generate a
default constructor, nor do they generate a call to the default
constructor. So, even if you happened to define a default
constructor, it will not be called and that will only confuse
you.
To avoid such problems, the C# compiler disallows definition
of a default constructor by the user. And because it doesn't
generate a default constructor, you can't initialize fields when
defining them, ..."

I'm not quite sure I understand. Is it because people might
declare struct variables without initializing them and think
that the compiler will call a parameterless constructor?

I'm slightly perplexed that I can't explicitly initialize a
struct without parameters, because allowing me to do that
would make other programmers think that this constructor
is implicitly called when they forget to initialize their
variables. Or do I get it wrong?

I'd rather prefer that the compiler forced me to initialize
structs in general - optimizing away the cases where
the constructor call would have no effect because it
just zeroes zeroes.

Regards/Ole N.
 
Ole,

Few stupid questions.
What do you use this type of struct for?
When I put this in a web page it seems to keep track of the seed number on
postbacks and the web is stateless
Is this kept in memory all times as long as the application is running. (
singleton )
I am trying to learn here.
Thanks for any help or input.

Sa


Ole Nielsby said:
I've stumbled on this restriction more than once, and I'd
like to know the philosophy behind it [...]

Excerpt from http://www.codeproject.com/csharp/structs_in_csharp.asp:

"Although the CLR allows it, C# does not allow structs to
have a default parameterless constructor. The reason is that,
for a value type, compilers by default neither generate a
default constructor, nor do they generate a call to the default
constructor. So, even if you happened to define a default
constructor, it will not be called and that will only confuse
you.
To avoid such problems, the C# compiler disallows definition
of a default constructor by the user. And because it doesn't
generate a default constructor, you can't initialize fields when
defining them, ..."

I'm not quite sure I understand. Is it because people might
declare struct variables without initializing them and think
that the compiler will call a parameterless constructor?

I'm slightly perplexed that I can't explicitly initialize a
struct without parameters, because allowing me to do that
would make other programmers think that this constructor
is implicitly called when they forget to initialize their
variables. Or do I get it wrong?

I'd rather prefer that the compiler forced me to initialize
structs in general - optimizing away the cases where
the constructor call would have no effect because it
just zeroes zeroes.

Regards/Ole N.
 
Ole Nielsby said:
Why is this?

I've stumbled on this restriction more than once, and I'd
like to know the philosophy behind it if there is one. I figure
I'd be less prone to make this error if I knew the reason.

Let me mention two cases where I wanted parameterless
struct constructors but could not get them.

1st, I needed sortable identity stamps on certain classes of
objects. I cooked this up:

struct IdentityStamp
{
public IdentityStamp()
{
lock (locker) this.stamp = seed++;
}
public readonly long stamp;
private static object locker = new object();
private static long seed = 0;
}

but it didn't compile and I had to change it, to
introduce an essentially unneeded parameter in
the constructor. I can't figure out why this had to
be so...

Hi Ole,

you shouldn't use a constructor for this.
You could use something like this:

struct IdentityStamp
{
public IdentityStamp NewStamp()
{
IdentityStamp newStamp = new IdentityStamp();
lock (locker) newStamp.stamp = seed++;
return newStamp;
}
......
}

HTH
Christof
 
Mythran said:
Excerpt from http://www.codeproject.com/csharp/structs_in_csharp.asp:


"Although the CLR allows it, C# does not allow structs to have a default
parameterless constructor. The reason is that, for a value type, compilers
by default neither generate a default constructor, nor do they generate a
call to the default constructor. So, even if you happened to define a
default constructor, it will not be called and that will only confuse you.
To avoid such problems, the C# compiler disallows definition of a default
constructor by the user. And because it doesn't generate a default
constructor, you can't initialize fields when defining them, ..."

That doesn't "explain" anything. It's a circular argument that boils down to
"compilers don't create constructors because if they did they wouldn't
bother calling them".

I don't know what the real reason is but it may have something to do with
version compatibility - Normally you can replace a dll with a new version
using the same method signatures and everything will work OK but this would
not be possible with default constructors because the compiler does not
actually call a default constructor - it just makes the memory 0 for
efficiency reasons - consequently, If you added a default constructor it
would not be called unless you recompiled.

Regarding the original post - I think that the design is misguided - If you
need a unique identity in a class then assign it in the class (or better a
base class) You can use an IdentityStamp class to get it if you want using a
static method [eg this.id = IdentityStamp.GetNext();]
Assuming that you could do what the OP wanted it would not behave as
expected:

// IdentityStamp.seed == 0
Obj obj = new Obj(); // class usng IdentityStamp
IdentityStamp id = obj.Id;
Foo(id); // void Foo(IdentityStamp id)
// IdentityStamp.seed is now at least 3.

This would create a new stamp then overwrite it with the one from obj which
is probably not what you intended.

C++ gets around this with copy constructors (even the line that looks like
assignment!). In C# there is no copy constructor to fix the problem for you.
 
Christof Nordiek said:
you shouldn't use a constructor for this.
You could use something like this:

struct IdentityStamp
{
public IdentityStamp NewStamp()

This is what I did (using a static method). It just seems
a bit awkward that I can't use the constructor.

Regards/Ole N.
 
MSDN said:
Ole,

Few stupid questions.
What do you use this type of struct for?

I use it for maintaining a sort order for in-memory objects.
The only operations performed on the struct are comparisons
and GetHashCode(). Serialization/web programming is not
an issue yet.
 
Christof,

Where is locker???
need complete example please.
What is the advantage of using a Struct and not a Class

Thank You,

SA
 
Ole,

How do you finally GC it?

Thank You,

SA

Ole Nielsby said:
I use it for maintaining a sort order for in-memory objects.
The only operations performed on the struct are comparisons
and GetHashCode(). Serialization/web programming is not
an issue yet.
 
Nick Hounsome said:
I don't know what the real reason is but it may have something
to do with version compatibility - Normally you can replace a
dll with a new version using the same method signatures and
everything will work OK but this would not be possible with
default constructors because the compiler does not actually
call a default constructor - it just makes the memory 0 for
efficiency reasons - consequently, If you added a default
constructor it would not be called unless you recompiled.

Makes some sort of sense, though I'm not at ease with
this kind of deep-tech implementation detail having too
much influence on the language design.
Regarding the original post - I think that the design is
misguided

Original poster disagrees, but this might be a matter of
slightly different programming styles, yours perhaps
being tuned by experience with C# to stay away from
its weak spots, while I - as a functional programming
freak involved with language desing - have trained
myself to question the language.
- If you need a unique identity in a class then
assign it in the class (or better a base class)
You can use an IdentityStamp class to get it if
you want using a static method [eg this.id =
IdentityStamp.GetNext();]

That's what I did, to get things runnig, not because I
deemed it reasonable.
Assuming that you could do what the OP wanted
it would not behave as expected:

// IdentityStamp.seed == 0
Obj obj = new Obj(); // class usng IdentityStamp
IdentityStamp id = obj.Id;
Foo(id); // void Foo(IdentityStamp id)
// IdentityStamp.seed is now at least 3.

This would create a new stamp then overwrite it
with the one from obj which is probably not what
you intended.

C++ gets around this with copy constructors (even
the line that looks like assignment!). In C# there is
no copy constructor to fix the problem for you.

This still seems a bit obscure.

Are you implying that the line

IdentityStamp id = obj.Id;

is treated as being equivalent of

IdentityStamp id = new IdentityStamp();
id = obj.Id;

and

Foo(id)

is treated as something like:

Foo(new IdentityStamp() = id)

???

Considering how C# handles classes, I find these
implicit constructor calls quite unnecessary - why
can't the compiler just zero the struct and flag it as
uninitialized, just as a class ref would be nulled and
flagged uninitialized?

Is this because the clr uses default constructors to
ensure floats are properly zeroed or something like
that?

Regards/Ole N.
 
Ole Nielsby said:
Nick Hounsome said:
I don't know what the real reason is but it may have something
to do with version compatibility - Normally you can replace a
dll with a new version using the same method signatures and
everything will work OK but this would not be possible with
default constructors because the compiler does not actually
call a default constructor - it just makes the memory 0 for
efficiency reasons - consequently, If you added a default
constructor it would not be called unless you recompiled.

Makes some sort of sense, though I'm not at ease with
this kind of deep-tech implementation detail having too
much influence on the language design.
Regarding the original post - I think that the design is
misguided

Original poster disagrees, but this might be a matter of
slightly different programming styles, yours perhaps
being tuned by experience with C# to stay away from
its weak spots, while I - as a functional programming
freak involved with language desing - have trained
myself to question the language.
- If you need a unique identity in a class then
assign it in the class (or better a base class)
You can use an IdentityStamp class to get it if
you want using a static method [eg this.id =
IdentityStamp.GetNext();]

That's what I did, to get things runnig, not because I
deemed it reasonable.
Assuming that you could do what the OP wanted
it would not behave as expected:

// IdentityStamp.seed == 0
Obj obj = new Obj(); // class usng IdentityStamp
IdentityStamp id = obj.Id;
Foo(id); // void Foo(IdentityStamp id)
// IdentityStamp.seed is now at least 3.

This would create a new stamp then overwrite it
with the one from obj which is probably not what
you intended.

C++ gets around this with copy constructors (even
the line that looks like assignment!). In C# there is
no copy constructor to fix the problem for you.

This still seems a bit obscure.

Are you implying that the line

IdentityStamp id = obj.Id;

is treated as being equivalent of

IdentityStamp id = new IdentityStamp();
id = obj.Id;

and

Foo(id)

is treated as something like:

Foo(new IdentityStamp() = id)

???

No. I think that having a proper default constructor would imply that they
would have to be treated like that.
Considering how C# handles classes, I find these
implicit constructor calls quite unnecessary - why
can't the compiler just zero the struct and flag it as
uninitialized, just as a class ref would be nulled and
flagged uninitialized?

It does.
Is this because the clr uses default constructors to
ensure floats are properly zeroed or something like
that?

Regards/Ole N.

This is doing my head in too.

The design of IdentityStamp seems to imply that all IdentityStamps are
unique and yet you want to be able to copy them which inevitably leads to
non-unique copies. This seems logically unsound which is why I prefer that
the uniqueness is confined to a reference type where it makes more sense.

The whole issue of "IdentityStamp s1 = s2;" is a logical minefield:

either:

1. It is a construction followed by copy - in which case you have the
problem that I outlined.

or

2. It is a assignment from an IdentityStamp to something that is not (yet)an
IdentityStamp - which is logically wrong.

In C++ the whole issue is resolved with, possibly implicit, copy
constructors "X(const X&)" and by explicitly stating that the examples I
gave above use these copy constructors but C#/.NET has no equivalent.

(This is only a problem for structs as reference types are always explicitly
constructed and never copied)
 
Back
Top