F# – Adding custom indexer and slicer to your type

Indexer

If your have a type that rep­re­sents a col­lec­tion of val­ues, adding a cus­tom index­er gives you a nat­ur­al way to index direct­ly into the object using the .[ ] oper­a­tor.

Take this sim­ple Cal­en­dar class for instance, which keeps a map (F# equiv­a­lent of a Dictionary<TKey, TVal­ue>) of notes against Date­Time val­ues:

image

By adding a cus­tom index­er here I’m now able to write code like this:

image

Also, as you may have noticed already, F# allows you to use non-inte­ger para­me­ters in your index­er! In this case, I’m using a tuple of int * string * int. You can use this index­er from your C# code too:

image

One-Dimensional Slicer

That’s pret­ty cool, but we can go a step fur­ther by allow­ing you to use slicers on our types too. To allow users to get all the notes asso­ci­at­ed with a range of years, e.g. from 1999 to 2009, let’s add a slicer:

image

So now we can do this:

image

Two-Dimensional Slicer

Pret­ty awe­some, right? But what if we want to refine our search cri­te­ria even more and let you spec­i­fy a year range as well a range of months, e.g. get me all notes for April/May/June in the years 1999 to 2009. Thank­ful­ly, F# lets you define a two-dimen­sion­al slicer too:

image

This two-dimen­sion­al slicer allows me to query the cal­en­dar with a year range as well as a month range:

image

As you can see, index­ers and slicers give the con­sumers of your code a much more intu­itive way to inter­act with the data encap­su­lat­ed in your type. Keep in mind though, that F# does not allow you to add slicer with more than two dimen­sions, but I think two-dimen­sion­al slicers should be good enough for most day-to-day require­ments.

Update 2011/11/08:

Swapped out my ver­bose option­al argu­ment han­dling with default­Arg as Arse­ny Kapoulkine point­ed out in the com­ments.