What’s Different in the Revised Language Definition?

Conversion Operators




Speaking of that grotty feel to the language, having to write op_Implicit to specify a conversion just didn’t feel like C++ in the T1 language design. For example, here is a definition of MyDouble taken from the T1 language specification:


__gc struct MyDouble


   static MyDouble* op_Implicit( int i );

   static int op_Explicit( MyDouble* val );

   static String* op_Explicit( MyDouble* val );



This says that, given an integer, the algorithm for converting that integer into a MyDouble is provided by the op_Implicit operator. Moreover, that conversion will be carried out implicitly by the compiler. Similarly, given a MyDouble object, the two op_Explicit operators provide the respective algorithms for converting that object into either an integer or a managed String entity. However, the compiler will not be carried out the conversion unless explicitly requested by the user.


In C#, this would look as follows:


class MyDouble


   public static implicit operator MyDouble( int i );

   public static explicit operator int( MyDouble val );

   public static explicit operator string( MyDouble val );



And apart from the weirdness of the explicit public access label for each member, the C# code looks a lot more like C++ than the Managed Extensions to C++ does. When I was writing C# code, I could usually guess at the meaning of a construct without going to the book and that tickled my C++ basic instincts. When I write T1 code, I can never figure things out [it seems] without cracking open the book, or asking one of the experts here. Not only does that make me feel dumb, but it breaks my coding `zone’, and I don’t feel as good about what I’m doing [that is, my code], which is not good if I spend a good part of my day coding.


So we had to fix that. But how should we do that?


On one hand, C++ programmers are left slightly reeling by the absence of a single argument constructor being construed as a conversion operator. On the other hand, however, that design proved grotty enough to manage that the ISO committee introduced a keyword, explicit, just to reign in its unintended consequences – for example, an Array class which takes a single integer argument as a dimension will implicitly convert any integer into an Array object even when that is the very last thing one wants. Andy Koenig was the first person who brought that to my attention when he explained a design idiom of a dummy second argument to a constructor just to prevent such a bad thing from happening. So I don’t regret at all the absence of a single constructor implicit conversion semantic for C++/CLI.


On the other hand, it is not ever a good idea to provide a conversion pair when designing a class type within C++. The best example for that is the standard string class. The implicit conversion is the single-argument constructor taking a C-style string. However, it does not provide the corresponding implicit conversion operator – that of converting a string object to a C-style string, but rather requires the user to explicitly invoke a named function – in this case, c_str().


So, associating an implicit/explicit behavior on a conversion operator [as well as encapsulating the set of conversions to a single form of declaration] seems an improvement on the original C++ support for conversion operators, which has been a public cautionary tale since 1988 when Robert Murray gave a Usenix C++ talk  entitled Building Well-Behaved Type Relationships in C++ and which led to an explicit keyword. The revised T2 language support for conversion operators looks as follows:


ref struct MyDouble



      static operator MyDouble^ ( int i );

      static explicit operator int ( MyDouble^ val );

      static explicit operator String^ ( MyDouble^ val );



where the default behavior for the operator is to support an implicit application of the conversion algorithm, freeing us from having to introduce yet another contextual keyword (yack!).



disclaimer: This posting is provided "AS IS" with no warranties, and confers no rights.