Why is class Sample<T> where T : Stream, class ILLEGAL

  • Thread starter Thread starter puzzlecracker
  • Start date Start date
Why would it be invalid? All it's saying that the close type of
instance is required to be class, inherit from Stream and have
parameterless constructor.



where T: class states this about T; "Can be any class", it _doesn't_ state
"Can't be a struct" or "must at least be a class".
where T: Stream states this about T; "Must be a Stream".

Thus where T: class, Stream states this about T;
"Can be any class" and "Must be a Stream". Clearly this is contradition,
since not all classes are Streams.

Then it is a totally different beast. In this case, Stream indicates
that it has to be class Stream, and not any class. Then why

where T:class, ISomeInterface is allowed?
Agreed. The contradiction argument doesn't hold just thought it might help.
The truth is wot Marc says, the list of contraints can contain only one
primary constraint class, struct or a specific type. The reason this
restriction is there is that anything else would be pointless due to it
being redundant.
 
On Nov 4, 2:06 pm, "Anthony Jones" <[email protected]>
wrote:




No, that's not the reason - you can, for instance, do T : class, new()
which means "can be any class which has a parameterless constructor".

The problem isn't that they're contradictory, but that there's
redundancy - if you know that T derives from Stream, you already know
that T is a class.

Jon
How is it a redundancy if struct can also inherit from class
(reference type)?
 
puzzlecracker said:
How is it a redundancy if struct can also inherit from class
(reference type)?

Structs can only inherit from classes in a very, very limited set of
circumstances - when that class is Object, Enum or ValueType basically.

You can't derive a struct from Stream, for example.
 
Anthony Jones said:
I get that but the OP seemed to be struggling with redunancy as an argument.
By expressing it as a contradiction (which it is) it might be better
absorbed.

But it's the wrong reason - and if you start applying that elsewhere,
you'll get a skewed view. For instance, by your logic this should be
invalid too:

void Foo<T>() where T : class, IDisposable

That's perfectly valid though.

": class" simply doesn't mean "T can be any reference type" - it means
"T *must* be a reference type; other constraints may be applied too".
Redunancy isn't intinsically an error, for example, there are
many places where the keyword private would be redundant yet its not error
to use in those places, hence simply because something is redundant doesn't
mean its in error. So I can understand the "because its redundant" doesn't
quite cut it.

That's why it's forbidden in this case, however. There are plenty of
other places where redundancy is forbidden too - for instance,
declaring a const as "static".
I think Marc has it with the "there can be only one" primary constraint
explanation.

It's much the same thing, IMO. Note how Marc's answer referred to the
redundancy...
 
I have read the article about constraints on type parameters at

http://msdn.microsoft.com/en-us/library/d5x73970(printer).aspx

I still don't quite understand it. We implement generic classes
because we want it to be applicable to any objects.

But if a generic list class which constrains that it only takes
objects of type Employee like so:

public class GenericList<T> where T : Employee
{
private Node next;
private T data;
[snip]
}

, then why don't we simply create a specific list class like below
since it restricts to Employee type only?

public class EmployeeList
{
private Node next;
private Employee data;
[snip]
}

Any hint please? Thanks.
 
Author said:
I have read the article about constraints on type parameters at

http://msdn.microsoft.com/en-us/library/d5x73970(printer).aspx

I still don't quite understand it. We implement generic classes
because we want it to be applicable to any objects.

But if a generic list class which constrains that it only takes
objects of type Employee like so:

public class GenericList<T> where T : Employee
{
private Node next;
private T data;
[snip]
}

, then why don't we simply create a specific list class like below
since it restricts to Employee type only?

public class EmployeeList
{
private Node next;
private Employee data;
[snip]
}

Any hint please? Thanks.

Prior to the arrival of Generics in C# 2 this is exactly what you had to do.
However this is a real pain when you have some general functionality (which
is where we get the term Generic) that you have to repeat over and over
again.

You would have to create an CompanyList and an AddressList and a ProjectList
and a ... all containing pretty much identical code except for a few
methods and properties would return a specific type and/or a few parameters
would have the same specific type.

You could of course just use an existing list class that simply used object
but then you're left with casts being peppered all over the place and the
compiler couldn't give you the compile time type checking you'd like.
Alternatively you create all these various (what were known as strongly
typed) class that delegated to an internal common implementation.

What Generics gives us the ability to write the functionality once and
re-use it for various types whilst maintaining "stongly typed"
implementations that gives compile time type checking.

These:-

List<Company>
List<Employee>
List<Address>
List<Project>

automatically cause the compiler to generate new types based on a Generic
type save a whole bunch of duplicate coding.
 
I have read the article about constraints on type parameters at

I still don't quite understand it.  We implement generic classes
because we want it to be applicable to any objects.
But if a generic list class which constrains that it only takes
objects of type Employee like so:
public class GenericList<T> where T : Employee
{
       private Node next;
       private T data;
      [snip]
}
, then why don't we simply create a specific list class like below
since it restricts to Employee type only?
public class EmployeeList
{
       private Node next;
       private Employee data;
      [snip]
}
Any hint please?  Thanks.

Prior to the arrival of Generics in C# 2 this is exactly what you had to do.
However this is a real pain when you have some general functionality (which
is where we get the term Generic) that you have to repeat over and over
again.

You would have to create an CompanyList and an AddressList and a ProjectList
and a ...  all containing pretty much identical code except for a few
methods and properties would return a specific type and/or a few parameters
would have the same specific type.

You could of course just use an existing list class that simply used object
but then you're left with casts being peppered all over the place and the
compiler couldn't give you the compile time type checking you'd like.
Alternatively you create all these various (what were known as strongly
typed) class that delegated to an internal common implementation.

What Generics gives us the ability to write the functionality once and
re-use it for various types whilst maintaining "stongly typed"
implementations that gives compile time type checking.

These:-

List<Company>
List<Employee>
List<Address>
List<Project>

automatically cause the compiler to generate new types based on a Generic
type save a whole bunch of duplicate coding.

Thank you, but I guess my question was skipped. :-) I understand
Generics and I have been programming with generics for a while.

My question was this:

If we will implement a generic class GenericList and constrains it to
the type Employee as shown below,

public class GenericList<T> where T : Employee
{
private Node next;
private T data;
[snip]
}

then, why don't we simply implement a concrete EmployeeList like below
instead of implementing a generic class and restrict it to type
Employee (the latter is essentially pretending to be generic)?

public class EmployeeList
{
private Node next;
private Employee data;
[snip]
}

Do you see what I was asking now? Thanks.
 
[...]
public class GenericList<T> where T : Employee
{
       private Node next;
       private T data;
      [snip]
}
then, why don't we simply implement a concrete EmployeeList like below
instead of implementing a generic class and restrict it to type
Employee (the latter is essentially pretending to be generic)?
public class EmployeeList
{
        private Node next;
        private Employee data;
       [snip]
}
Do you see what I was asking now?  Thanks.

The short answer:

     GenericList<AccountingEmployee> accountants = ...;
     GenericList<ProductionEmployee> workers = ...;

     workers = accountants;  // FAILS!  The compiler won't let you do this

As opposed to:

     EmployeeList accountants = ...;
     EmployeeList workers = ...;

     workers = accountants; // Oops! Now we're got a bunch of CPAs handling  
dangerous machines

In fact, there are actually a number of other advantages that a  
constrained generic offers over a non-generic that just uses a base class,  
but they all generally lead to the same thing: a much-enhanced degree of  
compile-time type safety that you simply wouldn't get without generic  
classes.  In particular, it's not just about sharing funcionality; it's 
about sharing functionality without losing type information.

Pete

I just gave it a shot by having AccountingEmployee and
ProductionEmployee inheriting from Employee. And like you said, the
compiler will not allow the following assignment:

accountingEmployeeList = productionEmployeeList;

So, I think it is fair to say that when a generic class has a single
constraint (e.g. Employee), the advantage of this constrained generic
class will only show up when it is used for inherited classes of
Employee.

Otherwise, if the generic class has a single constraint (e.g.
Employee) and nothing inherits from Employee (or if Employee cannot be
inherited), then

class GenericList<T> where T: Employee

is completely equivalent to the non-generic EmployeeList as I have
shown.

Is this correct? Thanks.
 
[...]
Otherwise, if the generic class has a single constraint (e.g.
Employee) and nothing inherits from Employee (or if Employee cannot be
inherited), then
class GenericList<T> where T: Employee
is completely equivalent to the non-generic EmployeeList as I have
shown.
Is this correct?  Thanks.

Yes.  If there is only ever going to be one class that can fulfill the  
constraint, then you can only ever create a single version of the generic 
type, and so it would be impossible to ever reuse the code in the generic 
class with any other type, obviating any benefit from the generic class.

Of course, that scenario simply isn't relevant to what generics are useful  
for.  So I'm not sure that the observation is helpful.  But it is a true  
observation.  :)

Pete

The observation is helpful for people who haven't thought about
inheritance (like me, I believe many other junior OO programmers as
well) and thus are confused by the MSDN example at

http://msdn.microsoft.com/en-us/library/d5x73970.aspx

where GenerList<T> has a single constraint.

Of course, I am sure there are many junior OO programmers out there
who simply take the example for granted and never seriously think why
a single constraint for a generic class. :-)
 
Hmmm...well, that is an unfortunate code sample, I'd agree.  It does  
actually say this:

     The constraint enables the generic class to use the Employee.Name
     property because all items of type T are guaranteed to be either
     an Employee object or an object that inherits from Employee.

That is, they do explicitly call out the possibility of an inherited  
class.  But I agree, the example would be more useful if it actually  
_showed_ a constraint using a base class, and then using the generic class  
with derived types.

Hah, I am not a careful reader. I didn't notice that sentence.
Well, I still think the example isn't useful.  But at least now I know  
where it came from.  :)

You might want to consider submitting some feedback suggesting to  
Microsoft that they make the example more useful and clear by adding some 
derived types to the code for use with the generic.

Do they listen? I once wrote to them and asked if they could please
make the MSDN banner collapsible (with a + and - button click) because
my monitor is only 17", the main content area shows up very small on
my monitor and thus hard to read. (see the screen shot below) It is
not always convenient to do full-screen or to shrink the left frame
which has the navigation menus. I didn't expect them to listen
anyway.

http://gnewsgroup.googlepages.com/aspnet_portal.PNG/aspnet_portal-full;init:.PNG
 
Back
Top