Simple Sequences

It’s always interesting coming to a new codebase.

Often you find things that are done in a different way than perhaps you would code it. If you’re lucky, you might find things that are done in a better way than you might have seen before.

Take the opportunity to pass on what you know to your fellow developers and improve the code. And of course to learn everything they have to teach you too!

One simple example I encountered recently is the use of sequences.

Most developers know that arrays and lists (and others) can be treated as IEnumerable, which means that you can use foreach on them.

Often however, it’s easy to miss just how powerful and expressive sequences can be. There is also the often misunderstood yield key word.

What is this Sequence of which you speak?

A sequence can be thought of as taking one item at a time from a line of items. Like sweets from a tube.

You define what happens to each of the items as you take them. For example, you could eat them, or maybe use them to create different items in another sequence.

Let’s have a look at a simple example:

        // <summary>
        // Convert some Models into ViewModels
        // </summary>
        private IEnumerable<ViewModel> CreateViewModels(IEnumerable<Model> models)
        {
            // Create a list to put the new ViewModels in:
            var viewmodels = new List<ViewModel>();

            // Loop over ALL of the models
            foreach (var model in models)
            {
                // Create a new ViewModel:
                var viewModel = new ViewModel(model.Id, model.Name);

                // Add it to the list
                viewmodels.Add(viewModel);
            }

            // finally, return the list of ALL ViewModels
            return viewmodels;
        }

This code is simply taking some Models and converting them into ViewModels.

However, if we think of things as Sequences, then there isn’t any need for the List because we do this:


        // <summary>
        // Convert some Models into ViewModels
        // </summary>
        private IEnumerable<ViewModel> CreateViewModels(IEnumerable<Model> models)
        {
            return models.Select(m => new ViewModel(m.Id, m.Name));
        }

Now there are some very important and subtle differences in these two pieces of code and they’ll become more familiar as you get used to thinking about Sequences.

Lazy Evaluation

No ViewModels are created until the IEnumerable is evaluated. What evaluates a sequence then? Here are some examples of evaluating the sequence.


var viewModels = CreateViewModels(models);

// This pulls each viewModel, one at a time from the sequence.
foreach(var viewModel in viewModels)
{
   ...
}


var viewModels = CreateViewModels(models);

// This pulls each viewModel, one at a time and puts them into an array.
var viewModelsArray = viewModels.ToArray();


var viewModels = CreateViewModels(models);

// This pulls each viewModel, one at a time and puts them into a list.
var viewModelsArray = viewModels.ToList();


var viewModels = CreateViewModels(models);

// This pulls each viewModel, one at a time and counts them.
var viewModelsArray = viewModels.Count();

As you request the ViewModels, the Select statement in CreateViewModels pulls the models from the IEnumerable sequence.

Re-Evaluation

We’ve seen a few examples of calls that evaluate a sequence. Care must be taken to not re-evaluate the sequence repeatly when you don’t mean to.

For example:


var viewModels = CreateViewModels(models);

// The entire sequence must be evaluated to work out the count
var numberOfViewModels = viewModels.Count();

// .. and now we are evaluating the sequence from scratch again
foreach(var viewModel in viewModels)
{
    ...
}

Finally

Before this post gets too long, I’ll finish this post with a few examples of other simple keywords.

Have a think about how much work they are doing, and in particular when they are getting away with doing as little as possible.

var viewModels = CreateViewModels(models);

// This means it only takes one Model and only creates this one ViewModel
var justTheFirstViewModel = viewModels.First();
var viewModels = CreateViewModels(models);

// This means it ignores the first 3, then assigns the value of the fourth one.
// Note that it must fully evaluate (i.e. instantiate) all 4 ViewModels, then though it's ignoring the first 3.
var justTheFourthViewModel = viewModels.Skip(3).First();
var viewModels = CreateViewModels(models);

// Must read all the way through (i.e. instantiate all viewmodels in) the sequence to remember just the last one.
var justTheFourthViewModel = viewModels.Last();
Advertisements