F# – Adding custom indexer and slicer to your type

Indexer

If your have a type that represents a collection of values, adding a custom indexer gives you a natural way to index directly into the object using the .[ ] operator.

Take this simple Calendar class for instance, which keeps a map (F# equivalent of a Dictionary<TKey, TValue>) of notes against DateTime values:

image

By adding a custom indexer here I’m now able to write code like this:

image

Also, as you may have noticed already, F# allows you to use non-integer parameters in your indexer! In this case, I’m using a tuple of int * string * int. You can use this indexer from your C# code too:

image

One-Dimensional Slicer

That’s pretty cool, but we can go a step further by allowing you to use slicers on our types too. To allow users to get all the notes associated 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

Pretty awesome, right? But what if we want to refine our search criteria even more and let you specify 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. Thankfully, F# lets you define a two-dimensional slicer too:

image

This two-dimensional slicer allows me to query the calendar with a year range as well as a month range:

image

As you can see, indexers and slicers give the consumers of your code a much more intuitive way to interact with the data encapsulated in your type. Keep in mind though, that F# does not allow you to add slicer with more than two dimensions, but I think two-dimensional slicers should be good enough for most day-to-day requirements.

Update 2011/11/08:

Swapped out my verbose optional argument handling with defaultArg as Arseny Kapoulkine pointed out in the comments.

  • http://zeuxcg.org/ Arseny Kapoulkine

    Thanks, this is useful.
    Your method of handling optional arguments is quite verbose, defaultArg will do just fine (i.e. let lbYear = defaultArg lowerBoundYear DateTime.MinValue.Year)

  • theburningmonk

    Arseny – Thanks for the feedback, defaultArg had completely skipped my mind when I put the example together!

  • Pingback: F# equivalent of C#’s Object Initialization syntax | theburningmonk.com()

  • Mark

    Just what I wanted to know! Thank you :)