remove struct's default constructor?

Z

Zytan

Hi,
Why are you making this thing a struct anyway?
Why not make it a class?

Hi,

Bill, it's just a few strings and ints that are related. And I want
to pass this data all at the same time (rather use many parameters),
so I put them together in a struct. Then, Jon Skeet said structs are
better off with private data members, so I made them readonly
(although he prefers properties, since they allow for future
modification, and I agree, but my struct is too simple for that). So,
then I needed a constructor to set the values.

Then I realized the values could be set by accident to all 0's (and
can never be fixed) if the default constructor is applied. I just
really hate it when languages do things implicitly like this. Reminds
me of C++'s desire to make copy constructors, default constructors,
etc., when you don't want them. I feel like saying, "stop helping me,
because it's not helping." So, now, everything's perfect except for
this C# implied default constructor that zeros everything out, which
could be invoked by accident. It'd be nice if I could override it.
It'd be best if it didn't exist (once I made my own constructor, that
is).

So, it's funny how a little struct can be moved into a position,
incrementally, by doing The Right Thing each step, to where people are
dumbfounded why it shouldn't be a class. In that account, every
struct should be a class. :) And yes, if it was more complicated than
this, I would use a class. The journey has been fun!

Cheers,

Zytan
 
B

Barry Kelly

Zytan said:
Yes, junk would exist if no constructor is called. But, if I force
any use of a struct to use my constructor, then the values will be
what the constructor forces them to be. This is even better than
having them zeroed out. Imagine only having proper values. Zerod
values are better than junk values. Proper values are even better
than zeroed values.

If there were no way to create structs in a default manner, then it
would be impossible to safely create an array of arbitrary length of
such structs, and similarly, for the same reason, it would be impossible
to store such structs in something like a
No, it's not perfect for all. How can you claim that? For my struct,
it should never, ever have zeros in it. Ever. Zeros are just not
proper values.

You should design your struct so that zeros are meaningful values. Don't
forget that it's only the fields that are initialized to zero, so the
external behaviour of the struct, via properties and methods, can be
anything you want it to be.

If it's still too much of a problem, don't use structs. Use classes.
I am dumbfounded as to your defensive behaviour.

Take a chill pill, man!

-- Barry
 
B

Barry Kelly

Zytan said:
Bill, it's just a few strings and ints that are related. And I want
to pass this data all at the same time (rather use many parameters),
so I put them together in a struct.

Structs are more suited to values where copies need to be distinct, i.e.
the type modeled needs to have value semantics in the same ways as e.g.
a Complex type would. In other words, structs are useful to avoid the
aliasing issues of classes.

Also, structs work best if they are read-only, otherwise you get funny
issues with e.g. { List<Point> list; /* ... */ list.Foo = 42; } won't
actually modify an item in the list, but a temporary value that gets
discarded.

Performance benefits, if there are any (you need to measure), need to be
more dramatic in order to justify the decision to use structs rather
than classes, IMHO.
Then, Jon Skeet said structs are
better off with private data members, so I made them readonly
(although he prefers properties, since they allow for future
modification, and I agree, but my struct is too simple for that).

Nonsense - no struct is too simple to have private fields with public
properties rather than public fields.

Trivial property accessors get inlined. There's no good reason to have
public fields, pretty much ever.

-- Barry
 
W

Willy Denoyette [MVP]

Zytan said:
Answering a question with a snappy question is attitude. I don't
expect MSDN to be completely correct. MSDN is giving strong evidence
that it is true, so I believe it just may be true. When C# refuses to
allow me to make a constructor with 0 parameters, and MSDN tells me
explicitly that the reason I cannot do this is because a default
constructor already exists, then, yes, I am going to believe it. The
evidence supports this.

No, it doesn't provide any evidence, there is no such thing like a "default constructor"
(called a "user defined special member function" in C++) for value types emitted by the
managed compilers, nor can you define one yourself, except when using IL where you can do
almost everything even produce very unsafe code.
Write some code and look at the IL (and even better at the JITted code), there is no .ctor()
in a value type nor is there a "call" to such constructor ever emitted, all there is, is a
initobj instruction, but even this one is optimized away by the JIT compiler.
Ok, thanks for the in depth explanation. Things are always zeroed out
before a constructor is called. I get it. In fact, I think it's
great.

But, this doesn't prove that there is no default constructor for
structs. If the default cosntructor for structs is just to zero
things out, then it doesn't need to exist,

True, there is no "default constructor" for value types.

and therefore doesn't have
to exist in the final byte code. The fact that everything is zeroed
out is one of the reasons such a default constructor needn't actually
exist, since it'd just do the same work again.

True, that's why there is no such "default constructor", why do you keep on insisting on
this?
Again, I will ask: Why does C# disallow a parameterless constructor?

A parameter-less user defined constructor *is* a default constructor! And value types DO NOT
SUPPORT default constructors!
Even if you are directly using IL as implementation language, and you define a default
constructor on a value class, still, the home of the value type will be initialized to zero,
before you explicitly call the constructor. This because the initialization is NOT part of
the construction, its simply part of the initialization of the local variables at method
entry time.

No managed language compiler I know of,will generate a default constructor. Check [1] [2]
and [3] so see what ECMA says about this.
Especially [3] is what you should read, it explains how value classes can be *initialized*.
And that's exactly what the C# compiler is generating, depending on whether the struct
(value type) has a user defined (obviously one with parameters)constructor or not.
MSDN says it is because a default parameterless constructor exists.
If MSDN is wrong,

Well, It is!

then shouldn't the creation of a parameterless
constructor be allowed?

Again, because parameter-less constructors are "default constructors" ( or "user defined
special member function") and these are not allowed in value types!

Willy.

[1] From ECMA-372 C++/CLI Language Specification.
12.2.1 Value classes
[Note: A value class is a data structure that can contain fields, function members, and
nested types. Unlike
other class types, value classes do not support user-defined destructors, finalizers,
default constructors, copy
constructors, or copy assignment operators. Value classes are designed to allow the CLI
execution engine to
efficiently copy value class objects.


[2]From ECMA-335 ch. 8.9.7
5. Unlike object types, instances of value types do not require a constructor to be called
when an
instance is created. Instead, the verification rules require that verifiable code initialize
instances
to zero (null for object fields).


[3] From ECMA-335 12.1.6.2.1 Initializing instances of value types
There are three options for initializing the home of a value type instance. You can zero it
by loading the address
of the home (see Table 8: Address and Type of Home Locations) and using the initobj
instruction (for local
variables this is also accomplished by setting the localsinit bit in the method's header).
You can call a userdefined
constructor by loading the address of the home (see Table 8: Address and Type of Home
Locations)
and then calling the constructor directly. Or you can copy an existing instance into the
home, as described
in §12.1.6.2.2.
 
B

Ben Voigt

Zytan said:
Hey, no problem. I thought the same thing.


Yes, these are valid solutions. Thanks. I don't think my issue is
large enough to warrant any of these things. I am more just curious
as to why I can't remove the default zeroing out.

Actually, I think the zeroing is done en masse, whenever the gc compacts the
heap, the newly freed memory is zeroed. Then, a new structure instance can
be created by just reserving memory and no need to call any constructor at
all.
 
B

Barry Kelly

Ben said:
Actually, I think the zeroing is done en masse, whenever the gc compacts the
heap, the newly freed memory is zeroed. Then, a new structure instance can
be created by just reserving memory and no need to call any constructor at
all.

Yes, for structs that are part of an array or other reference type.
However, many structs will be locals or parameters, for which zeroing
out theoretically takes extra time, if the JIT optimizer doesn't detect
the redundant zeroing.

-- Barry
 
B

Barry Kelly

Zytan said:
Again, I will ask: Why does C# disallow a parameterless constructor?
MSDN says it is because a default parameterless constructor exists.
If MSDN is wrong, then shouldn't the creation of a parameterless
constructor be allowed?

A better reference for C# and .NET low-level behaviour are the ECMA
specs, see #334 and #335. They're freely downloadable specs from
http://www.ecma-international.org/ .

-- Barry
 
B

Ben Voigt

Barry Kelly said:
Yes, for structs that are part of an array or other reference type.
However, many structs will be locals or parameters, for which zeroing
out theoretically takes extra time, if the JIT optimizer doesn't detect
the redundant zeroing.

The point is that no constructor call is made in certain circumstances.
That's actually stated as the reason for not allowing default constructors
on value types (on some developer's blog) -- they weren't willing to
guarantee they would always be called.
 
B

Barry Kelly

Ben said:
The point is that no constructor call is made in certain circumstances.
That's actually stated as the reason for not allowing default constructors
on value types (on some developer's blog) -- they weren't willing to
guarantee they would always be called.

Yes, I fully agree with you. I was just broadening the point to include
locals, rather than just having the GC responsible.

-- Barry
 
J

Jon Skeet [C# MVP]

Zytan said:
Bill, it's just a few strings and ints that are related. And I want
to pass this data all at the same time (rather use many parameters),
so I put them together in a struct.

None of that has anything to do with whether it should be a struct or a
class. You should only ask yourself whether you want value type
semantics or reference type semantics.

Personally, I can only remember about 2 structs I've ever written. I
almost *always* use classes.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
This is not about attitude this is about reality, many things in MSDN
are "wrong or "badly worded", you can't and should never expect such
huge piece of documentatin to be perfect. It's up to the reader to
correctly interpret what's been written, or to ask MSFT to correct
what's wrong.

Personally, I think it's about context. From the context of C#, I think
you end up with a consistent approach if you consider all value types
to have an implicit parameterless constructor which initialises
everything to zero. It means you don't have to specify that:

int x = new int();

actually isn't calling a constructor. It basically makes life easier
from the point of view of someone who is only interested in C# rather
than the guts, without actually doing *much* conceptual damage.


Now, at the CLR level, it *isn't* calling a constructor, it's calling
initobject (or something similar - I can't remember offhand). But at
the C# level, I think it's reasonable to treat it as a parameterless
constructor.

This isn't the only place that C# terminology and CLR/CLI terminology
clash a bit.
 
J

Jon Skeet [C# MVP]

A parameter-less user defined constructor *is* a default constructor!

Ah, no - there I disagree. I would say that a default constructor is
one supplied by the compiler. It is a public, parameterless constructor
which looks identical to one which can (for reference types, obviously)
be supplied in code, but it's often handy to be able to distinguish
between a default constructor as generated by the compiler and a public
parameterless constructor as supplied by the user.

I haven't seen any references to a "default constructor" in the C# spec
other than one provided by the compiler.
No managed language compiler I know of,will generate a default
constructor. Check [1] [2] and [3] so see what ECMA says about this.

If we're quoting ECMA, we should also quote the C# spec (ECMA 334)
which doesn't say that the compiler will generate a default constructor
for value types, but which *does* say that "every struct implicitly has
a parameterless instance constructor, which always returns the value
that results from setting all value type fields to their default
value". (2nd edition)

As I've said in another post, I think that's reasonable for the C# spec
to define in terms of keeping C# itself consistent, even though no
actual IL parameterless constructor is generated or called.
 
B

Bruce Wood

Hi,

Bill, it's just a few strings and ints that are related. And I want
to pass this data all at the same time (rather use many parameters),
so I put them together in a struct.

I would use a simple class for this. Even make all fields public if
you want to just use it as a container. Remember: "struct" in C# has
implications far beyond what it has in, say, C++. In C# it's a
specialized tool, rather than a nuance on "class".

Use a class in this case. You'll find that it works out better.
 
W

Willy Denoyette [MVP]

Jon Skeet said:
Ah, no - there I disagree. I would say that a default constructor is
one supplied by the compiler. It is a public, parameterless constructor
which looks identical to one which can (for reference types, obviously)
be supplied in code, but it's often handy to be able to distinguish
between a default constructor as generated by the compiler and a public
parameterless constructor as supplied by the user.

It depends on what documents you reading, there is no consistent definition of a "default
constructor", some call a "default user defined constructor" a default constructor" while
others don't make the distinction. Anyway, you got a point, I also prefer to call the
compiler generated constructor the "default constructor".

I haven't seen any references to a "default constructor" in the C# spec
other than one provided by the compiler.
No managed language compiler I know of,will generate a default
constructor. Check [1] [2] and [3] so see what ECMA says about this.

If we're quoting ECMA, we should also quote the C# spec (ECMA 334)
which doesn't say that the compiler will generate a default constructor
for value types, but which *does* say that "every struct implicitly has
a parameterless instance constructor, which always returns the value
that results from setting all value type fields to their default
value". (2nd edition)

Which is "wrong" also, the C# compiler does not produce a "default constructor" for value
types, that is, there is no .ctor() emitted in IL.
ECMA-334 also says that such constructor "returns" an initialized value type! Now, how can
something that doesn't exist return something, more, how can you ever call such thing?
All what the C# compiler does in this case is:
- When a local holds a value type, then the value is initialized by means of the .locals
init, and this at method entry.
Now, C# is a bit paranoic about this, it also emits an "initobj" at the point of
declaration (after moving the local address on the evaluation stack), as a result of the (C#
compiler enforced) new T(); call.
Note that the latter is optimized away by the JIT.
- When a field holds a value type, then the compiler emits an "initobj" (after moving...).

Only when there is a "user defined parameterized constructor" call, then will the compiler
emit "newobj instance void .ctor(arg, ..);" in IL.
In this case the JIT compiler will not optimize away the "locals int" action, that means
that even now the local holding the value type will still get initialized to 0. As I said
previously this is no big deal, the locals init is bloody fast (unless you don't get what
structs are made for in .NET ;-)).

As I've said in another post, I think that's reasonable for the C# spec
to define in terms of keeping C# itself consistent, even though no
actual IL parameterless constructor is generated or called.

Agreed, but the more you dive into the ECMA specs, the more apparent the inconsistencies and
contradictions become, this confuses some people as you now.

Willy.
 
W

Willy Denoyette [MVP]

Jon Skeet said:
Personally, I think it's about context. From the context of C#, I think
you end up with a consistent approach if you consider all value types
to have an implicit parameterless constructor which initialises
everything to zero. It means you don't have to specify that:

int x = new int();

actually isn't calling a constructor. It basically makes life easier
from the point of view of someone who is only interested in C# rather
than the guts, without actually doing *much* conceptual damage.


Now, at the CLR level, it *isn't* calling a constructor, it's calling
initobject (or something similar - I can't remember offhand). But at
the C# level, I think it's reasonable to treat it as a parameterless
constructor.

This isn't the only place that C# terminology and CLR/CLI terminology
clash a bit.


I would agree if C# was the only language on the CLR, but it isn't true, heck, some people
even think that C# is .NET.
And this is exactly what the ECMA-334 reflects, that document was written at the time C# was
the only language on the CLR submitted to ECMA, Now that we have three ECMA standard
language docs available(C# and C++/CLI and Eiffel), the inconsistencies become apparent,
none of them are perfect, but ECMA-334 shows his age and history.

Willy.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
I would agree if C# was the only language on the CLR, but it isn't
true, heck, some people even think that C# is .NET.

On the other hand, the C# language doesn't *have* to run on the CLR.
That's the only implementation I'm aware of, but it's not guaranteed.
And this is exactly what the ECMA-334 reflects, that document was
written at the time C# was the only language on the CLR submitted to
ECMA, Now that we have three ECMA standard language docs available(C#
and C++/CLI and Eiffel), the inconsistencies become apparent, none of
them are perfect, but ECMA-334 shows his age and history.

Indeed - but it's consistent with itself, so as long as one is aware
that what is true in C# terminology isn't necessarily true in CLR
terminology and vice versa, I think it's okay to say that from the C#
point of view, value types have default parameterless constructors.
 
W

Willy Denoyette [MVP]

Jon Skeet said:
On the other hand, the C# language doesn't *have* to run on the CLR.
That's the only implementation I'm aware of, but it's not guaranteed.
Sure not, let's talk about the CLI then, it's still the "Common Language ..." which is
dominant and indicative, but still it doesn't mean that C# is the only language supported.
Indeed - but it's consistent with itself, so as long as one is aware
that what is true in C# terminology isn't necessarily true in CLR
terminology and vice versa, I think it's okay to say that from the C#
point of view, value types have default parameterless constructors.

I'm afraid, we will have to agree to disagree :-(.
C# (the compiler) doesn't emit a parameterless constructor (aka "default constructor"), and
obviously, doesn't emit a call to a parameterless constructor either, instead, an"initobj
..."[1] is emitted to initialize a value type.
Why it's okay to say that "from the C# point of view, value types have default parameterless
constructors.", is beyond me, really. Honestly, this confuses people as it confused the OP,
hence it's question.
Note, however, that an instance of a value type, can have a parameterless constructor. You
can write valid value classes having a parameterless constructor IL (using ILAsm). All you
need is a "call instance void SomeValue::.ctor()" to create an instance of the value type
(here SomeValue). The only drawback is that it's slower to initialize an instance using this
method than a simple initobj or relying on "initlocals".

[1] a somewhat redundant "initobj", as the variable (local or embedded) holding the value is
already initialized at zero, because of the "initlocals" bit (emitted by the same
compiler!), or in case of embedded values, because of the GC/memory allocator action (an
implementation detail).
This brings us back to the OP's question - how can I prevent this to happen - , well the
answer is you can't unless you switch to another language like ILAsm.

Willy.
 
Z

Zytan

Yes, these are valid solutions. Thanks. I don't think my issue is
Actually, I think the zeroing is done en masse, whenever the gc compacts the
heap, the newly freed memory is zeroed. Then, a new structure instance can
be created by just reserving memory and no need to call any constructor at
all.

You're right, and I knew that.

I meant to say: "I am more just curious as to why I can't disallow
anyone from creating a struct without calling my own constructor."

Zytan
 
Z

Zytan

The point is that no constructor call is made in certain circumstances.
That's actually stated as the reason for not allowing default constructors
on value types (on some developer's blog) -- they weren't willing to
guarantee they would always be called.

Ah, now we are getting to the truth. Thanks, Barry. This makes
sense. Do you know from which blog you are quoting?

Zytan
 

Ask a Question

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

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

Ask a Question

Top