Anders Hejlsberg talks about generics in C #, Java and C ++

xiaoxiao2021-03-06  50

Anders Hejlsberg talks about generics in C #, Java and C

[Translation] lover_p 2004-03-25 ------------------------------------------------------------------------------------------------------------------------------------------------ --------------------------------------- Original: Bill Venners, Bruce Eckel 2004.2.26 : Http://www.artima.com/intv/Generics.html Translation: lover_p

Character introduction]

Anders Hejlsberg, Microsoft famous engineers, leading his group to design 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 Elphi. 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]

Pan-type Overview of the generic C # generic and Java generic 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 (read: 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. Wan in C #

Bill Venners: How is the generic work in C #?

Anders Hejlsberg: In C # without generics, you can only write class list {...}; and in the generic C #, you can write Class List {...}, here T Is a type parameter. In List , you can use T as a type. When it is actually used to create a List object, you have to write list or list . This way you construct a new type from List , it seems that you have replaced 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 you compile List 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 , you will see if you have used list . If not, it calls JIT to compile LIST with an int type variable into 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 , 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 my program declares a list and a list , I have never used List ...

Anders Hejlsberg: ... Then the system will not instantiate List . 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 value types - such as List , list , list , list - we have established a unique can be established for each Execute the copy of the native code. Therefore, List has its own code, list has its own code, list has 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 whether it is 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 Unlike List , they actually share the code of all methods.

Anders Hejlsberg: Yes. As the detail of implementation, they actually share the same native code.

Comparison of C # generics and Java generics

Bruce Eckel: How to compare the generics and generics in Java in C #?

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, using Java generics, I think you don't actually get any performers, because when you compile a Java generic class, the compiler will replace all type parameters to Object. Of course, if you try to build a list , 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 the system.type of the List 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 reflection combine these two System.Type and create a list , and then you can also get another system.type of List . Therefore, all you can do when you can do it during compilation.

Comparison of C # generics and C templates

Bruce Eckel: How to compare C # generics and C templates?

Anders Hejlsberg: I ​​think the best understanding of C # generics and C templates is: C # generics more like class, but it has type parameters; C template is close to the macro, but it looks like class.

The biggest difference between the C # generic and C templates is the timing of the type check, and how to instantiate. First, C # is instantiated at runtime. When C is compiled, or may be instantiated when it is connected. Anyway, C 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 , methods that can be performed on a value of Type T are only those methods that can be found in the Object type, because only these methods are we guaranteed. In C #, we must ensure that all operations performed on a type parameter can be successful.

C is opposite. In C , 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 of parameter t, and x and y are T type variables, then you execute x y, if you define an Operator for two T, otherwise you can only get some meaningless wrong information. Therefore, in a sense, the C template is actually unmatched, or a weak type. And C # generics is a strong type. Constraint in the C # generic

Bruce Eckel: How is the constraint work in a C # generic?

Anders Hejlsberg: In the C # generics, we can apply constraints for type parameters. Take our List as an example, you can say Class List where t: iComparable. This means that T must implement the IComparable interface.

Bruce Eckel: Interest. In C , the constraint is implicit.

Anders Hejlsberg: Yes. We can also do this in C #. For example, we have a Dictionary , which 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 can I get a weak type template like a C template? For example, can I write a function, with two parameters A and B b, and write A B in the code? Can I say that I don't care about whether A and B have Operator because 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 parameters must have a constructor with two parameters, implement Operator , with this static method, there are two instance methods, etc.". The problem is, do you want this mode matching mechanism? Never match anything to complete mode is a whole continuous body. There is no thing (pattern matching) too small, you can't explain the problem; and complete mode matches is too complicated, so we need to find a balance point in the middle. We allow you to specify constraints as a class, one or more interfaces, and some constructors constraints. 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 this constraint when compiling and running. Any method implied by this constraint 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 Nubmerges. But you can't abstract "I must have an Operator ", we can't know the specific meaning of this sentence.

Bill Venners: You are constrained by the type 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, you can use it in the constraint system, you can use a factory model. For example, you have a Martix , 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 as a parameter, and in Calculator , 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 that C template is 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.

转载请注明原文地址:https://www.9cbs.com/read-85351.html

New Post(0)