Peter said:
Bruce Wood said:
Peter said:
It might be possible to design a language that has essentially all of the
functionally capabilities of the lower level languages, without the
requirement
of ever directly dealing with pointers.
True, but one question I know the C# team constantly asks is whether a
feature is worth the additional complexity it adds to the language. (I
know this because they frequently cite that as a reason for not
including certain features.) What does it really buy you being able to
take the address of an arbitrary variable (in safe code... I know that
you can do it in unsafe code)? As I said, I think that Java (and now
C#) have demonstrated that it doesn't buy you much. You mentioned
boxing overhead, but in .NET 2.0 you can pretty-much avoid boxing...
all you have to do is learn a new idiom: a new way to do what you've
always done, but now in a new language.
Are you referring to Generics? Does this address this issue of passing a
struct
by (address) reference?
No. "ref" and "out" address the issue of passing a struct by reference
(to a method).
Generics address the problem of writing a type that contains another,
arbitrary type that could be a value type or a reference type, without
incurring boxing overhead and while maintaining compile-time type
safety. For example, in .NET 1.1 if I wanted a "vector" of Persons, I
would write:
ArrayList personList = new ArrayList();
personList.Add(new Person("Frank"));
Person frank = (Person)personList[0];
Here, Person is a reference type (as most user-defined types are) and
so the ArrayList now contains one entry, which is a reference to a
Person that has space allocated for it on the heap. However, I've lost
(compile-time) type checking: ArrayList is a collection of Object, and
so to get Frank back I had to use a cast, which involves a run-time
type check.
If I want a "vector" of ints, I say this:
ArrayList intList = new ArrayList();
intList.Add(15);
int i = (int)intList[0];
Here, 15 is an integer value type. Since ArrayList is a collection of
Object, the value type has to be boxed onto the heap and a reference to
it placed in the ArrayList. In order to get the value back, I have to
unbox the value, the unbox operation here represented by the cast.
Generics eliminate both problems. You'll recognize the template syntax
of C++:
List<Person> personList = new List<Person>();
personList.Add(new Person("Frank"));
Person frank = personList[0];
There's no need for a cast or for a run-time type check because the
compiler already knows that every reference in the list refers to a
Person.
Similarly,
List<int> intList = new List<int>();
intList.Add(15);
int i = intList[0];
No boxing, no unboxing. The list holds native integers, not Objects.
That, in the end, is what it comes down to: C# works very well. It's
just that it does things differently than does C++, and you can't take
C++ idioms and concepts and start writing C# as though it were C++. In
a few domains, C++ is much better suited to the problems than is C#,
but in most domains C# gives you all the functionality you need while
helping keep you out of trouble.
I think that it is possible to take the concept of C# further along. To be
able
to provide every required feature of a language such as C++, yet to do this
in
an entirely type safe way, with essentially no additional execution time
overhead, and drastically reduce the number of details that must be handled
by
the programmer. I think that C# has done an excellent job of achieving these
goals up to this point. I think that there are two opportunities for
improvement:
(1) Little tweaks here and there to eliminate more of the additional
execution
time overhead.
(2) Abstract out the distinction between reference types and value types so
that
the programmer will not even need to know the difference. The underlying
architecture can still have separate reference types and value types, yet,
this
can be handled entirely transparently by the compiler and CLR.
How would you begin to achieve this?
I'm sorry, but I have to ask this... I don't mean to be combative or
snobby, but I'm a bit confused. It appears to me that you're trying to
get your head around C#'s version of value types, how they work, what
is boxing and unboxing and when does it happen, what are generics, and
some basic plumbing issues about how C# works. Correct me if I'm wrong,
but you seem knowledgeable about the inner workings of the machine, but
you're still trying to map what's going on in C# back to what happens
under the covers. If I can presume to sum up your questions, you're
experienced and intelligent, but some aspects of C# haven't quite
"clicked" for you yet.
And yet... you claim that C# is somehow lacking and needs improvement,
and I'm just dying to ask... based on what? I guess something just
isn't "clicking" for ME here.... I find myself very productive in C#.
There will always be a need for improvement in computer programming languages
until computers reach the point where they can anticipate every possible need in
advance. What I am saying is that C# has made great strides in providing
essentially all of the capability of C++, but at a reduced cost of programmer
effort. C# is in many respects an improved C++.
All of the benefits of advances in programming languages are derived in terms of
reduced programming effort to achieve the desired result. C# can go one more
step further with this and eliminate the need for programmers to ever pay any
attention to the differences between value types and reference types.
I disagree. The only way I can think of to interpret your suggestion is
by way of comparison, viz:
C# has two fundamental classes of types: value types and reference
types. The act very differently: value types being... well, values such
as integers, doubles, floats. Also included here are date/times and
some other types such as System.Drawing.Point and
System.Drawing.Rectangle. You can also make your own value types, but
you should have very little cause to do so. Reference types are used
for almost everything else. Java takes a similar approach to this.
One could unify the two classes of types by making everything a
reference type, or at least act like a reference type. Every integer,
double, float, or decimal would live (or appear to live) on the heap,
with a reference pointing to it. I believe that Smalltalk took an
approach similar to this, although I can't be sure because I've never
actually used Smalltalk.
One could also unify the two classes of types by making everything a
value type. This is essentially what C++ does. If you don't explicitly
take the address of something, it's a value. C# could do this, but then
you would have to have some syntax to indicate that you were passing a
reference to a method, for example, instead of passing the entire
object on the stack, which most of the time you don't want to do.
Because C++ has pointers, this is all very easy in C++. However, I
claim that this is one place where C# got it right: MOST OF THE TIME
you want to pass a reference to an object, and you want to pass what C#
considers value types by value. In C#, if you say nothing special, this
is what you get. If you say "ref", then you can pass a value type by
reference (or change the reference to a reference type--a pointer to a
pointer, in C++ terms). The C# team _could_ create a "copy" keyword
that would allow you to pass a reference type "by value" as it were, as
you can do in C++, rather than forcing you to say
"(Person)frank.Clone()" which is rather clunky.
So, again, I don't see how unifying the two kinds of types would
"improve programmer productivity". It would certainly make it easier
for people coming from the C++ world to understand what was going on,
but I think that it would confuse most newbies and if it were done
wrong would lead to newbies copying huge objects onto the stack by
mistake, which undermines claims to "improved productivity."
There are some areas of the .NET Framework that I think could use
improvement, but the language itself works just fine for me. I find the
difference between value types and reference types very clear and
logical. I don't see where the "great rewards in increased programmer
productivity" will come from by trying to unify the two of them into...
what? A C++ type model? I'm sorry, but I found more people utterly
No, not into a C++ type model.
C# unified [Varname.FieldName and Varname->FieldName]
into the single [Varname.FieldName]
Take this same C# idea to its logical conclusion.
Again, I'm confused. C# has no Varnam->FieldName syntax. That's C++.
The only ways I can see to "unify" the model is put everything on the
heap (or make it act as though it were on the heap), or make everything
a value type (which is essentially C++'s approach). Neither alternative
makes the language easier to understand or use, IMHO.
And it's not really very difficult to start with. There's only one rule
that's different from C++, which is this: "Reference types (which is to
say, most types) in C# act natively like pointer types in C++. That is,
if Person is a reference type, passing a Person to a method passes a
reference; every Person variable holds a reference; and every Person
instance lives on the heap." All other types (that is, value types) act
like C++ types. In the end, it's C# reference types, not value types,
that differ from C++.
And you know what? I like that better. No more "&", no more "*"... you
just use the types and they do what you probably wanted to do anyway
without having to pepper your code with additional syntax. Oh, and
you're not allowed to do patently silly things like pass an 80Kb
instance on the stack, even if 0.01% of the time that really is what
you would have wanted to do....