why no struct inheritance?

  • Thread starter Thread starter not_a_commie
  • Start date Start date
N

not_a_commie

What's the technical reason for not allowing structs to be
hierarchical? WPF has a nice Point3D struct. I wanted to add some
additional constructors to it for converting from my data types.
 
C# extension methods may be at least a partial solution for you, if you
can live with using C# 3.0, which won't be to production bits for a few
months yet:

http://bobondevelopment.com/2007/04/05/blurring-the-lines-c-extension-methods/

That won't allow you to add a constructor, but it will allow you to
extend existing classes (including those you don't have source to) in
other ways.

In the meantime, perhaps a static helper method to convert your
arguments and return the desired struct will serve just as well.

--Bob
 
not_a_commie said:
What's the technical reason for not allowing structs to be
hierarchical?

Well, it would be reasonably feasible to allow inheritance so long as
you didn't want polymorphic methods and didn't add any member
variables. You see, if I declare:

struct Point
{
int x;
int y;

// Other operations
}

and then elsewhere in your code:

Point point;

then the "point" variable has room for 8 bytes - 4 for x, 4 for y. If
we were able to do:

Point point = new ExtendedPoint();

then:
a) the runtime couldn't know the actual type of the value, because
there isn't any room for it
b) there wouldn't be room for any extra member variables of
ExtendedPoint


I'm sure there would be ways round this is value type inheritance had
been desired from the start, but the current design doesn't allow it at
all.

As Bob said, extension methods in C# 3 may well help you.
 
Could you just provide a cast definition from your new types?

I like it. It's not clean or anything, but it should do just what I
want.
 
Am Sun, 6 May 2007 16:28:09 +0100 schrieb Jon Skeet [C# MVP]:
Point point = new ExtendedPoint();

then:
a) the runtime couldn't know the actual type of the value, because
there isn't any room for it
b) there wouldn't be room for any extra member variables of
ExtendedPoint

If this would compile (i.e no syntax error), the expected behavior is
crystal clear:
1. an object ob type ExtendedPoint is created (memory allocated + fully
constructed)
2. Memory for an object of type Point is allocated
3. The assignment is performed.

Note that we have value types, not reference types. That means: it all
depends on the definition of the assignment operator. Since we cannot
overload the assignment operator, your statement is illegal for any user
defined structs Point and ExtendedPoint.

No argument against derivation of structs.


Paule
 
Note that we have value types, not reference types. That means: it all
depends on the definition of the assignment operator. Since we cannot
overload the assignment operator, your statement is illegal for any user
defined structs Point and ExtendedPoint.

No argument against derivation of structs.

So there'd be no polymorphism possible... sounds like a good argument
against derivation of structs to me. I wouldn't be able to pass an
ExtendedPoint to a method requiring a Point, contrary to all normal
expectations. To not have a conversion available from a derived type to
the base type seems very odd to me.
 
So there'd be no polymorphism possible... sounds like a good argument
against derivation of structs to me.

Value types are not made for polymorphism, virtual functions etc. For
virtual functions to work, you need the concept of a handle, pointer,
reference etc. You need to be able to distinguish between "the handle" and
"the object", and both can be of different types. Languages like C++ make
this more clear, pointers are first-class-objects there. In C#, many people
think after the statement

T t = new T

with a class type T, that "t is an object of type T", which is of course
wrong.
I wouldn't be able to pass an
ExtendedPoint to a method requiring a Point, contrary to all normal
expectations.

Depends on your expectations. Why? A little exemple....
What would you expect the outcome of

void f( T t )
{
t.x = 1;
}

to be after a call to f?
- If T is of value type?
- If T is of reference type?

The outcome is very different - no compiler warning, nothing. Conclusion?
You have to simply *know* what kind of type T is....

Now back to your statement.
I wouldn't be able to pass an
ExtendedPoint to a method requiring a Point, contrary to all normal
expectations.

It is, of course possible, and inside the method, you will get a perfect
Point-object. For value types, this perfectly meets my expectations.

If your requirements are such that you need polymorphic behavior, don't use
value types. They are not appropriate for this.


I still cannot see why the behavior of value types should prevent
derivation. Derivation has other uses besides the polymorphism-enabler.

Paule
 
Paul Werkowitz said:
Value types are not made for polymorphism, virtual functions etc.

I agree, although they work okay for implementing interfaces, provided
you don't mind the cost of boxing.

<snip parameter passing example>

I agree, you need to know whether you're dealing with a value type or a
reference type. Mutable value types are bad idea in general though, and
should be avoided, making this kind of thing less of an issue.
It is, of course possible, and inside the method, you will get a perfect
Point-object. For value types, this perfectly meets my expectations.

But it wouldn't meet mine, probably due to different backgrounds.
If your requirements are such that you need polymorphic behavior, don't use
value types. They are not appropriate for this.

No, but I suspect I'm not the only one who will expect there to be an
implicit conversion from any type to its base type.
I still cannot see why the behavior of value types should prevent
derivation. Derivation has other uses besides the polymorphism-enabler.

True, but I think you'll agree it makes derivation less useful if you
don't get polymorphism, I think which makes it a reasonable argument
against inclusion - it means the added language/framework complexity
doesn't have as much payback as might be expected on first glance.
 
Am Mon, 14 May 2007 19:59:56 +0100 schrieb Jon Skeet [C# MVP]:
I agree, although they work okay for implementing interfaces, provided
you don't mind the cost of boxing.
No sire, they do not. Boxing transfers the value object into something
completely different. THERE IS NO SUCH THING AS virtuality / polymorphism
etc. for value types.

I agree that you can create a reference type from a value type, and that
language designers might come to the conclusion that such conversion should
sometimes be implicit. The result of such conversion is NOT of VALUE TYPE!


<snip parameter passing example>

I agree, you need to know whether you're dealing with a value type or a
reference type. Mutable value types are bad idea in general though, and
should be avoided, making this kind of thing less of an issue.

No, I strongly disagree. Two reasons:

1.) If you have for example a Rect structure .... how can you e.g. increase
it by 1 pixel without changing the values?

2.) Original problem still remains. What do we know of the passed object
after f has executed:

void f( V v )
{
v.g();
}

if
- V is of value type?
- V is of ref type?

Seems to be the same problem to me.




But it wouldn't meet mine, probably due to different backgrounds.


No, but I suspect I'm not the only one who will expect there to be an
implicit conversion from any type to its base type.
I don't understand. You think in terms of reference-semantics. For value
types, there are no references.

I hope, after the statements

int i = 5;
int k = i;
k = 0;

you do not expect i to have the value 0......

These statements transfer values! Then it is absolutely logical that the
statement in

D d = ....
B b = d;

creates a completely new B-object and initializes it with *the values* from
d.
For value types, I do not expect that b now "points" to a D-object.


True, but I think you'll agree it makes derivation less useful if you
don't get polymorphism, I think which makes it a reasonable argument
against inclusion - it means the added language/framework complexity
doesn't have as much payback as might be expected on first glance.

Also here, I don't see this. Complexity cannot be the issue. If we say,
that we can derive at all, derivation for value types is not too complex to
comprehend at all. For beginners, the distinction between value types and
reference types is much more difficult, especially because there is no
notational difference.

Greetz
Paule
 
No sire, they do not. Boxing transfers the value object into something
completely different. THERE IS NO SUCH THING AS virtuality / polymorphism
etc. for value types.

I think it doesn't help that you can override methods. Arguably the
polymorphism is only used there when it's in its boxed
I agree that you can create a reference type from a value type, and that
language designers might come to the conclusion that such conversion should
sometimes be implicit. The result of such conversion is NOT of VALUE TYPE!

Agreed. (I think the "constrain" IL op code may make things slightly
trickier here, but that's below the surface.)
No, I strongly disagree. Two reasons:

1.) If you have for example a Rect structure .... how can you e.g. increase
it by 1 pixel without changing the values?

By returning a new value, just like DateTime.AddMinutes does.
2.) Original problem still remains. What do we know of the passed object
after f has executed:

void f( V v )
{
v.g();
}

if
- V is of value type?
- V is of ref type?

Seems to be the same problem to me.

Well, you should certainly still know whether you're using a reference
type or a value type, yes.
I don't understand. You think in terms of reference-semantics. For value
types, there are no references.

But because of the way that .NET emphasises reference types over value
types (when making custom types, anyway) that changes the general feel
of the languages and thus expectations.
I hope, after the statements

int i = 5;
int k = i;
k = 0;

you do not expect i to have the value 0......

No, of course not. Assignment works by value for all types - it's just
it's the reference that's assigned in the reference type case.
These statements transfer values! Then it is absolutely logical that the
statement in

D d = ....
B b = d;

creates a completely new B-object and initializes it with *the values* from
d.
For value types, I do not expect that b now "points" to a D-object.

I agree it's a perfectly reasonable way of doing things, but it's not
what I'd have originally expected if this were allowed - which, of
course, it's not.
Also here, I don't see this. Complexity cannot be the issue. If we say,
that we can derive at all, derivation for value types is not too complex to
comprehend at all. For beginners, the distinction between value types and
reference types is much more difficult, especially because there is no
notational difference.

There is complexity in adding the feature of deriving from structs.
There is also a benefit to it. The question is whether the benefit
outweighs the cost in complexity or not. I don't believe it does, you
presumably do. That's a perfectly reasonable matter of opinion.
 
Am Wed, 16 May 2007 18:32:04 +0100 schrieb Jon Skeet [C# MVP]:[snipped]
Its a matter of opinion, ok.

But to your last statement I have a question:
There is complexity in adding the feature of deriving from structs.
There is also a benefit to it. The question is whether the benefit
outweighs the cost in complexity or not. I don't believe it does, you
presumably do. That's a perfectly reasonable matter of opinion.

What complexity do you see in the feature of deriving from a struct? We
have no polymorphism here, only the possibility to override functions and
add new ones. To write non-trivial programs in C#, you need reference
types, derivation, polymorphism, ..... the whole enchilada. Such a person
should be able to grasp the concept of derivation of value types, too,
IMHO.

Greetz!
Paule
 
Paul Werkowitz said:
Am Wed, 16 May 2007 18:32:04 +0100 schrieb Jon Skeet [C# MVP]:[snipped]
Its a matter of opinion, ok.

But to your last statement I have a question:
There is complexity in adding the feature of deriving from structs.
There is also a benefit to it. The question is whether the benefit
outweighs the cost in complexity or not. I don't believe it does, you
presumably do. That's a perfectly reasonable matter of opinion.

What complexity do you see in the feature of deriving from a struct? We
have no polymorphism here, only the possibility to override functions and
add new ones.

And add new fields, presumably. However, you *do* still need to learn
what is and isn't now allowed, and what should happen in various cases.
There's more to learn, and for little benefit IMO. (I very rarely write
my own value types to start with, and can't remember ever wanting to
derive one value type from another.)
To write non-trivial programs in C#, you need reference
types, derivation, polymorphism, ..... the whole enchilada. Such a person
should be able to grasp the concept of derivation of value types, too,
IMHO.

Yes, but in the same way that someone who has learned a difficult
language (e.g. Welsh) should be able to learn a relatively simple
language (e.g. French). That doesn't mean they would instantly *know*
French having learned Welsh. They'd have more to learn. I'm all for
keeping the language as simple as possible unless there's a really good
benefit to be gained from adding complexity (e.g. the addition of
generics and nullable types). Just MHO though.
 

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

Back
Top