September 21, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Dynamic Programming with Lambda Expressions

  • November 25, 2009
  • By Paul Kimmel
  • Send Email »
  • More Articles »

Dynamic Programming with Lambda Expressions - Introduction

There are a lot of ways to write code. Sometimes we write code as simply as possible, straight forward-perhaps inline calculations and sometimes we add levels of indirection. Indirection, or abstraction, makes code a bit more challenging to understand, but abstraction can add flexibility and a level of dynamism that can be very powerful and useful.

This article shows you how to use Lambda expressions as function arguments to support dynamic function behavior. If you program like this for critical aspects of your application then you will create a more flexible and powerful solution.

Most of the Time

A lot of code is written in a direct way. Suppose you have an application that needs to calculate sales tax. It is reasonable to write the calculation directly. For example, in Michigan the sales tax is currently 6%. To calculate sales tax you could write:

Dim total as Double = value * (1 + .06)

If this calculation is written inline it will solve the problem, but it does not represent a flexible or reusable solution. The next evolutionary improvement is to define a function that performs the calculation, and you could provide an optional argument. For example, you could move the calculation to a function and make the amount of tax optional, providing the most common default value for the tax amount. Listing 1 shows the code moved into a function.

Listing 1: Reusable code with a regular function and optional default value.

Function CalculateSalesTax(ByVal total As Double, _
  Optional ByVal tax As Double = 0.06) As Double
  Return total * (1 + tax)
End Function

All but beginning programmers eventually get to writing code like the code shown in Listing 1 with the optional argument usage being employed eventually.

The solution in listing 1 is practical and suffices for a lot of scenarios. The only drawback is that it isn't flexible. You can pass in a total and a tax amount and the calculation is always the same. And, as I said, for routine solutions defining a well-named function is reusable and as a plus self-commenting. Sometimes though you need to write a solution that is even more flexible.

Some of the Time

Sometimes, especially if you are writing code that will be used by others, you need to write your code more flexibly. You can write your code to be more flexible by adding function parameters. Function parameters mean that part of the behavior will be passed in as a function. In general, use this approach if you aren't sure about all of the scenarios that the function must support.

You can define function parameters a couple of ways. You can define a delegate and define the function--parameter type as an argument of the delegate type or you can use one of the pre-existing generic delegates like Func. To provide the function-parameter you can add an existing second function and the AddressOf operator or you pass a Lambda Expression. Listing 2 demonstrates how to define a function- parameter using the pre-defined Func generic delegate and satisfy that argument with a Lambda Expression.

Listing 2: A function with a function parameter satisfied by a Lambda Expression.

Module Module1
  
 Sub Main()
  Dim total = CalculateSalesTax(100, 0.06, _
    Function(sale, tax) sale * (1 + tax))
  Console.WriteLine(total)
  Console.ReadLine()
 End Sub
  
 Function CalculateSalesTax(ByVal total As Double, _
  ByVal tax As Double, _
  ByVal calculator As Func(Of Double, Double, Double)) _
  As Double
  Return calculator(total, tax)
 End Function
End Module

CalculateSalesTax receives (all of it's behavior as the third argument. The third argument is defined as Func(Of Double, Double, Double), a generic delegate. Other generic delegates include Action(Of T) and Predicate(Of T).

The calculator argument can be satisfied by any function that has two double arguments and double return type. This could be the address of a function, a Lambda Expression assigned to a variable of the same type--Func(Of Double, Double, Double)--or a literal Lambda Expression. In Listing 2 the calculator argument is satisfied by the Lambda Expression

Function(sale, tax) sale * (1 + tax)

Lambda Expressions are just very condensed functions. They use the Function keyword, parameter names with or without the parameter types, and the statement that performs the work. No End Function, no function name, and no return keyword are required.

The opportunity with writing code like this is that the consumer--the programmer using the code--can determine the behavior to pass to the function--in the example CalculateSalesTax. Assume for example that the sales tax is a fixed rate unless the dollar amount exceeds $50,000. For high priced items a luxury tax is imposed in some states. Then, the consumer could incorporate the luxury tax determinator in an alternate function. Listing 3 demonstrates an alternate implementation of the code (incorporating an arbitrary value for the luxury tax).

Listing 3: An alternate implementation of the solution in Listing 2 that adds additional functionality.

Module Module1
  
 Sub Main()
   Dim calculator = Function(sale, tax) IIf(sale > 25000, _
     sale * (1 + tax + 0.02), sale * (1 + tax))
  
   Dim total = CalculateSalesTax(100000, 0.06, calculator)
   Console.WriteLine(total)
   Console.ReadLine()
 End Sub
  
 Function CalculateSalesTax(ByVal total As Double, _
     Optional ByVal tax As Double = 0.06) As Double
   Return total * (1 + tax)
 End Function
  
 Function CalculateSalesTax(ByVal total As Double, ByVal tax As Double, _
    ByVal calculator As Func(Of Double, Double, Double)) As Double
   Return calculator(total, tax)
 End Function
End Module

Notice that in the solution, a new Lambda Expression is assigned to an anonymous variable. The new Lambda Expression uses the IIf function to test whether or not the sale amount exceeds 25,000; if it does an additional amount is added to the tax amount representing a luxury tax.

Summary

The code in the solution uses a Lambda Expression and function-parameters. The solution is both reusable and very flexible because defining function-parameters means that future consumers can provide part of the solution.

Having as many ways of providing solutions as possible ensures that you are prepared for every day routine programming and exceptional programming cases. The key to great solutions is being aware of a wide variety of possible solutions and picking the best one for a given context.

Biography

Paul Kimmel is the VB Today columnist for CodeGuru.com and has written several books on object-oriented programming and .NET. Check out his upcoming book Professional DevExpress ASP.NET Controls (from Wiley) now available on Amazon.com and fine bookstores everywhere. Look for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours (from Sams). You may contact him for technology questions at pkimmel@softconcepts .com. Paul Kimmel is a Technical Evangelist for Developer Express, Inc, and you can ask him about Developer Express at paulk@devexpress.com and read his DX blog at http:// community.devexpress.com/blogs/paulk.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel