How do arrays in C# partially implement IList<T>? - c#

So as you may know, arrays in C# implement IList<T>, among other interfaces. Somehow though, they do this without publicly implementing the Count property of IList<T>! Arrays have only a Length property.
Is this a blatant example of C#/.NET breaking its own rules about the interface implementation or am I missing something?

So as you may know, arrays in C# implement IList<T>, among other interfaces
Well, yes, erm no, not really. This is the declaration for the Array class in the .NET 4 framework:
[Serializable, ComVisible(true)]
public abstract class Array : ICloneable, IList, ICollection, IEnumerable,
IStructuralComparable, IStructuralEquatable
{
// etc..
}
It implements System.Collections.IList, not System.Collections.Generic.IList<>. It can't, Array is not generic. Same goes for the generic IEnumerable<> and ICollection<> interfaces.
But the CLR creates concrete array types on the fly, so it could technically create one that implements these interfaces. This is however not the case. Try this code for example:
using System;
using System.Collections.Generic;
class Program {
static void Main(string[] args) {
var goodmap = typeof(Derived).GetInterfaceMap(typeof(IEnumerable<int>));
var badmap = typeof(int[]).GetInterfaceMap(typeof(IEnumerable<int>)); // Kaboom
}
}
abstract class Base { }
class Derived : Base, IEnumerable<int> {
public IEnumerator<int> GetEnumerator() { return null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
The GetInterfaceMap() call fails for a concrete array type with "Interface not found". Yet a cast to IEnumerable<> works without a problem.
This is quacks-like-a-duck typing. It is the same kind of typing that creates the illusion that every value type derives from ValueType which derives from Object. Both the compiler and the CLR have special knowledge of array types, just as they do of value types. The compiler sees your attempt at casting to IList<> and says "okay, I know how to do that!". And emits the castclass IL instruction. The CLR has no trouble with it, it knows how to provide an implementation of IList<> that works on the underlying array object. It has built-in knowledge of the otherwise hidden System.SZArrayHelper class, a wrapper that actually implements these interfaces.
Which it doesn't do explicitly like everybody claims, the Count property you asked about looks like this:
internal int get_Count<T>() {
//! Warning: "this" is an array, not an SZArrayHelper. See comments above
//! or you may introduce a security hole!
T[] _this = JitHelpers.UnsafeCast<T[]>(this);
return _this.Length;
}
Yes, you can certainly call that comment "breaking the rules" :) It is otherwise darned handy. And extremely well hidden, you can check this out in SSCLI20, the shared source distribution for the CLR. Search for "IList" to see where the type substitution takes place. The best place to see it in action is clr/src/vm/array.cpp, GetActualImplementationForArrayGenericIListMethod() method.
This kind of substitution in the CLR is pretty mild compared to what happens in the language projection in the CLR that allows writing managed code for WinRT (aka Metro). Just about any core .NET type gets substituted there. IList<> maps to IVector<> for example, an entirely unmanaged type. Itself a substitution, COM doesn't support generic types.
Well, that was a look at what happens behind the curtain. It can be very uncomfortable, strange and unfamiliar seas with dragons living at the end of the map. It can be very useful to make the Earth flat and model a different image of what's really going on in managed code. Mapping it to everybody favorite answer is comfortable that way. Which doesn't work so well for value types (don't mutate a struct!) but this one is very well hidden. The GetInterfaceMap() method failure is the only leak in the abstraction that I can think of.

New answer in the light of Hans's answer
Thanks to the answer given by Hans, we can see the implementation is somewhat more complicated than we might think. Both the compiler and the CLR try very hard to give the impression that an array type implements IList<T> - but array variance makes this trickier. Contrary to the answer from Hans, the array types (single-dimensional, zero-based anyway) do implement the generic collections directly, because the type of any specific array isn't System.Array - that's just the base type of the array. If you ask an array type what interfaces it supports, it includes the generic types:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Output:
System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
For single-dimensional, zero-based arrays, as far as the language is concerned, the array really does implement IList<T> too. Section 12.1.2 of the C# specification says so. So whatever the underlying implementation does, the language has to behave as if the type of T[] implements IList<T> as with any other interface. From this perspective, the interface is implemented with some of the members being explicitly implemented (such as Count). That's the best explanation at the language level for what's going on.
Note that this only holds for single-dimensional arrays (and zero-based arrays, not that C# as a language says anything about non-zero-based arrays). T[,] doesn't implement IList<T>.
From a CLR perspective, something funkier is going on. You can't get the interface mapping for the generic interface types. For example:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Gives an exception of:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
So why the weirdness? Well, I believe it's really due to array covariance, which is a wart in the type system, IMO. Even though IList<T> is not covariant (and can't be safely), array covariance allows this to work:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... which makes it look like typeof(string[]) implements IList<object>, when it doesn't really.
The CLI spec (ECMA-335) partition 1, section 8.7.1, has this:
A signature type T is compatible-with a signature type U if and only if at least one of the following holds
...
T is a zero-based rank-1 array V[], and U is IList<W>, and V is array-element-compatible-with W.
(It doesn't actually mention ICollection<W> or IEnumerable<W> which I believe is a bug in the spec.)
For non-variance, the CLI spec goes along with the language spec directly. From section 8.9.1 of partition 1:
Additionally, a created vector with element type T, implements the interface System.Collections.Generic.IList<U>, where U := T. (§8.7)
(A vector is a single-dimensional array with a zero base.)
Now in terms of the implementation details, clearly the CLR is doing some funky mapping to keep the assignment compatibility here: when a string[] is asked for the implementation of ICollection<object>.Count, it can't handle that in quite the normal way. Does this count as explicit interface implementation? I think it's reasonable to treat it that way, as unless you ask for the interface mapping directly, it always behaves that way from a language perspective.
What about ICollection.Count?
So far I've talked about the generic interfaces, but then there's the non-generic ICollection with its Count property. This time we can get the interface mapping, and in fact the interface is implemented directly by System.Array. The documentation for the ICollection.Count property implementation in Array states that it's implemented with explicit interface implementation.
If anyone can think of a way in which this kind of explicit interface implementation is different from "normal" explicit interface implementation, I'd be happy to look into it further.
Old answer around explicit interface implementation
Despite the above, which is more complicated because of the knowledge of arrays, you can still do something with the same visible effects through explicit interface implementation.
Here's a simple standalone example:
public interface IFoo
{
void M1();
void M2();
}
public class Foo : IFoo
{
// Explicit interface implementation
void IFoo.M1() {}
// Implicit interface implementation
public void M2() {}
}
class Test
{
static void Main()
{
Foo foo = new Foo();
foo.M1(); // Compile-time failure
foo.M2(); // Fine
IFoo ifoo = foo;
ifoo.M1(); // Fine
ifoo.M2(); // Fine
}
}

IList<T>.Count is implemented explicitly:
int[] intArray = new int[10];
IList<int> intArrayAsList = (IList<int>)intArray;
Debug.Assert(intArrayAsList.Count == 10);
This is done so that when you have a simple array variable, you don't have both Count and Length directly available.
In general, explicit interface implementation is used when you want to ensure that a type can be used in a particular way, without forcing all consumers of the type to think about it that way.
Edit: Whoops, bad recall there. ICollection.Count is implemented explicitly. The generic IList<T> is handled as Hans descibes below.

Explicit interface implementation. In short, you declare it like void IControl.Paint() { } or int IList<T>.Count { get { return 0; } }.

It's no different than an explicit interface implementation of IList. Just because you implement the interface doesn't mean its members need to appear as class members. It does implement the Count property, it just doesn't expose it on X[].

With reference-sources being available:
//----------------------------------------------------------------------------------------
// ! READ THIS BEFORE YOU WORK ON THIS CLASS.
//
// The methods on this class must be written VERY carefully to avoid introducing security holes.
// That's because they are invoked with special "this"! The "this" object
// for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]
// where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will
// see a lot of expressions that cast "this" "T[]".
//
// This class is needed to allow an SZ array of type T[] to expose IList<T>,
// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is
// made:
//
// ((IList<T>) (new U[n])).SomeIListMethod()
//
// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,
// finds the corresponding generic method (matched simply by method name), instantiates
// it for type <T> and executes it.
//
// The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be
// array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly
// "T[]" - for orefs, it may be a "U[]" where U derives from T.)
//----------------------------------------------------------------------------------------
sealed class SZArrayHelper {
// It is never legal to instantiate this class.
private SZArrayHelper() {
Contract.Assert(false, "Hey! How'd I get here?");
}
/* ... snip ... */
}
Specifically this part:
the interface stub dispatcher treats this as a special case, loads up
SZArrayHelper, finds the corresponding generic method (matched simply
by method name), instantiates it for type and executes it.
(Emphasis mine)
Source (scroll up).

Related

Relation between IEnumerable and arrays

What makes .Net IEnumerable so special that compiler types like arrays can be passed as an argument in its place with it being a class library interface. Is there some sort of inheritance in the background?
What actually happens when an array can interchangeably replace a collection or IEnumerable as a parameter:
public void DoJob(IEnumerable<Job> jobs)
{
}
Like this method call:
Job job = new Job();
DoJob(new [] { job });
Since you came from Java, I will start by telling you that in C#, there is a unified type system, where every type derives from object, unlike in Java where there are special "primitives".
So in C#, arrays are just another type. Who says they can't implement interfaces? They can! All the compiler provides is some syntax for creating them. In actuality, arrays' type is System.Array.
This is its declaration:
public abstract class Array : ICloneable, IList, ICollection,
IEnumerable, IStructuralComparable, IStructuralEquatable
See IEnumerable in there?
EDIT:
For IEnumerable<T>, we can find it in the language spec:
Section 12.1.2:
A one-dimensional array T[] implements the interface
System.Collections.Generic.IList (IList for short) and its base
interfaces.
IList<T> implements IEnumerable<T>.
Arrays are a special case in .NET, because you are not allowed to directly inherit from the Array class.
From the documentation:
Single-dimensional arrays implement the IList<T>, ICollection<T>, IEnumerable<T>, IReadOnlyList<T> and IReadOnlyCollection<T> generic interfaces. The implementations are provided to arrays at run time, and as a result, the generic interfaces do not appear in the declaration syntax for the Array class.
This is due to the fact that generics did not exist in .NET 1.0, and to prevent breaking changes, a compiler hack had to be applied.
IEnumerable is an Interface and what you're referring to is Polymorphism.
Arrays, Lists, Collections, and many other types in .NET have a base IEnumerable interface at a minimum. If you make the parameter request Job[] then only an array of Job could be used, meaning a List or other collection would have to be converted to an Array before it could be passed to the parameter. This means the method, hopefully is dealing with and expecting the array for a specific reason. If the method doesn't care about the type of collection, list, or array and simply wants to iterate through the items, then it should look lower in the inheritance tree so that many types can use the method. Making the method IEnumerable<Job> allows the method to work with ANY type that derives from IEnumerable<T> where, in this case, T is of type Job.
Knowing this a List<Job>, ObservableCollection<Job>, Job[] or linq query with select of Job plus many more can use this method.

How do interfaces like IEnumerable work without proper implementation?

From what I understand on interfaces, is that in order to use them, you must declare that a class is implementing it by adding the name of the interface after a colon and then, implement the methods.
I'm currently learning about Enumerators, IEnumerable etc. and this got me confused. Here's an example of what I mean:
static IEnumerable<int> Fibs(int fibCount)
{
for (int i = 0, prevFib = 1, curFib = 1; i < fibCount; i++) {
yield return prevFib;
int newFib = prevFib + curFib;
prevFib = curFib;
curFib = newFib;
}
}
IEnumerable seems to be a normal interface as any other, I even checked the method definition and that's what it pretty much seems like.
How is it possible that I can use an interface as a type/return type in the method definition and when/how do I know I should use certain interfaces as types like in this example?
EDIT: I really doubt it has anything to do with the yield keyword since a lot of interfaces are used as properties this way for example in MVC in Models and passed like it to Views. Example:
public IEnumerable<Category> Categories {get;set;}
There is extra magic when you use yield keyword, i.e. create an iterator block. The compiler makes a state machine for you.
So C# has a special feature here, and it only has this feature with IEnumerable<>. So it is the C# language which is magical.
The interface IEnumerable<> in itself is a boring ordinary type. No magic in it.
Note: Technically, the yield magic works when the "formal" return type is either IEnumerable<>, IEnumerator<>, IEnumerable, or IEnumerator, but usually you use the first of these. Do not go non-generic, of course.
IEnumerable is a special case. The yield return statement instructs the compiler to add the code that implements IEnumerable.
As for your edit:
If an interface is used a the type of a property, any object of a class that implements this interface can be assigned and the property will return an object that implements this interface. In your example, any collection of categories that implements IEnumerable<Category> can be assigned to the property, e.g. a List<Category>. In comparison to using just List<Category>, using the interface allows a wider range of objects to be assigned. The interface defines the abstract requirements that are relevant for the property.
In C#, interfaces are a special "kind" of type that differs from a class in a few key ways:
You cannot include any implementation code of their methods.
A single class can "inherit from" (called "implementing") as many as it wants.
You cannot instantiate a new instance of an interface.
(There is also some language features associated specifically with interfaces, such as explicit implementations, but those aren't important for this discussion.)
Beyond that, interfaces can be use pretty much anywhere you can use any other reference type. That includes defining fields, properties, or local variables with interface types, or using them as parameter types or return types on methods.
The trick is, if you define a property as, say, an IEnumerable<int>, and you want to set it's value, you cannot do this:
public IEnumerable<int> Numbers { get; set; }
...
this.Numbers = new IEnumerable<int>();
That's an error. You can't create a new instance of an interface, because it's just a "template" -- there's nothing "behind" it to actually do anything. However, you can do this:
public IEnumerable<int> Numbers { get; set; }
...
this.Numbers = new List<int>();
Because List<T> implements IEnumerable<T>, the compiler will automatically do the type conversion to make the assignment work. Any concrete class that implements IEnumerable<> can be assigned to a property of type IEnumerable<>, which is why you see interface property types so often. It allows you to change the underlying concrete type (maybe you want to change List<T> to ObservableCollection<T>, but the users of your class neither know nor care when you do.
The same goes for methods with an interface return type, except there's an extra option here that C# throws in as a bonus:
public IEnumerable<string> GetName()
{
// this fails.
return new IEnumerable<string>();
// this works.
return new List<String>();
// this also works because magic!~
yield return "hello";
yield return "there";
yield return "!";
}
That last case is a special form of "syntactic sugar" that C# provides because it's such a common requirement. As other people have mentioned, the compiler specifically looks for yield return statements on methods that return IEnumerable or IEnumerator (both generic and non-generic versions) and does some hefty rewriting of the code.
Behind the scenes, C# is creating a hidden class, which implements IEnumerable<string>, and implementing it's GetEnumerator method to return an IEnumerator<string> object that provides those three string values. That would be a lot of boilerplate code for you to write, although you could certainly write it yourself. In previous versions of C#, there was no yield and you did have to write it yourself.
If you really want to know, you can find the C# equivalent here, among other places. In essence, it takes the method that contains your yield statements and creates a IEnumerator<>.MoveNext method out of it, but turning it into a state machine. It uses the equivalent of labels and goto statements to jump back to the correct place each time a consumer calls MoveNext on the same instance. Also, as I understand it, it does things that you can't actually do in C# (it jumps into and out of loops) but that are legal in IL code, so it's implementation is more efficient that what you could write yourself.
But once you get past the secret cause of the yield keyword, you're still doing the same thing. You're still creating a class, that implements IEnumerable<>, and using that as the return value for your method.
For your specific example, even though the method return type is IEnumerable<int>, the actual return type will be a type that implements IEnumerable<int>. As others have mentioned, the ‘yield return’ results in a type which implements IEnumerable<int>. In this specific case, you don’t know what that type is. When I run this through the debugger and do a result.GetType() (where result is returned from the Fibs method), I see that result is of type <Fibs>d__0, which sounds a little strange to me. So instead of worrying about that strange-sounding type, we can just treat it like an IEnumerable<int>, because all we really want to be able to do is to iterate over it, which is the behavior that IEnumerable<int> exposes.
That’s for your specific example, but the idea is the same elsewhere. By using an interface, you are saying that you don’t care exactly what type is used/returned, as long as it exposes certain behavior or properties. For example if I have an interface IFoo that exposes a method DoSomething(), and I have a method that returns IFoo, then I can return anything that implements IFoo, but no matter what I return, the caller of the method is sure that it can DoSomething() with the object. Similarly, if I have a method that takes an IFoo, then the method is sure that it will be able to DoSomething() with that parameter.
For me interfaces also help me design my classes. For example I write the interface first to determine what’s important for the class to be able to do and have, and then I create the concrete class that implements that interface. And when I’m writing code that uses the class, I ask for the interface rather than the concrete type.
And there’s all sorts of other reasons to use interfaces, for example to create mocks for testing, for dependency injection, for fluent API design, and probably a hundred other reasons.

More on implicit conversion operators and interfaces in C# (again)

Okay. I've read this post, and I'm confused on how it applies to my example (below).
class Foo
{
public static implicit operator Foo(IFooCompatible fooLike)
{
return fooLike.ToFoo();
}
}
interface IFooCompatible
{
Foo ToFoo();
void FromFoo(Foo foo);
}
class Bar : IFooCompatible
{
public Foo ToFoo()
{
return new Foo();
}
public void FromFoo(Foo foo)
{
}
}
class Program
{
static void Main(string[] args)
{
Foo foo = new Bar();
// should be the same as:
// var foo = (new Bar()).ToFoo();
}
}
I have thoroughly read the post I linked to. I have read section 10.10.3 of the C# 4 specification. All of the examples given relate to generics and inheritance, where the above does not.
Can anyone explain why this is not allowed in the context of this example?
Please no posts in the form of "because the specification says so" or that simply quote the specification. Obviously, the specification is insufficient for my understanding, or else I would not have posted this question.
Edit 1:
I understand that it's not allowed because there are rules against it. I am confused as to why it's not allowed.
I understand that it's not allowed because there are rules against it. I am confused as to why it's not allowed.
The general rule is: a user defined conversion must not in any way replace a built-in conversion. There are subtle ways that this rule can be violated involving generic types, but you specifically say that you are not interested in generic type scenarios.
You cannot, for example, make a user-defined conversion from MyClass to Object, because there already is an implicit conversion from MyClass to Object. The "built in" conversion will always win, so allowing you to declare a user-defined conversion would be pointless.
Moreover, you cannot even make a user-defined implicit conversion that replaces a built-in explicit conversion. You cannot, for example, make a user-defined implicit conversion from Object to MyClass because there already is a built-in explicit conversion from Object to MyClass. It is simply too confusing to the reader of the code to allow you to arbitrarily reclassify existing explicit conversions as implicit conversions.
This is particularly the case where identity is involved. If I say:
object someObject = new MyClass();
MyClass myclass = (MyClass) someObject;
then I expect that this means "someObject actually is of type MyClass, this is an explicit reference conversion, and now myclass and someObject are reference equal". If you were allowed to say
public static implicit operator MyClass(object o) { return new MyClass(); }
then
object someObject = new MyClass();
MyClass myclass = someObject;
would be legal, and the two objects would not have reference equality, which is bizarre.
Already we have enough rules to disqualify your code, which converts from an interface to an unsealed class type. Consider the following:
class Foo { }
class Foo2 : Foo, IBlah { }
...
IBlah blah = new Foo2();
Foo foo = (Foo) blah;
This works, and one reasonably expects that blah and foo are reference equals because casting a Foo2 to its base type Foo does not change the reference. Now suppose this is legal:
class Foo
{
public static implicit operator Foo(IBlah blah) { return new Foo(); }
}
If that is legal then this code is legal:
IBlah blah = new Foo2();
Foo foo = blah;
we have just converted an instance of a derived class to its base class but they are not reference equal. This is bizarre and confusing, and therefore we make it illegal. You simply may not declare such an implicit conversion because it replaces an existing built-in explicit conversion.
So alone, the rule that you must not replace any built-in conversion by any user-defined conversion is sufficient to deny you the ability to create a conversion that takes an interface.
But wait! Suppose Foo is sealed. Then there is no conversion between IBlah and Foo, explicit or implicit, because there cannot possibly by a derived Foo2 that implements IBlah. In this scenario, should we allow a user-defined conversion between Foo and IBlah? Such a user-defined conversion cannot possibly replace any built-in conversion, explicit or implicit.
No. We add an additional rule in section 10.10.3 of the spec that explicitly disallows any user-defined conversion to or from an interface, regardless of whether this replaces or does not replace a built-in conversion.
Why? Because one has the reasonable expectation that when one converts a value to an interface, that you are testing whether the object in question implements the interface, not asking for an entirely different object that implements the interface. In COM terms, converting to an interface is QueryInterface -- "do you implement this interface?" -- and not QueryService -- "can you find me someone who implements this interface?"
Similarly, one has a reasonable expectation that when one converts from an interface, one is asking whether the interface is actually implemented by an object of the given target type, and not asking for an object of the target type that is entirely different from the object that implements the interface.
Thus, it is always illegal to make a user-defined conversion that converts to or from an interface.
However, generics muddy the waters considerably, the spec wording is not very clear, and the C# compiler contains a number of bugs in its implementation. Neither the spec nor the implementation are correct given certain edge cases involving generics, and that presents a difficult problem for me, the implementer. I am actually working with Mads today on clarifying this section of the spec, as I am implementing it in Roslyn next week. I will attempt to do so with as few breaking changes as possible, but a small number may be necessary in order to bring the compiler behaviour and the specification language in line with each other.
The context of your example, it won't work again because the implicit operator has been placed against an interface... I'm not sure how you think your sample is different to the one you linked other than you try to get one concrete type across to another via an interface.
There is a discussion on the topic here on connect:
http://connect.microsoft.com/VisualStudio/feedback/details/318122/allow-user-defined-implicit-type-conversion-to-interface-in-c
And Eric Lippert might have explained the reason when he said in your linked question:
A cast on an interface value is always treated as a type test because
it is almost always possible that the object really is of that type
and really does implement that interface. We don't want to deny you
the possibility of doing a cheap representation-preserving conversion.
It seems to be to do with type identity. Concrete types relate to each other via their hierarchy so type identity can be enforced across it. With interfaces (and other blocked things such as dynamic and object) type identity becomes moot because anyone/everyone can be housed under such types.
Why this is important, I have no idea.
I prefer explicit code that shows me I am trying to get a Foo from another that is IFooCompatible, so a conversion routine that takes a T where T : IFooCompatible returning Foo.
For your question I understand the point of discussion, however my facetious response is if I see code like Foo f = new Bar() in the wild I would very likely refactor it.
An alternative solution:
Don't over egg the pudding here:
Foo f = new Bar().ToFoo();
You have already exposed the idea that Foo compatible types implement an interface to achieve compatibility, use this in your code.
Casting versus converting:
It is also easy to get wires crossed about casting versus converting. Casting implies that type information is integral between the types you are casting around, hence casting doesn't work in this situation:
interface IFoo {}
class Foo : IFoo {}
class Bar : IFoo {}
Foo f = new Foo();
IFoo fInt = f;
Bar b = (Bar)fInt; // Fails.
Casting understands the type hierarchy and the reference of fInt cannot be cast to Bar as it is really Foo. You could provide a user-defined operator to possibly provide this:
public static implicit operator Foo(Bar b) { };
And doing this in your sample code works, but this starts to get silly.
Converting, on the other hand, is completely independent of the type hierarchy. Its behaviour is entirely arbitrary - you code what you want. This is the case you are actually in, converting a Bar to a Foo, you just happen to flag convertible items with IFooCompatible. That interface doesn't make casting legal across disparate implementing classes.
As for why interfaces are not allowed in user-defined conversion operators:
Why can't I use interface with explicit operator?
The short version is that it's disallowed so that the user can be
certain that conversions between reference types and interfaces
succeed if and only if the reference type actually implements that
interface, and that when that conversion takes place that the same
object is actually being referenced.
Okay, here's an example of why I believe the restriction is here:
class Foo
{
public static implicit operator Foo(IFooCompatible fooLike)
{
return fooLike.ToFoo();
}
}
class FooChild : Foo, IFooCompatible
{
}
...
Foo foo = new FooChild();
IFooCompatible ifoo = (IFooCompatible) foo;
What should the compiler do here, and what should happen at execution time? foo already refers to an implementation of IFooCompatible, so from that point of view it should just make it a reference conversion - but the compiler doesn't know that's the case, so should it actually just call the implicit conversion?
I suspect the basic logic is: don't allow an operator to defined which could conflict with an already-valid conversion based on the execution-time type. It's nice for there to be exactly zero or one possible conversion from an expression to a target type.
(EDIT: Adam's answer sounds like it's talking about pretty much the same thing - feel free to regard my answer as merely an example of his :)
What would probably be helpful here would be for .net to provide a "clean" way to associate an interface with a static type, and have various types of operations on interface types map to corresponding operations on the static type. In some scenarios this can be accomplished with extension methods, but that is both ugly and limited. Associating with interfaces with static classes could offer some significant advantages:
Presently, if an interface wishes to offer consumers multiple overloads of a function, every implementation must implement every overload. Pairing a static class with an interface, and allowing that class to declare methods in the style of extension methods would allow consumers of the class to use overloads provided by the static class as though they were part of the interface, without requiring implementers to provide them. This can be done with extension methods, but it requires that the static method be manually imported on the consumer side.
There are many circumstances where an interface will have some static methods or properties which are very strongly associated with it (e.g. `Enumerable.Empty`). Being able to use the same name for the interface and the 'class' of the associated properties would seem cleaner than having to use separate names for the two purposes.
It would provide a path to supporting optional interface members; if a member exists in an interface but not an implementation, the vtable slot could be bound to a static method. This would be an extremely useful feature, since it would allow interfaces to be extended without breaking existing implementations.
Given that unfortunately such a feature only exists to the extent necessary to work with COM objects, the best alternative approach I can figure would be to define a struct type which holds a single member of interface type, and implements the interface by acting as a proxy. Conversion from the interface to the struct would not require creation of an extra object on the heap, and if functions were to provide overloads which accepted that struct, they could convert back to the interface type in a manner whose net result would be value-preserving and not require boxing. Unfortunately, passing such a struct to a method which used the interface type would entail boxing. One could limit the depth of boxing by having the struct's constructor check whether the interface-type object that was passed to it was a nested instance of that struct, and if so unwrap one layer of boxing. That could be a bit icky, but might be useful in some cases.

Struct/Class to Interface substitution contract broken?

public interface IVector<TScalar> {
void Add(ref IVector<TScalar> addend);
}
public struct Vector3f : IVector<float> {
public void Add(ref Vector3f addend);
}
Compiler answer:
"Vector3f does not implement interface member IVector<float>.Add(ref IVector<float>)"
But you can do this:
public interface IVector<T, TScalar>
where T : IVector<T, TScalar>
{
void Add(ref T addend);
}
public struct Vector3f : IVector<Vector3f, float>
{
public void Add(ref Vector3f addend)
{
}
}
However, this means you've got mutable structs, which you shouldn't. To have immutable ones, you'd need to redefine the interface:
public interface IVector<T, TScalar>
where T : IVector<T, TScalar>
{
T Add(T addend);
}
public struct Vector3f : IVector<Vector3f, float>
{
public Vector3f Add(Vector3f addend)
{
}
}
EDIT:
As Anthony Pegram points out, there are holes in this pattern. Nonetheless, it's widely used. For example:
struct Int32 : IComparable<Int32> ...
For more information, here is a link to Eric Lippert's article Curiouser and curiouser about this pattern.
Others have noted a difficulty with your interface, which is that there isn't any way to cleanly identify classes which can operate mutually with other items of their own class; this difficulty stems in some measure from the fact that such classes violate the Liskov Substitution Principle; if a class accepts two objects of type baseQ and expects to have one operate on each other, then the LSP would dictate that one should be able to replace one of the baseQ objects with a derivedQ. This in turn implies that a baseQ should operate on a derivedQ, and a derivedQ should operate on a baseQ. More broadly, any derivative of baseQ should operate on any other derivative of baseQ. The interface is thus not covariant, nor contravariant, nor invariant, but rather non-generic.
If the reason one wishes to use generics is to allow one's interfaces to act upon structs without boxing, the pattern given in phoog's answer is a good one. One generally shouldn't worry about imposing reflexive constraints on type parameters, since the purpose of the interfaces is to be used not as constraints, rather than variable or parameter types, and the necessary conditions can be imposed by the routine using the constraints (e.g. VectorList<T,U> where T:IVector<T,U>).
Incidentally, I should mention that the behavior of interface types used as constraints is very different from that of variables and parameters of interface type. For every struct type, there is another type derived from ValueType; this latter type will exhibit reference semantics rather than value semantics. If a variable or parameter of a value type is passed to a routine or stored in a variable that requires a class type, the system will copy the contents to a new class object derived from ValueType. If the struct in question is immutable, any and all such copies will always hold the same content as the original and each other, and may thus be regarded as being generally semantically equivalent to the original. If, however, the struct in question is mutable, such copying operations may yield semantics very different from what might be expected. While there are times it can be useful to have interface methods mutate structs, such interfaces must be used with extreme care.
For example, consider the behavior of List<T>.Enumerator, which implements IEnumerator<T>. Copying one variable of type List<T>.Enumerator to another of that same type will take a "snapshot" of the list position; calling MoveNext on one variable will not affect the other. Copying such a variable to one of type Object, IEnumerator<T>, or an interface derived from IEnumerator<T>, will also take a shapshot, and as above calling MoveNext on either the original or the new variable will leave the other unaffected. On the other hand, copying one variable of type Object, IEnumerator<T>, or an interface derived from IEnumerator<T> to another which is also one of those types (same or different), will not take a snapshot, but simply copy a reference to the earlier-created snapshot.
There are times it can be useful to have all copies of a variable be semantically equivalent. There are other times it can be useful for them to be semantically detached. Unfortunately, if one isn't careful, one may end up with an odd mish-mosh of semantics which could only be described as "semantically confusing".

What is cool about generics, why use them?

I thought I'd offer this softball to whomever would like to hit it out of the park. What are generics, what are the advantages of generics, why, where, how should I use them? Please keep it fairly basic. Thanks.
Allows you to write code/use library methods which are type-safe, i.e. a List<string> is guaranteed to be a list of strings.
As a result of generics being used the compiler can perform compile-time checks on code for type safety, i.e. are you trying to put an int into that list of strings? Using an ArrayList would cause that to be a less transparent runtime error.
Faster than using objects as it either avoids boxing/unboxing (where .net has to convert value types to reference types or vice-versa) or casting from objects to the required reference type.
Allows you to write code which is applicable to many types with the same underlying behaviour, i.e. a Dictionary<string, int> uses the same underlying code as a Dictionary<DateTime, double>; using generics, the framework team only had to write one piece of code to achieve both results with the aforementioned advantages too.
I really hate to repeat myself. I hate typing the same thing more often than I have to. I don't like restating things multiple times with slight differences.
Instead of creating:
class MyObjectList {
MyObject get(int index) {...}
}
class MyOtherObjectList {
MyOtherObject get(int index) {...}
}
class AnotherObjectList {
AnotherObject get(int index) {...}
}
I can build one reusable class... (in the case where you don't want to use the raw collection for some reason)
class MyList<T> {
T get(int index) { ... }
}
I'm now 3x more efficient and I only have to maintain one copy. Why WOULDN'T you want to maintain less code?
This is also true for non-collection classes such as a Callable<T> or a Reference<T> that has to interact with other classes. Do you really want to extend Callable<T> and Future<T> and every other associated class to create type-safe versions?
I don't.
Not needing to typecast is one of the biggest advantages of Java generics, as it will perform type checking at compile-time. This will reduce the possibility of ClassCastExceptions which can be thrown at runtime, and can lead to more robust code.
But I suspect that you're fully aware of that.
Every time I look at Generics it gives
me a headache. I find the best part of
Java to be it's simplicity and minimal
syntax and generics are not simple and
add a significant amount of new
syntax.
At first, I didn't see the benefit of generics either. I started learning Java from the 1.4 syntax (even though Java 5 was out at the time) and when I encountered generics, I felt that it was more code to write, and I really didn't understand the benefits.
Modern IDEs make writing code with generics easier.
Most modern, decent IDEs are smart enough to assist with writing code with generics, especially with code completion.
Here's an example of making an Map<String, Integer> with a HashMap. The code I would have to type in is:
Map<String, Integer> m = new HashMap<String, Integer>();
And indeed, that's a lot to type just to make a new HashMap. However, in reality, I only had to type this much before Eclipse knew what I needed:
Map<String, Integer> m = new Ha Ctrl+Space
True, I did need to select HashMap from a list of candidates, but basically the IDE knew what to add, including the generic types. With the right tools, using generics isn't too bad.
In addition, since the types are known, when retrieving elements from the generic collection, the IDE will act as if that object is already an object of its declared type -- there is no need to casting for the IDE to know what the object's type is.
A key advantage of generics comes from the way it plays well with new Java 5 features. Here's an example of tossing integers in to a Set and calculating its total:
Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);
int total = 0;
for (int i : set) {
total += i;
}
In that piece of code, there are three new Java 5 features present:
Generics
Autoboxing and unboxing
For-each loop
First, generics and autoboxing of primitives allow the following lines:
set.add(10);
set.add(42);
The integer 10 is autoboxed into an Integer with the value of 10. (And same for 42). Then that Integer is tossed into the Set which is known to hold Integers. Trying to throw in a String would cause a compile error.
Next, for for-each loop takes all three of those:
for (int i : set) {
total += i;
}
First, the Set containing Integers are used in a for-each loop. Each element is declared to be an int and that is allowed as the Integer is unboxed back to the primitive int. And the fact that this unboxing occurs is known because generics was used to specify that there were Integers held in the Set.
Generics can be the glue that brings together the new features introduced in Java 5, and it just makes coding simpler and safer. And most of the time IDEs are smart enough to help you with good suggestions, so generally, it won't a whole lot more typing.
And frankly, as can be seen from the Set example, I feel that utilizing Java 5 features can make the code more concise and robust.
Edit - An example without generics
The following is an illustration of the above Set example without the use of generics. It is possible, but isn't exactly pleasant:
Set set = new HashSet();
set.add(10);
set.add(42);
int total = 0;
for (Object o : set) {
total += (Integer)o;
}
(Note: The above code will generate unchecked conversion warning at compile-time.)
When using non-generics collections, the types that are entered into the collection is objects of type Object. Therefore, in this example, a Object is what is being added into the set.
set.add(10);
set.add(42);
In the above lines, autoboxing is in play -- the primitive int value 10 and 42 are being autoboxed into Integer objects, which are being added to the Set. However, keep in mind, the Integer objects are being handled as Objects, as there are no type information to help the compiler know what type the Set should expect.
for (Object o : set) {
This is the part that is crucial. The reason the for-each loop works is because the Set implements the Iterable interface, which returns an Iterator with type information, if present. (Iterator<T>, that is.)
However, since there is no type information, the Set will return an Iterator which will return the values in the Set as Objects, and that is why the element being retrieved in the for-each loop must be of type Object.
Now that the Object is retrieved from the Set, it needs to be cast to an Integer manually to perform the addition:
total += (Integer)o;
Here, a typecast is performed from an Object to an Integer. In this case, we know this will always work, but manual typecasting always makes me feel it is fragile code that could be damaged if a minor change is made else where. (I feel that every typecast is a ClassCastException waiting to happen, but I digress...)
The Integer is now unboxed into an int and allowed to perform the addition into the int variable total.
I hope I could illustrate that the new features of Java 5 is possible to use with non-generic code, but it just isn't as clean and straight-forward as writing code with generics. And, in my opinion, to take full advantage of the new features in Java 5, one should be looking into generics, if at the very least, allows for compile-time checks to prevent invalid typecasts to throw exceptions at runtime.
If you were to search the Java bug database just before 1.5 was released, you'd find seven times more bugs with NullPointerException than ClassCastException. So it doesn't seem that it is a great feature to find bugs, or at least bugs that persist after a little smoke testing.
For me the huge advantage of generics is that they document in code important type information. If I didn't want that type information documented in code, then I'd use a dynamically typed language, or at least a language with more implicit type inference.
Keeping an object's collections to itself isn't a bad style (but then the common style is to effectively ignore encapsulation). It rather depends upon what you are doing. Passing collections to "algorithms" is slightly easier to check (at or before compile-time) with generics.
Generics in Java facilitate parametric polymorphism. By means of type parameters, you can pass arguments to types. Just as a method like String foo(String s) models some behaviour, not just for a particular string, but for any string s, so a type like List<T> models some behaviour, not just for a specific type, but for any type. List<T> says that for any type T, there's a type of List whose elements are Ts. So List is a actually a type constructor. It takes a type as an argument and constructs another type as a result.
Here are a couple of examples of generic types I use every day. First, a very useful generic interface:
public interface F<A, B> {
public B f(A a);
}
This interface says that for some two types, A and B, there's a function (called f) that takes an A and returns a B. When you implement this interface, A and B can be any types you want, as long as you provide a function f that takes the former and returns the latter. Here's an example implementation of the interface:
F<Integer, String> intToString = new F<Integer, String>() {
public String f(int i) {
return String.valueOf(i);
}
}
Before generics, polymorphism was achieved by subclassing using the extends keyword. With generics, we can actually do away with subclassing and use parametric polymorphism instead. For example, consider a parameterised (generic) class used to calculate hash codes for any type. Instead of overriding Object.hashCode(), we would use a generic class like this:
public final class Hash<A> {
private final F<A, Integer> hashFunction;
public Hash(final F<A, Integer> f) {
this.hashFunction = f;
}
public int hash(A a) {
return hashFunction.f(a);
}
}
This is much more flexible than using inheritance, because we can stay with the theme of using composition and parametric polymorphism without locking down brittle hierarchies.
Java's generics are not perfect though. You can abstract over types, but you can't abstract over type constructors, for example. That is, you can say "for any type T", but you can't say "for any type T that takes a type parameter A".
I wrote an article about these limits of Java generics, here.
One huge win with generics is that they let you avoid subclassing. Subclassing tends to result in brittle class hierarchies that are awkward to extend, and classes that are difficult to understand individually without looking at the entire hierarchy.
Wereas before generics you might have classes like Widget extended by FooWidget, BarWidget, and BazWidget, with generics you can have a single generic class Widget<A> that takes a Foo, Bar or Baz in its constructor to give you Widget<Foo>, Widget<Bar>, and Widget<Baz>.
Generics avoid the performance hit of boxing and unboxing. Basically, look at ArrayList vs List<T>. Both do the same core things, but List<T> will be a lot faster because you don't have to box to/from object.
The best benefit to Generics is code reuse. Lets say that you have a lot of business objects, and you are going to write VERY similar code for each entity to perform the same actions. (I.E Linq to SQL operations).
With generics, you can create a class that will be able to operate given any of the types that inherit from a given base class or implement a given interface like so:
public interface IEntity
{
}
public class Employee : IEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int EmployeeID { get; set; }
}
public class Company : IEntity
{
public string Name { get; set; }
public string TaxID { get; set }
}
public class DataService<ENTITY, DATACONTEXT>
where ENTITY : class, IEntity, new()
where DATACONTEXT : DataContext, new()
{
public void Create(List<ENTITY> entities)
{
using (DATACONTEXT db = new DATACONTEXT())
{
Table<ENTITY> table = db.GetTable<ENTITY>();
foreach (ENTITY entity in entities)
table.InsertOnSubmit (entity);
db.SubmitChanges();
}
}
}
public class MyTest
{
public void DoSomething()
{
var dataService = new DataService<Employee, MyDataContext>();
dataService.Create(new Employee { FirstName = "Bob", LastName = "Smith", EmployeeID = 5 });
var otherDataService = new DataService<Company, MyDataContext>();
otherDataService.Create(new Company { Name = "ACME", TaxID = "123-111-2233" });
}
}
Notice the reuse of the same service given the different Types in the DoSomething method above. Truly elegant!
There's many other great reasons to use generics for your work, this is my favorite.
I just like them because they give you a quick way to define a custom type (as I use them anyway).
So for example instead of defining a structure consisting of a string and an integer, and then having to implement a whole set of objects and methods on how to access an array of those structures and so forth, you can just make a Dictionary
Dictionary<int, string> dictionary = new Dictionary<int, string>();
And the compiler/IDE does the rest of the heavy lifting. A Dictionary in particular lets you use the first type as a key (no repeated values).
Typed collections - even if you don't want to use them you're likely to have to deal with them from other libraries , other sources.
Generic typing in class creation:
public class Foo < T> {
public T get()...
Avoidance of casting - I've always disliked things like
new Comparator {
public int compareTo(Object o){
if (o instanceof classIcareAbout)...
Where you're essentially checking for a condition that should only exist because the interface is expressed in terms of objects.
My initial reaction to generics was similar to yours - "too messy, too complicated". My experience is that after using them for a bit you get used to them, and code without them feels less clearly specified, and just less comfortable. Aside from that, the rest of the java world uses them so you're going to have to get with the program eventually, right?
To give a good example. Imagine you have a class called Foo
public class Foo
{
public string Bar() { return "Bar"; }
}
Example 1
Now you want to have a collection of Foo objects. You have two options, LIst or ArrayList, both of which work in a similar manner.
Arraylist al = new ArrayList();
List<Foo> fl = new List<Foo>();
//code to add Foos
al.Add(new Foo());
f1.Add(new Foo());
In the above code, if I try to add a class of FireTruck instead of Foo, the ArrayList will add it, but the Generic List of Foo will cause an exception to be thrown.
Example two.
Now you have your two array lists and you want to call the Bar() function on each. Since hte ArrayList is filled with Objects, you have to cast them before you can call bar. But since the Generic List of Foo can only contain Foos, you can call Bar() directly on those.
foreach(object o in al)
{
Foo f = (Foo)o;
f.Bar();
}
foreach(Foo f in fl)
{
f.Bar();
}
Haven't you ever written a method (or a class) where the key concept of the method/class wasn't tightly bound to a specific data type of the parameters/instance variables (think linked list, max/min functions, binary search, etc.).
Haven't you ever wish you could reuse the algorthm/code without resorting to cut-n-paste reuse or compromising strong-typing (e.g. I want a List of Strings, not a List of things I hope are strings!)?
That's why you should want to use generics (or something better).
The primary advantage, as Mitchel points out, is strong-typing without needing to define multiple classes.
This way you can do stuff like:
List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();
Without generics, you would have to cast blah[0] to the correct type to access its functions.
Don't forget that generics aren't just used by classes, they can also be used by methods. For example, take the following snippet:
private <T extends Throwable> T logAndReturn(T t) {
logThrowable(t); // some logging method that takes a Throwable
return t;
}
It is simple, but can be used very elegantly. The nice thing is that the method returns whatever it was that it was given. This helps out when you are handling exceptions that need to be re-thrown back to the caller:
...
} catch (MyException e) {
throw logAndReturn(e);
}
The point is that you don't lose the type by passing it through a method. You can throw the correct type of exception instead of just a Throwable, which would be all you could do without generics.
This is just a simple example of one use for generic methods. There are quite a few other neat things you can do with generic methods. The coolest, in my opinion, is type inferring with generics. Take the following example (taken from Josh Bloch's Effective Java 2nd Edition):
...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
return new HashMap<K, V>();
}
This doesn't do a lot, but it does cut down on some clutter when the generic types are long (or nested; i.e. Map<String, List<String>>).
Generics allow you to create objects that are strongly typed, yet you don't have to define the specific type. I think the best useful example is the List and similar classes.
Using the generic list you can have a List List List whatever you want and you can always reference the strong typing, you don't have to convert or anything like you would with a Array or standard List.
the jvm casts anyway... it implicitly creates code which treats the generic type as "Object" and creates casts to the desired instantiation. Java generics are just syntactic sugar.
I know this is a C# question, but generics are used in other languages too, and their use/goals are quite similar.
Java collections use generics since Java 1.5. So, a good place to use them is when you are creating your own collection-like object.
An example I see almost everywhere is a Pair class, which holds two objects, but needs to deal with those objects in a generic way.
class Pair<F, S> {
public final F first;
public final S second;
public Pair(F f, S s)
{
first = f;
second = s;
}
}
Whenever you use this Pair class you can specify which kind of objects you want it to deal with and any type cast problems will show up at compile time, rather than runtime.
Generics can also have their bounds defined with the keywords 'super' and 'extends'. For example, if you want to deal with a generic type but you want to make sure it extends a class called Foo (which has a setTitle method):
public class FooManager <F extends Foo>{
public void setTitle(F foo, String title) {
foo.setTitle(title);
}
}
While not very interesting on its own, it's useful to know that whenever you deal with a FooManager, you know that it will handle MyClass types, and that MyClass extends Foo.
From the Sun Java documentation, in response to "why should i use generics?":
"Generics provides a way for you to communicate the type of a collection to the compiler, so that it can be checked. Once the compiler knows the element type of the collection, the compiler can check that you have used the collection consistently and can insert the correct casts on values being taken out of the collection... The code using generics is clearer and safer.... the compiler can verify at compile time that the type constraints are not violated at run time [emphasis mine]. Because the program compiles without warnings, we can state with certainty that it will not throw a ClassCastException at run time. The net effect of using generics, especially in large programs, is improved readability and robustness. [emphasis mine]"
Generics let you use strong typing for objects and data structures that should be able to hold any object. It also eliminates tedious and expensive typecasts when retrieving objects from generic structures (boxing/unboxing).
One example that uses both is a linked list. What good would a linked list class be if it could only use object Foo? To implement a linked list that can handle any kind of object, the linked list and the nodes in a hypothetical node inner class must be generic if you want the list to contain only one type of object.
If your collection contains value types, they don't need to box/unbox to objects when inserted into the collection so your performance increases dramatically. Cool add-ons like resharper can generate more code for you, like foreach loops.
Another advantage of using Generics (especially with Collections/Lists) is you get Compile Time Type Checking. This is really useful when using a Generic List instead of a List of Objects.
Single most reason is they provide Type safety
List<Customer> custCollection = new List<Customer>;
as opposed to,
object[] custCollection = new object[] { cust1, cust2 };
as a simple example.
In summary, generics allow you to specify more precisily what you intend to do (stronger typing).
This has several benefits for you:
Because the compiler knows more about what you want to do, it allows you to omit a lot of type-casting because it already knows that the type will be compatible.
This also gets you earlier feedback about the correctnes of your program. Things that previously would have failed at runtime (e.g. because an object couldn't be casted in the desired type), now fail at compile-time and you can fix the mistake before your testing-department files a cryptical bug report.
The compiler can do more optimizations, like avoiding boxing, etc.
A couple of things to add/expand on (speaking from the .NET point of view):
Generic types allow you to create role-based classes and interfaces. This has been said already in more basic terms, but I find you start to design your code with classes which are implemented in a type-agnostic way - which results in highly reusable code.
Generic arguments on methods can do the same thing, but they also help apply the "Tell Don't Ask" principle to casting, i.e. "give me what I want, and if you can't, you tell me why".
I use them for example in a GenericDao implemented with SpringORM and Hibernate which look like this
public abstract class GenericDaoHibernateImpl<T>
extends HibernateDaoSupport {
private Class<T> type;
public GenericDaoHibernateImpl(Class<T> clazz) {
type = clazz;
}
public void update(T object) {
getHibernateTemplate().update(object);
}
#SuppressWarnings("unchecked")
public Integer count() {
return ((Integer) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) {
// Code in Hibernate for getting the count
}
}));
}
.
.
.
}
By using generics my implementations of this DAOs force the developer to pass them just the entities they are designed for by just subclassing the GenericDao
public class UserDaoHibernateImpl extends GenericDaoHibernateImpl<User> {
public UserDaoHibernateImpl() {
super(User.class); // This is for giving Hibernate a .class
// work with, as generics disappear at runtime
}
// Entity specific methods here
}
My little framework is more robust (have things like filtering, lazy-loading, searching). I just simplified here to give you an example
I, like Steve and you, said at the beginning "Too messy and complicated" but now I see its advantages
Obvious benefits like "type safety" and "no casting" are already mentioned so maybe I can talk about some other "benefits" which I hope it helps.
First of all, generics is a language-independent concept and , IMO, it might make more sense if you think about regular (runtime) polymorphism at the same time.
For example, the polymorphism as we know from object oriented design has a runtime notion in where the caller object is figured out at runtime as program execution goes and the relevant method gets called accordingly depending on the runtime type. In generics, the idea is somewhat similar but everything happens at compile time. What does that mean and how you make use of it?
(Let's stick with generic methods to keep it compact) It means that you can still have the same method on separate classes (like you did previously in polymorphic classes) but this time they're auto-generated by the compiler depend on the types set at compile time. You parametrise your methods on the type you give at compile time. So, instead of writing the methods from scratch for every single type you have as you do in runtime polymorphism (method overriding), you let compilers do the work during compilation. This has an obvious advantage since you don't need to infer all possible types that might be used in your system which makes it far more scalable without a code change.
Classes work the pretty much same way. You parametrise the type and the code is generated by the compiler.
Once you get the idea of "compile time", you can make use "bounded" types and restrict what can be passed as a parametrised type through classes/methods. So, you can control what to be passed through which is a powerful thing especially you've a framework being consumed by other people.
public interface Foo<T extends MyObject> extends Hoo<T>{
...
}
No one can set sth other than MyObject now.
Also, you can "enforce" type constraints on your method arguments which means you can make sure both your method arguments would depend on the same type.
public <T extends MyObject> foo(T t1, T t2){
...
}
Hope all of this makes sense.
I once gave a talk on this topic. You can find my slides, code, and audio recording at http://www.adventuresinsoftware.com/generics/.
Using generics for collections is just simple and clean. Even if you punt on it everywhere else, the gain from the collections is a win to me.
List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
stuff.do();
}
vs
List stuffList = getStuff();
Iterator i = stuffList.iterator();
while(i.hasNext()) {
Stuff stuff = (Stuff)i.next();
stuff.do();
}
or
List stuffList = getStuff();
for(int i = 0; i < stuffList.size(); i++) {
Stuff stuff = (Stuff)stuffList.get(i);
stuff.do();
}
That alone is worth the marginal "cost" of generics, and you don't have to be a generic Guru to use this and get value.
Generics also give you the ability to create more reusable objects/methods while still providing type specific support. You also gain a lot of performance in some cases. I don't know the full spec on the Java Generics, but in .NET I can specify constraints on the Type parameter, like Implements a Interface, Constructor , and Derivation.
Enabling programmers to implement generic algorithms - By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type-safe and easier to read.
Stronger type checks at compile time - A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.
Elimination of casts.

Categories