Stan Lippman's BLog

C++/CLI

Declaring Indexed Properties

What’s Different in the Revised Language Definition?

Declaring Indexed Properties

 

 

In an earlier entry on operator overloading, I showed the following construction, in which the x-coordinate of a managed reference Vector class object is directly accessed using an indexed property, as follows:

 

int main()

{

       Vector^ p2 = gcnew Vector( 1.475 );

       Vector^ p3 = gcnew Vector( p2[ 0 ], 2.4745 );

}

 

If you are not familiar with the original language, you will be as surprised as I was to discover that this construct is not supported. That is, all indexed properties are required to be given a name, and there is therefore no way, for example, to provide a managed subscript operator that can be directly applied to a Vector or Matrix class object. This is something of a fatal wound to the language if you care about subscripting. A second lexical shortcoming is that it is visually difficult to distinguish between a property declaration from that of an indexed property – the number of parameters is the only indication. Finally, indexed properties suffer from the same problems as those of scalar properties – the accessors are not treated as an atomic unit, but separated into individual methods.  For example,

 

public __gc class Vector;

public __gc class Matrix

{

    float mat[,];

 

public:

   __property void set_Item( int r, int c, float value);

   __property int get_Item( int r, int c );

 

   __property void set_Row( int r, Vector* value );

   __property int get_Row( int r );

};

 

As you can see, the indexers are distinguished only by the additional parameters to specify a two or single dimension index. In the revised syntax, the indexers are distinguished by a bracket following the name of the indexer and within which are listed the index types and optional index identifiers. In addition, as with the scalar properties, the get/set accessors are collected within a brace pair. For example,

 

public ref class Vector;

public ref class Matrix

{

private:

      array<float, 2>^ mat;

 

public:

 

      property int Item [int,int]

      {

            int get( int r, int c );

            void set( int r, int c, float value );

      }

 

      property int Row [int]

      {

            int get( int r );

            void set( int r, Vector^ value );

      }

 

};

 

The design question with regard supporting a class level index property is in how to indicate that the index applies to the class itself? There is no one solution to this. One suggestion was to use the class name, analogous to the declaration of a constructor. A second suggestion championed the this keyword. And the winner is: default. To specify a class level indexed property, one substitutes the default keyword for the user-specified name. For example,

 

public ref class Matrix

{

private:

      array<float, 2>^ mat;

 

public:

 

      // ok: class level indexer now

      //

      //     Matrix mat …

      //     mat[ 0, 0 ] = 1;

      //

      // invokes the set accessor of the default indexer …

 

      property int default [int,int]

      {

            int get( int r, int c );

            void set( int r, int c, float value );

      }

 

      property int Row [int]

      {

            int get( int r );

            void set( int r, Vector^ value );

      }

 

};

 

Some C++ programmers have expressed unhappiness with the factoring out of subscript support into the separate index facility. What’s wrong, they ask, with using the standard operator []? The primary difficulty of the subscript operator is that it is very challenging to distinguish between a read and write operation whereas it comes for free in the index property.

 

 

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

 

Published Friday, December 12, 2003 12:27 PM by slippman

Comments

 

Chris Wundram said:

I ran into this problem in the original MC++, and got around it by using the DefaultMember attribute, like this [System::Reflection::DefaultMember("Item")] public __gc class Foo { public: __property Object *get_Item(int index); } Although this only helped in the C# code that was referencing this class.
December 12, 2003 2:57 PM
 

stan lippman said:

hi, chris. yes, this is the way to have it done in the CLI for other languages that supported class-level index operators. this is another one of these thorny translation issues. in the new syntax, you would use the default index property to publish your indexer to the CLI. i have been talking with brandon bray about how to best translate this -- to give you that CLI connection plus not break any existing code within the managed application. my current thinking, without working out all the ramifications, so if you have any suggestions or concerns please let me know, is to generate a default instance, and the instance named in the attribute, the default instance stubbing to the named instance. does that sound reasonably sane?
December 17, 2003 3:17 PM
Anonymous comments are disabled

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker