Why can't I inherit from DateTime?

  • Thread starter Thread starter Frank Rizzo
  • Start date Start date
My point is:

- ValueTypes in the system namespace can freely be optimized by the
jitter, but all other ValueTypes will be compiled as written.

No - the JIT can still optimise freely within the normal boundaries.
While it may have more knowledge about certain value types, there's
nothing to stop it from still optimising user-defined value types
heavily too, inlining operations etc.
For most applications; the boxing/unboxing is a problem that will
soon have it's remedy with generics.

And I think we both can agree on that.

That I agree with - for the most part. (Generics won't *always* prevent
boxing and unboxing. They're not a silver bullet. They'll help a great
deal though.)
 
Doh!
My understanding is it depends on how the value type is written (sans the
"primitive" value types) as to how much optimization they will get or not
get.
I should add that "primitive" value types actually use different IL opcodes,
so although the JIT will optimize them, the optimizations is going to be
different then non primitive value types...

Hope this helps
Jay
 
Jay B. Harlow said:
Michael,
??

The JITTER is free to optimize all value types equally whether they are in
the system namespace or not.

- But it can't.
I don't consider the fact that Int32 is a "primitive" as being "optimized"
or not.

- I don't either. I used the word primitive as an comparison to Java.
System.Int32 is indeed a ValueType in CIL, but not native. And that is
important.

Remember that Decimal is a value type in the System namespace, however it
is not a primitive type. I don't believe DateTime & TimeSpan are primitive
types either.

My understanding is it depends on how the value type is written (sans the
"primitive" value types) as to how much optimization they will get or not
get.

- There is no such thing as a primitive type in C#, just value types. This
is true for CIL. But there are a few types that will get special treatment
by the native JIT-compiler. Which is true not only for structs, but classes
too. String are one class I'm thinking of.
Naturally!

Hope this helps

- It did. Thanks! =)

- Michael S
 
Sorry, but I roundly disagree with you about making something like
Customer a struct (and thus a value type). This is exactly the kind of
thing that gets ex-C programmers (like me) in no end of trouble:
confusing C "structs" with C#'s value types. They are not the same. Too
many ex-C hacks continue to think that "struct" in C# should signal
some sort of "class lite", the way it does in other languages. It
absolutely doesn't. Trust me: I tried it. It sucked. Creating a

public struct Customer

is an absolutely horrible idea in C#. That's not what C# structs are
for.

At a conceptual level, C# structs are intended for those cases in which
you want _value semantics_ rather than _reference semantics_. The most
common situation is one in which you want to introduce a new type that
acts like primitive types: is immutable, is involved in calculations,
is passed by value rather than by reference, etc.

There are myriad situations in which this is a useful thing to be able
to do. C# certainly does _not_ "already give us all of the value types
we'll ever need." Not at all. For example, I work in the lumber
industry. We need fractional measures. My software needs to store 3
1/2, 11/16, and values like that. I need to be able to math with them,
reduce them, normalize them... all the stuff you need to do with
fractions. If I created a Fraction class, it would suck. I don't want
to be able to keep a reference to a Fraction and modify it. I want it
to act like an int or a double, so C# structs to the rescue! Of course,
you can do other things with structs, and they don't _have_ to be
immutable, but mutable structs are rare birds indeed, and so are more
likely than not a misuse of C#.

True, in C# you want a class 99% of the time, but structs are very
handy to have in those other 1% of cases. Structs only "suck" when you
try to use them for that for which they weren't intended. A screwdriver
makes a lousy hammer, which _doesn't_ mean that it "sucks" as a
screwdriver. Neither does it stop people from _trying_ to use it as a
hammer. :-)
 
Jon Skeet said:
Only if it's in a local variable. I fail to see how an Int32 which is
part of an instance on the heap can stick around as a register or on
the stack.

- Hehe Jon, I fail to see how you can do anything with an integer if you
don't get it into a cpu-register sooner or later. while a loop is running,
integers tend to stay in a register or in the cache. =)
I also fail to see in what way the JIT optimisation stops it from being
a value type. What value type semantics does Int32 *not* exhibit?

- That's my point. .Net and C# actually manage to get a cpu-register to come
out in C# as a dandy ValueType. It's brilliant!

However, if the jitter didn't optimize some ValueTypes, .NET would have the
blazing speed resembling a C-64. =)
That's true even at the IL level though, in this case. The DateTime
case is a bit more interesting.


If it's on the stack in the first place...

- Well as I was wrong about what a DateTime is, I'm not sure I should get
more involved. =)

My best regards Jon

- Michael
 
Michael S said:
- Hehe Jon, I fail to see how you can do anything with an integer if you
don't get it into a cpu-register sooner or later. while a loop is running,
integers tend to stay in a register or in the cache. =)

You can easily end up with integers which are *copied* into registers
or copied onto the stack though - or even just copied from one location
on the heap to another. The point is that your statement implied that
ints were *always* on the stack or in registers, which they're clearly
not.
- That's my point. .Net and C# actually manage to get a cpu-register to come
out in C# as a dandy ValueType. It's brilliant!

Agreed - but it goes against what you were saying before about it not
being a value type.
However, if the jitter didn't optimize some ValueTypes, .NET would have the
blazing speed resembling a C-64. =)

Of course.

<snip>
 
Michael S said:
- But it can't.


- I don't either. I used the word primitive as an comparison to Java.
System.Int32 is indeed a ValueType in CIL, but not native. And that is
important.

It's a primitive type which has specific CIL instructions for it.
That's pre-JIT special handling.
- There is no such thing as a primitive type in C#, just value types. This
is true for CIL.

No it's not. Look at Type.IsPrimitive. Ints not only get special
treatment by the JIT, they get special treatment by the C# compiler.

Compile the following, and then look at it in ildasm:

using System;

public class Test
{
static void Main()
{
int i = 5;
int j = 10;
int k = i+j;

decimal d = 1m;
decimal e = 2m;
decimal f = d+e;
}
}

The code for both the creation and addition is radically different for
int and decimal.
 
I stand corrected and you have a point.
Structs should be for invariant and mutable things only.

A customer should not be 'copied by value', it is one costomer, and hence
one instance.. ..of a class.

Great post Bruce

- Michael S
 
Michael,
- But it can't.
Why not?
- I don't either.
It appears you are as you are considering Int32 to be "optimized", when its
really "primitive". I don't consider the special treatment of Int32 to be
"optimized".
- There is no such thing as a primitive type in C#, just value types. This
As Jon stated, yes there are. Int32 is one of them. The primitive types are
those types that have specific IL representation/support (IL opcodes), such
as Integers & Doubles. Value types such as DateTime & Decimal are not
primitive.

Look at the IL of the sample that Jon posted, notice how the "int" IL code
is different then the "Decimal" IL code. I don't consider this an
optimization as much as its simply the difference of how code for primitive
types differ from code for non-primitive types. At a higher abstract level,
yes the IL code can be considered optimized, however the C# compiler did
this, not the jitter!

Hope this helps
Jay
 
Joanna Carter (TeamB) said:
"Michael S" <[email protected]> a écrit dans le message de (e-mail address removed)...
I am indeed looking to .NET 2.0 for the work I am doing and am hoping that
generics will greatly simplify the code I have to write.

My code could be simplified this minute if I was allowed to do it, but my
shop have a policy of 'not releasing anything built on beta'. Hence I get to
wait. Poor me...

But you could achieve the same end by marking a class as sealed. This then
also avoids the boxing overhead.
Indeed.


That is a poor definition of an interface :-)

---
* huge snip*
---

On purpose. And that's my whole issue with interfaces. They are often used
wrong.

Surely, the one great example on how interfaces are great is how XML is
handled on most platforms. I think it is excellent that an node in every
xml-stack is an interface. As it implies it is like a node. And will serve
like a node no matter the implementation.

Do you remember using COM in Delphi? It's painstaking but the best I've seen
so far. And it still ok as the the interface is there to suply for a
language-driven factory. Excellent.

And all interfaces should be 'like' someting. And I think people use
interfaces wrong often.

In your own example that I snipped, you mentioned IClonable and IDisposable.
But sometimes I stumble into to ICustomer and even IOrder. Now that is plain
bad use of interfaces. And it fails my test. Whenever do you need a
ICustomerlike object and what does an IOrderable object do? Get my point?

I use classes/interfaces for business objects as the need to pass them as
objects is more common than for the value types held in the objects.
=)

Joanna

- Michael S
 
Joanna,
But you could achieve the same end by marking a class as sealed. This then
also avoids the boxing overhead.

Sealing a Class has *no* effect on any boxing overhead! As only value types
are ever boxed!

Classes are reference types, Structures are value types.
Sealing the class prevents others from inheriting from it. Which what
Michael wants to prevent others doing to Customer.

Hope this helps
Jay
 
I'd like to help sum up this thread by putting out the _general_ rule
that when thinking about whether to implement a struct or class, if the
type is going to have only value type members, it's a candidate for a
struct, but if any of the members are going to be a reference type, it
should be implemented as a class.

For example, since my Customer object will need a String for the name
field, it must be a class.

If we look at the DateTime object, the only fields it contains are
value types.

I'd like to hear if anyone on this thread disagrees with this general
rule (aimed as people who don't intimitely understand stack/heap, etc).

Best regards,
Jeffrey Palermo
Blog: http://www.jeffreypalermo.com
 
Jeffrey Palermo said:
I'd like to help sum up this thread by putting out the _general_ rule
that when thinking about whether to implement a struct or class, if the
type is going to have only value type members, it's a candidate for a
struct, but if any of the members are going to be a reference type, it
should be implemented as a class.

I'm not sure I agree with that. In fact, I definitely don't, with a
counterexample.

See http://www.pobox.com/~skeet/csharp/threads/alternative.shtml for
the general background, and
http://www.pobox.com/~skeet/csharp/miscutil for the source - LockToken
is a struct which has a field of type Object. It absolutely should be a
struct, and it absolutely needs that field.
 
I disagree with this general rule. Whether something should be a struct
or a class does touch on whether it contains value or reference
members, however this is just one aspect of the decision, and not even
the most important one. I have a value type that contains a reference
member, and it should be a value type!

For newbies who are just starting out with C#, my general rule is
simple: you want a class. Period. Don't use structs unless you know you
need a struct.

How do you know you need a struct? You need a struct when you need
_value semantics_. There are lots of other hints that you might need a
struct, or hints that maybe that struct you built should be a class,
but that's the biggie: do you want value semantics? Do you want the
thing to act like an int or a double: be copied on every assignment, be
copied when being passed to a method, etc? Does it represent some sort
of quantity, or value, rather than a "thing" in the sense that a
Customer is a "thing" that deserves an identity whereas an integer is a
value.

Here's a big hint: could you give it a unique key? Would that make
sense? Customers have customer numbers; sales orders have sales order
numbers. These are all classes, pure and simple. An integer doesn't
have a UID, and couldn't have a UID. The concept makes no sense. That
means that it _might_ make a good value type (in the case of integer,
of course, it does).

As I said, I have a value type that contains a reference member: it's
called Measure, and it's a Decimal coupled with a unit of measure,
which is a class (reference type) in my system. Measure, however, is
clearly a value: I do mathematical operations with it. I want it to be
copied when it's assigned. I want it to be immutable: I certainly don't
want to have a reference to a Measure and go modifying it. I want it to
have _value semantics_.

On the other hand, I can imagine a class such as "annual sales figures"
that contains nothing more than values: a customer number, a start
date, and buckets for monetary values. No reference types. However, it
is a "thing," insofar as it is conceivable (and probable) that it has
UID (the customer number plus the start date). As well, you may want to
modify the sales figures for a customer for a time period. Definitely
reference semantics stuff. Definitely a class.

So, no: whether something contains only value types is not a good way
of deciding whether it needs to be a struct.
 
Jeffrey,
I too disagree with this rule!

I agree with Bruce & Jon, use a Class unless you really need to use a
Struct.

When do you need to use a Struct?

I follow the .NET Design Guidelines, in that you need a Struct when your
type needs to:
- act like primitive types
- have an instance size under 16 bytes
- are immutable
- value semantics are desired

http://msdn.microsoft.com/library/d...genref/html/cpconValueTypeUsageGuidelines.asp

The more of the above 4 items your Type needs, the more likely it needs to
be a Struct.

Hope this helps
Jay
 
Wow, great feedback. After this discussion and reading the content in
the links provided, I must take back my previous post. Yes, value
semantics must weigh out in the decision process. I _do_ like the
general rule: "Use a class" for those wondering which one to use.
Personally, I have never had the need for a struct. I do mostly
business applications where my object have an identify.

I'd like to ask a question about the 2nd MS guideline: "have an
instance size under 16 bytes". Is that really a hard and fast rule?
The DateTime struct, if you look at all the "long" members, its
instance size would be more than 16 bytes.

Best regards,
Jeffrey Palermo
Blog: http://www.jeffreypalermo.com
 
No, I think that the "less than 16 bytes" rule is more a guideline. It
simply asks you to keep in mind that value types are copied whenever
they are assigned, and if you create a large value type then all of
that copying will have a performance penalty.

However, it really depends upon how often you use the type in question,
and what else your application is doing. If your app spends all of its
time in the CPU, and the type in question is heavily used, then big
value types could be a problem.

If you're writing an application that reads from a database (and so you
spend most of your user's "real time" waiting for the database to
answer you), and the value type is not often used, then it probably
doesn't matter how big it is.
 
I'd like to ask a question about the 2nd MS guideline: "have an
instance size under 16 bytes". Is that really a hard and fast rule?
The DateTime struct, if you look at all the "long" members, its
instance size would be more than 16 bytes.

Which members are those? I think there's really just one.
 
Back
Top