Click here to Skip to main content
Click here to Skip to main content
Go to top

LINQ as Declarative Programming

, 29 Aug 2013
Rate this:
Please Sign up or sign in to vote.
How to take full advantage of declarative paradigm by using LINQ.

Introduction

The tip is aimed to show how to utilize the potential of LINQ. It also helps to understand the difference between imperative and declarative programming approaches.

Background

Assume that you're familiarized with the basics of OOP, Imperative Programming Paradigm, Declarative Programming Paradigm, C#, LINQ, Extension Methods, Expression Trees.

Issue

Consider the simple task:

Given the integers {1, ..., 1000}. Find numbers that are divisible by 29.

Let's be up to date and solve that by using the following LINQ query syntax:

from i in Enumerable.Range(1, 1000)
where i % 29 == 0
select i;  

Wow, that sounds almost like the original question! It is very readable and so declarative, isn't it? However, more experienced developer will probably automatically translate that declaration into its imperative counterpart:

foreach (var i in Enumerable.Range(1, 1000)
    if (i % 29 == 0)
        yield return i; 

The truth is that the default implementation of LINQ operators, acts in such way. While the programmer is analysing his translated imperative version of the query he points out, that the implementation is inefficient. The better solution will be as follows:

for (var i = 29; i <= 1000; i += 29)
    yield return i;  

What does he do next, for the sake of the performance? He rids off the LINQ query, writes a custom, imperative, illegible implementation and... that is the pattern, that this tip attempts to change!

Concept

To make a change, we need 3 .NET tools:

  • Extension Methods
  • Method Overloading
  • Expression Trees

LINQ beyond query syntax also has an equivalent method syntax. We might prescribe our original query to the following form:

Enumerable.Range(1, 1000).Where(i => i % 29 == 0); 

It is not as beautiful as the former, but is only aimed to facilitate further considerations. Notice that Where statement is nothing more than method invocation. An extension method Enumerable.Where is more specific. We are free to overload that method by a more concrete version that will capture our invocation:

static IEnumerable<int> Where(this IEnumerable<int> source, Func<int, bool> predicate) 

We could put the boosted algorithm here:

static IEnumerable<int> Where(this IEnumerable<int> source, Func<int, bool> predicate)
{  
    for (var i = 29; i <= 1000; i += 29)
        yield return i;
} 

But that is a one off, inflexible solution. We have ignored the predicate. Fortunately, there is a solution - Expression Trees. Look at the declaration below:

static IEnumerable<int> Where(
    this IEnumerable<int> source,
    Expression<Func<int, bool>> predicate) 

That also works well as the previous one, but gives additional advantages. It allows to explore the internals of given function. Probably the most shocking thing is that the function may never be invoked! Below is the simplified implementation of our custom Where method:

static IEnumerable<int> Where(
    this IEnumerable<int> source,
    Expression<Func<int, bool>> predicate)
{
    var body = predicate.Body as BinaryExpression;
    var bodyLeft = body.Left as BinaryExpression;
    var moduloRight = bodyLeft.Right as ConstantExpression;
    var rightValue = (int) moduloRight.Value;
 
    for (var i = rightValue; i < source.Count(); i += rightValue)
        yield return i;
}    

If something went wrong, then use standard Where method:

if (bodyLeft.NodeType != ExpressionType.Modulo)
    return Enumerable.Where(source, predicate.Compile());  

That's it! Now, we can use our original LINQ query syntax to solve the issue in a readable and also efficient way.

Declarative vs Imperative

Notice that the expression i % 29 == 0 have never been invoked! In imperative programming, you tell: Do i % 29 == 0 for each element. In declarative programming, you tell: Do what you wish, but the result must be equivalent to as you do i % 29 == 0 for each element.

Thus, LINQ may solve your task in a different manner than you can think. Keep that in mind. Free your mind from imperative and extend the usage of your LINQ.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ryszard Dżegan
Software Developer Rule Financial
Poland Poland
C# Developer.
Follow on   Twitter

Comments and Discussions

 
Question[My vote of 2] Good and bad at the same time. [modified] PinprofessionalPaulo Zemek30-Aug-13 18:34 
AnswerRe: [My vote of 2] Good and bad at the same time. PinprofessionalRyszard Dżegan30-Aug-13 20:35 
GeneralRe: [My vote of 2] Good and bad at the same time. PinprofessionalPaulo Zemek31-Aug-13 4:06 
QuestionPeculiar PinmemberFredrik Bornander29-Aug-13 22:03 
AnswerRe: Peculiar PinprofessionalRyszard Dżegan29-Aug-13 23:26 
GeneralRe: Peculiar PinmemberFredrik Bornander29-Aug-13 23:42 
GeneralRe: Peculiar PinprofessionalRyszard Dżegan30-Aug-13 0:46 
GeneralMy vote of 5 Pinmemberqq39747225129-Aug-13 20:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 29 Aug 2013
Article Copyright 2013 by Ryszard Dżegan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid