Edward said:
C# also has constructors and a default constructor. There is no
difference between C# and C++/CLI as far as this issue goes.
C# doesn't support default constructors for value types either. It's the
shortcoming of the CLR environment. The C++/CLI team has nothing to do
with this decision, they had to work with what they had. The CLR itself
doesn't support default and copy constructors for value types.
Theoretically Microsoft could have created C++/CLI in such a way that it
supports default constructors by generating implicit code behind this
feature. So when you instantiate a value type from C++/CLI, it could
automatically call a function, let's say "DefaultConstructor", to
initialize it for you. The problem with this is that such a value type
would not work outside of C++/CLI. If you decide to make such a type
public, and you instantiated it in C#, it wouldn't call the default
constructor automatically, and none of the other .NET languages would
do. Basically your type would fail to work as expected, unless it was
declared private to the assembly.
Yes, the compiler can do everything it wants internally. In fact, when
you create an std::vector<std::string> type and compile it with
/clr
ure, the compiler internally creates .NET value classes
std::vector and std::basic_string, which do have default constructors
(emulated!). Only those internal types can't be used from any other
module, they're private, just like the x86 code generated by a native
C++ compiler. Anything is doable in private code, but you won't be able
to make that public and use that type from other DLLs and other languages.
Microsoft decided not to allow that when you create your own value
types, even if it's a private type to the assembly.
A design which says that one can implement any constructor but a default
constructor is just plain bad no matter the OO language.
It may be true, but the CLR is not a language, it's a virtual machine.
They wanted to keep it simple and efficient. The idea behind value types
is that they are constructed by memset(&dest, 0, sizeof(dest)), and
copied using memcpy(&dest, &src, sizeof(src)). This way when you have an
array of value types, it is not needed to call the default/copy
constructor for each item individually. Value types were designed to
solve very simple problems, exactly those when you use a plain C struct
(a POD in C++).
This wouldn't be such a big problem if ref classes had either stack
syntax, or a reference counted auto-handle syntax (either way, portable
deterministic destruction at CLR-level).
But I don't see the current situation catastrophic. .NET is a reasonable
framework, much better than COM. Although in some ways .NET is a
fall-back for a true-heared C++ programmer (no const member functions,
no portable deterministic destruction, no templates), in other ways it's
a huge advancement (painless distributed component model, garbage
collection, well designed framework classes, reflection, properties,
events, two-way GUI designer). When you compare the interface that .NET
provides to the old Win32 GetProcAddress that supports only C calls,
it's "infinitely" more flexible and more object-oriented. C++/CLI does
its best to provide the best of both worlds (.NET and ISO C++), and I
think it can be further improved in a future Visual C++ release.
By the way, I don't think it's too late to introduce optional default
and copy constructors to .NET at a later time if such a decision is
made, either in C++/CLI only, or deep at CLR level. It wouldn't
automatically break existing code. Introducing const-correctness would
be much harder, now that nobody uses const at all.
Tom