10.1 IdentifiersLanguages that are either case-sensitive or case-insensitive can support the CLS. Since its rules apply only to items exposed to other languages, private members or types that aren't exported from an assembly may use any names they choose. For interoperation, however, there are some restrictions. In order to make tools work well with a case-sensitive language, it is important that the exact case of identifiers be maintained. At the same time, when dealing with non-English languages encoded in Unicode, there may be more than one way to represent precisely the same identifier that includes combining characters. The CLS requires that identifiers obey the restrictions of the appropriate Unicode standard and persist them in Canonical form C, which preserves case but forces combining characters into a standard representation. See CLS Rule 4, in Partition I, section 8.5.1. At the same time, it is important that externally visible names not conflict with one another when used from a case-insensitive programming language. As a result, all identifier comparisons shall be done internally to CLS-compliant tools using the Canonical form KC, which first transforms characters to their case-canonical representation. See CLS Rule 4, in Partition I, section 8.5.1. When a compiler for a CLS-compliant language supports interoperability with a non-CLS-compliant language, it must be aware that the CTS and VES perform all comparisons using code-point (i.e., byte-by-byte) comparison. Thus, even though the CLS requires that persisted identifiers be in Canonical form C, references to non-CLS identifiers will have to be persisted using whatever encoding the non-CLS language chose to use. It is a language design issue, not covered by the CTS or the CLS, precisely how this should be handled.
10.2 OverloadingNOTE The CTS, while it describes inheritance, object layout, name hiding, and overriding of virtual methods, does not discuss overloading at all. While this is surprising, it arises from the fact that overloading is entirely handled by compilers that target the CTS and not the type system itself. In the metadata, all references to types and type members are fully resolved and include the precise signature that is intended. This choice was made since every programming language has its own set of rules for coercing types and the VES does not provide a means for expressing those rules. Following the rules of the CTS, it is possible for duplicate names to be defined in the same scope as long as they differ in either kind (field, method, etc.) or signature. The CLS imposes a stronger restriction for overloading methods. Within a single scope, a given name may refer to any number of methods provided they differ in any of the following:
Notice that the signature includes more information but CLS-compliant languages need not produce or consume classes that differ only by that additional information (see Partition II for the complete list of information carried in a signature):
There is one exception to this rule. For the special names op_Implicit and op_Explicit described in Partition I, section 10.3.3 methods may be provided that differ only by their return type. These are marked specially and may be ignored by compilers that don't support operator overloading. Properties shall not be overloaded by type (that is, by the return type of their getter method), but they may be overloaded with different numbers or types of indices (that is, by the number and types of the parameters of its getter method). The overloading rules for properties are identical to the method overloading rules.
CLS Rule 37: Only properties and methods may be overloaded. CLS Rule 38: Properties, instance methods, and virtual methods may be overloaded based only on the number and types of their parameters, except the conversion operators named op_Implicit and op_Explicit, which may also be overloaded based on their return type. NOTE CLS (consumer): May assume that only properties and methods are overloaded, and need not support overloading based on return type unless providing special syntax for operator overloading. If return type overloading isn't supported, then the op_Implicit and op_Explicit may be ignored, since the functionality shall be provided in some other way by a CLS-compliant framework. CLS (extender): Should not permit the authoring of overloads other than those specified here. It is not necessary to support operator overloading at all, hence it is possible to entirely avoid support for overloading on return type. CLS (framework): Shall not publicly expose overloading except as specified here. Frameworks authors should bear in mind that many programming languages, including Object-Oriented languages, do not support overloading and will expose overloaded methods or properties through mangled names. Most languages support neither operator overloading nor overloading based on return type, so op_Implicit and op_Explicit shall always be augmented with some alternative way to gain the same functionality.
10.3 Operator OverloadingCLS-compliant consumer and extender tools are under no obligation to allow defining of operator overloading. CLS-compliant consumer and extender tools do not have to provide a special mechanism to call these methods. NOTE This topic is addressed by the CLS so that
Operator overloading is described by using the names specified below, and by setting a special bit in the metadata (SpecialName) so that they do not collide with the user's namespace. A CLS-compliant producer tool shall provide some means for setting this bit. If these names are used, they shall have precisely the semantics described here.
10.3.1 Unary OperatorsUnary operators take one argument, perform some operation on it, and return the result. They are represented as static methods on the class that defines the type of their one operand or their return type. Table 2-4, Unary Operator Names, shows the names that are defined. 10.3.2 Binary OperatorsBinary operators take two arguments, perform some operation, and return a value. They are represented as static methods on the class that defines the type of one of their two operands or the return type. Table 2-5, Binary Operator Names, shows the names that are defined. 10.3.3 Conversion OperatorsConversion operators are unary operations that allow conversion from one type to another. The operator method shall be defined as a static method on either the operand or return type. There are two types of conversions:
NOTE Conversions provide functionality that can't be generated in other ways, and many languages will not support the use of the conversion operators through special syntax. Therefore, CLS rules require that the same functionality be made available through an alternate mechanism. Using the more common ToXxx (where Xxx is the target type) and FromYyy (where Yyy is the name of the source type) naming pattern is recommended. Because these operations may exist on the class of their operand type (so-called "from" conversions) and would therefore differ on their return type only, the CLS specifically allows that these two operators be overloaded based on their return type. The CLS, however, also requires that if this form of overloading is used then the language shall provide an alternate means for providing the same functionality since not all CLS languages will implement operators with special syntax.
CLS Rule 39: If either op_Implicit or op_Explicit is provided, an alternate means of providing the coercion shall be provided. NOTE CLS (consumer): Where appropriate to the language design, use the existence of op_Implicit and/or op_Explicit in choosing method overloads and generating automatic coercions. CLS (extender): Where appropriate to the language design, implement user-defined implicit or explicit coercion operators using the corresponding op_Implicit, op_Explicit, ToXxx, and/or FromXxx methods. CLS (framework): If coercion operations are supported, they shall be provided as FromXxx and ToXxx, and optionally op_Implicit and op_Explicit as well. CLS frameworks are encouraged to provide such coercion operations.
10.4 Naming PatternsSee also Partition V[, Annex D.1, Naming Guidelines]. While the CTS does not dictate the naming of properties or events, the CLS does specify a pattern to be observed. For Events: An individual event is created by choosing or defining a delegate type that is used to signal the event. Then, three methods are created with names based on the name of the event and with a fixed signature. For the examples below we define an event named Click that uses a delegate type named EventHandler. EventAdd, used to add a handler for an event Pattern: void add_<EventName> (<DelegateType> handler) Example: void add_Click (EventHandler handler); EventRemove, used to remove a handler for an event Pattern: void remove_<EventName> (<DelegateType> handler) Example: void remove_Click (EventHandler handler); EventRaise, used to signal that an event has occurred Pattern: void family raise_<EventName> (Event e) For Properties: An individual property is created by deciding on the type returned by its getter method and the types of the getter's parameters (if any). Then, two methods are created with names based on the name of the property and these types. For the examples below we define two properties: Name takes no parameters and returns a System.String, while Item takes a System.Object parameter and returns a System.Object. Item is referred to as an indexed property, meaning that it takes parameters and thus may appear to the user as though it were an array with indices. PropertyGet, used to read the value of the property Pattern: <PropType> get_<PropName> (<Indices>) Example: System.String get_Name (); Example: System.Object get_Item (System.Object key); PropertySet, used to modify the value of the property Pattern: void set_<PropName> (<Indices>, <PropType>) Example: void set_Name (System.String name); Example: void set_Item (System.Object key, System.Object value); 10.5 ExceptionsThe CLI supports an exception handling model, which is introduced in Partition I, section 12.4.2. CLS-compliant frameworks may define and throw externally visible exceptions, but there are restrictions on the types of objects thrown:
CLS Rule 40: Objects that are thrown shall be of type System.Exception or inherit from it. Nonetheless, CLS-compliant methods are not required to block the propagation of other types of exceptions. NOTE CLS (consumer): Need not support throwing or catching of objects that are not of the specified type. CLS (extender): Must support throwing of objects of type System.Exception or a type inheriting from it. Need not support throwing of objects of other types. CLS (framework): Shall not publicly expose thrown objects that are not of type System.Exception or a type inheriting from it. 10.6 Custom AttributesIn order to allow languages to provide a consistent view of custom attributes across language boundaries, the Base Class Library provides support for the following rules defined by the CLS:
CLS Rule 41: Attributes shall be of type System.Attribute, or inherit from it. NOTE CLS (consumer): Need not support attributes that are not of the specified type. CLS (extender): Must support the authoring of custom attributes. CLS (framework): Shall not publicly expose attributes that are not of type System.Attribute or a type inheriting from it. The use of a particular attribute class may be restricted in various ways by placing an attribute on the attribute class. The System.AttributeUsageAttribute is used to specify these restrictions. The restrictions supported by the System.AttributeUsageAttribute are:
NOTE Since these are CLS rules and not part of the CTS itself, tools are required to specify explicitly the custom attributes they intend to apply to any given metadata item. That is, compilers or other tools that generate metadata must implement the AllowMultiple and Inherit rules. The CLI does not supply attributes automatically. The usage of attributes in the CLI is further described in Partition II. |