Original: Bill Venners, Bruce Eckel 2004.2.26 Original: http://www.Artima.com/intv/Generics.html Translation: lover_p [Character Introduction] Anders Hejlsberg, Microsoft Famous Engineer, Leading His Group Designed C # (Read C-Sharp) programming language. Hejlsberg's first mounting the software industry history stage was in the early 1980s because he designed a Pascal compiler for MS-DOS and CP / M. At that time, a small company's Borland quickly hired him, and bought his compiler and renamed Turbo Pascal. In Borland, Hejlsberg continued to develop Turbo Pascal, and finally led his group to design Turbo Pascal alternatives: Delphi. In 1996, after 13 years of entering Borland, Hejlsberg joined Microsoft. Initially, he did the architect of Visual J and Windows Fundatioin Classes (WFC). Subsequently, Hejlsberg became the key participants of C #'s CEO and .NET Framework. Currently, Anders Hejlsberg is also leading the continued development of C # programming languages. Bruce Eckel, Think IN C (C Programming Thoughts) and the author of Think in Java (Java Programming Thoughts). Editor - in-chief of Bill Venners, Artima.com. [Content] Wizard Overview of the generic C # generics and Java generics comparison C # generics and C templates Constraints in C # generics
Wild outline
Bruce Eckel: Can you make a quick introduction to generics? Anders Hejlsberg: The generic is actually an ability to add type parameters to your type, also known as parameterized types or parameter polymorphism. The most famous example is the List collection class. A List is an easy-to-grow array. It has a sorting method that you can index it for it, and so on. Now, if there is no parameterized type, it is not very good regardless of the use of the array or using List. If you use an array, you can get a strong type, because you can declare an array of Customer types, but you lose your growth and those convenient methods; if you use a list, you can get all your convenience, but you lose Strong type. What is it difficult to say that a list is (type) List, it is just an Object's List [Demon "," What type of list "refers to what type is the element stored by the List. This will bring you trouble, because the type can only be checked when running, that is, the type check is not performed when compiling. Even if you have a hard to put a Customer into a list and try to get a string from it, the compiler will not be unhappy. You can't find it can't work before running. At the same time, when you put simple types [translation: pointing type], you must also pack them. It is because of these issues, you have to hover between the List and arrays, you often have to decide which one should be used. The greatness of generics is that you can enjoy your cake now because you can define a list.
(Reading: List of t) [Translation: Chinese can be said "T type List"]. When you use List, you can say what type of list it is, and you will get a strong type, the compiler will check your type. These are only the benefits of intuitiveness, and they have many other advantages. Of course, you are not only used for List, Hastable, Dictionary (the data structure of the key to the value) - all you want to call. You may want to shoot String to Customer, shoot int image to ORDER, where you can get strong types. How does the generic Bill Venners in C # work in a generic in C #? Anders Hejlsberg: In C # without generics, you can only write class list {}; and in a generic C #, you can write Class List
<
T
>
{}, T herein is a type parameter. In list
<
T
>
In, you can use T as a type. When it is actually used to build a List object, you have to write list.
<
int
>
List
<
Customer
>
. This way you are from list
<
T
>
It is a new type that looks like you replace all type parameters with your type variable. All T has become int or Customer, you don't have to convert down [Translation: INT and Customer convert to Object], they are stronger, and they are checked at any time. In CLR (Common Language Runtime, when running in public language), when you compile LIST
<
T
>
Or other generic types, they are converted to IL (Intermediate Language, Intermediate Language) and metadata. IL and metadata have additional information, you can know that this is a type of parameters, of course, the principle of the preach type of compilation and other types. At runtime, when your application first references List
<
T
>
When you look at whether you have used List?
<
int
>
. If not, it calls JIT will have a list of int type variables.
<
T
>
Compile IL and metadata. When JIT is instantly compiled by IL, the type parameters are also replaced. Bruce Eckel: So it is instantiated at runtime. Anders Hejlsberg: It is indeed instantiated at runtime. It produces a specific native code when needed. Field, when you say List
<
T
>
When you get an int type list. If the generic type is used in the type of T type, it becomes an array of INT types. Bruce Eckel: Does this class be collected by the garbage collector at a certain time? Anders Hejlsberg: Yes, this is an orthogonal issue. It will create a class in the assembly, which will always exist in the assembly. If you terminate the assembly, this class will disappear, like other classes. Bruce Eckel: But if I declare a List in my program
<
int
>
And a list
<
Cat
>
But I have never used List
<
Cat
>
... Anders Hejlsberg: ...... Then the system will not instantiate List
<
Cat
>
. Of course, except below. If you use NGen to generate a mirror, that is, if you prescribed to a mirror image of a native code, it will be pre-instantiated. However, if you run in a general environment, this instantiation is a pure demand drive (DEMAND DRIVEN), which will be delayed as much as possible [Translation] As mentioned above, until it is used]. In fact, all types we have to instantiate are all value types - such as LIST
<
int
>
List
<
Long
>
List
<
Double
>
List
<
Float
>
- We create a unique copy of the active native code for each. So List
<
int
>
Have its own code, List
<
Long
>
Have its own code, List
<
Float
>
Have its own code. We share their code for all reference types because they are the same, they are just some pointers. Bruce Eckel: So you only need to conversion. Anders Hejlsberg: No, it is actually unnecessary. We can share the original mirroring, but they actually have independent VTABLE. What I want to point out is that we just try to make meaningful sharing on the code, but we are very clear, for efficiency, there are many codes that cannot be shared. Typical is the value type, you will care about List
<
int
>
Is it int. You must not want to pack them as Object. Putting the value type is a shared method, but it will be large. Bill Venners: For reference types, different are just classes. List
<
ELEPHANT
>
Different from list
<
Orangutan
>
But they actually share the code of all methods. Anders Hejlsberg: Yes. As the detail of implementation, they actually share the same native code.
C # generic and Java generic comparison Bruce Eckel: How to compare generics in C # and generics in Java? Adners Hejlsberg: Java's generic is initially based on Martin Odersky and other people called a project called Pizza. After PIZZA is renamed GJ, then become JSR, and finally ended by Java language. This generic is capable of transporting in the original VM (Virtual Machine, virtual machine). That is, you don't have to modify your VM, but it will bring a lot of limitations. These restrictions will not appear soon, but soon you will say: "Well, this is a bit unfamiliar." For example, use Java generics, I think you can't get any performers, because when you compile one When the Java generic class, the compiler will replace all type parameters to object. Of course, if you try to build a list
<
int
>
You need to pack all INT. Therefore, this will have a lot of overhead. In addition, in order to make VM happy, the compiler must be inserted into all types of type. If a list is Object, and you want to treat these objects as Customer, you must convert Object to Customer to make the Type Checker. And it is really just to insert all of these types of conversions. Therefore, you just tasted the sweetness of the syntax, but did not get any effective efficiency. So I think this is (generic) Java's number one problem. On the second question, I think it is also a very serious problem, which is because the Java generic is implemented by eliminating all type parameters, you cannot get a reliable performance when running at runtime. When you reflect a generic List in Java, you can't learn this is a list of List. It is just a list. Because you lose type information, any dynamic type generated by the code generation scheme or reflecting scheme will not work. The only trend that makes me think is that more and more things will not be able to run, that is, because you throw the type information. But in our implementation, all of this information is available. You can use reflection to get List <
T
>
System.Type of the object. But you can't build an instance of it because you don't know what T is. But then you can use reflection to get int Sytem.Type. Then you can request reflections combine these two system.type and build a list.
<
int
>
, Then you can get List
<
int
>
Another System.Type. Therefore, all you can do when you can do it during compilation.
C # generics and C
Comparison of templates Bruce Eckel: How to compare C # generics and C
Template? Anders Hejlsberg: I think of C # generics and C
The difference between the template is the best understanding: C # generics more like class, but it has type parameters; C
The template is close to the macro, but it looks like class. C # generics and C
The biggest difference between the templates is the timing of the type checking and how to instantiate. First, C # is instantiated at runtime. C
Make instantiation when compiling or may be connected. Anyway, C
It is instantiated before the program is running. This is the first point. The second point is different, when you compile generic types, C # will perform a strong type check. For a non-constrained type parameters, such as LIST
<
T
>
The method that can perform on the value of Type T is merely those that can be found in the Object type, because only these methods are wealth. In C #, we must ensure that all operations performed on a type parameter can be successful. C
Founded. In c
In, you can perform any operation you want to do on the type of type specified by the type parameter. But once you instantiate it, it may not work, you will get some sense of blurred error messages. For example, if you have a type parameter T, and X and Y are T type variables, then you perform X
Y, if you define an Operator for two T
Fortunately, you can only get some meaningless error messages. Therefore, in a sense, C
The template is actually uncustomized, or is weak type. And C # generics is a strong type. C # 型 的 约 b b b: How does the constraint work in a C # generic? Anders Hejlsberg: In the C # generics, we can apply constraints for type parameters. Take our List
<
T
>
Take an example, you can say Class List
<
T
>
WHERE T: IComparable. This means that T must implement the IComparable interface. Bruce Eckel: Interest. In c
In the middle, the constraint is implicit. Anders Hejlsberg: Yes. We can also do this in C #. For example, we have a Dictionary
<
K, V
>
It has an add () method, this method with K Key and V Value parameters. The implementation of the Add () method will be able to compare the KEY that you have existed in KEY and Dictionary, and it wants to use a interface called ICOMPARABLE. The only way is to convert the Key parameter to the IComparable interface and then call the CompareTo method. Of course, when you do this, you have established an implicit constraint for the K type and key parameters. If you pass the enabled Key does not implement the IComparable interface, you will get a runtime error. This is likely to appear in all your methods, because your agreement does not require Key to implement the IComparable interface. Of course, you have to pay for the runtime type check because you actually perform dynamic type conversion. Using constraints, you can eliminate dynamic inspections in your code, while in compiling or loading. There will be a lot of things when you ask K to implement the IComparable interface. For the value of the K type, you can now access the interface method without the need for type conversion. Because the program can ensure that this interface is implemented in semantics. Whenever you try to build an instance of this type, the compiler checks if these types have implemented this interface, if not implemented, will give you a compilation error. If you use reflection, you will get an exception. Bruce Eckel: You are a compiler and run (you will check)? Anders Hejlsberg: The compiler will check it, but you still have to do this by reflection at runtime, so the system will check it. Just as I said earlier, anything that can be made when compiling can be done by reflection. Bruce Eckel: I can make a function template, in other words, a function with a parameter that does not know the type? You add a strong type of check to the constraint, but I can be like C
Will you get a weak type template like a template? For example, can I write a function, with two parameters A and B B, and write A in the code
b? Can I say that I don't care about whether A and B have Operator?
Since they are weak types? Anders Hejlsberg: You really want to ask questions should be what this is in the constraint? The constraint, like other characteristics, will eventually be any complicated. When you consider it, the constraint is just a pattern matching mechanism. You may want to be able to say that "this type of parameter must have a constructor with two parameters, which implements Operator.
There is this static method, there are two examples, and so on. The problem is, you want this mode matching mechanism to have more complex? From no things to complete mode matching is a whole continuous body. No things ( The pattern matching) is too small, and the problem cannot be explained; and the full mode match is too complicated, so we need to find a balance point in the middle. We allow you to specify the constraint as a class, one or more interfaces, and some constructors Constraint. For example, you can say: "This type must implement ifoo and IBAR" or "this type must inherit the base class x". Once you do this, you will check if this constraint is true when compiling and running. This Any method implied by constraints is directly effective for the value specified by the type parameters. Now, in C #, the operator is a static member. Therefore, the operator cannot be a member of the interface, so the interface constraint cannot bring You Operator
. You can only get Operator through class constraints.
You can say that this type of parameters must inherit, such as Number classes, and Number class has Operator for two Nubmergers.
. But you can't say abstract "must have an operator
", We can't know the specific meaning of this sentence. Bill Venners: You are constrained by types instead of signing. Anders Hejlsberg: Yes. Bill Venners: So this type must expand a class or implement an interface. Anders Hejlsberg: Yes And we can still go further. In fact, we have thought about it again, but this will become quite complicated. And the increased complexity is not worth it compared to the result. If you want to do it Things are not directly supported in the constraint system, you can use a plant mode. For example, you have a Martix
<
T
>
In this Martix (matrix), you may want to define a "point" [translation: a multiplication operation on the matrix, and another is called a "fork"] method. This means that you will eventually consider how to multiply two T, but you can't say this is a constraint, at least when T is not int, double or float you can't say this. But you can make your Martix have a Calculator
<
T
>
As a parameter, in Calculator
<
T
>
Among them, there is a method called Multiply. You can implement it in it and pass the results to Martix. Bruce Eckel: And Calculator is also a parameterized type. Anders Hejlsberg: Yes. This is like factory models, and there are many ways to do it, this may not be your favorite method, but doing anything to pay for a price. Bruce eckel: Yes, I started thinking C
Templates are a weak type mechanism. And when you want to add a constraint, you have moved from the weak type to a strong type. But this will definitely bring more complexity. This is the price. Anders Hejlsberg: About Type You can think it is a roulette. The higher the roulette, the less good days, but higher security. But you can turn this roulette to any way.
Quoted from:
http://bbs.mvpcn.net/showpost.aspx?postid=72