Declaring Indexed Properties


"urn:schemas-microsoft-com:office:office" />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. 
    

 


Comments (2)

  1. Chris Wundram says:

    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.

  2. stan lippman says:

    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?