Showing posts with label Lambda. Show all posts
Showing posts with label Lambda. Show all posts

Saturday, April 21, 2012

If Your Only Tool Is A Lambda, All Your Problems Will Look Like Can Be Tackled By Lambda Only

I love lambda, you love lambda, we all love lambda. When we neo-.NET kids encounters a problem that involves anything enumerable, we launch right away our lambda-fu into stratosphere, not even taking into account that there might be a simpler way to tackle the problem


For example, given a problem to sum all BigIntegers, we tend to solve it in lambda-ish way sort of way. But since a BigInteger lacks a Sum lambda/extension method, we are inclined to write it with what is available to us, i.e. we use Aggregate lambda:


using System;
using System.Linq;

using System.Numerics;

using System.Collections.Generic;


class Great 
{
 public static void Main() 
 {
  var bigInts = new List<System.Numerics.BigInteger>() {1, 2, 3, 4};

  var result = bigInts.Aggregate((currentSum, item)=> currentSum + item);
   
  Console.WriteLine(result);
 
 }
}



However, we forget that there's already a simpler alternative available to us, which is BigInteger's helper Add method. Given lambda's popularity, we tend to forget that lambdas can be fed with helper methods. If there's already a predefined helper method for a given problem, by all means use them to simplify things up. The code above could be rewritten by using predefined helper:

var bigInts = new List<System.Numerics.BigInteger>() {1, 2, 3, 4};

var result = bigInts.Aggregate(BigInteger.Add);   

Console.WriteLine(result);

Output:
10


So there we are, we can use predefined helper method, simple and has lesser noise. Lest we forgot, lambdas are just inlined delegates; so if there's already a predefined helper method that matches the lambda's delegate signature, feel free to use that helper method

Monday, July 18, 2011

Make your query malleable with Linq

Perhaps you've already seen/made this query pattern in your coding career:

SELECT *
FROM SchoolOfThought
WHERE
 (
  @inputTeacher = ''
  OR 
  Teacher = @inputTeacher
 )
 AND
 (
  @inputSubject = ''
  OR
  Subject = @inputSubject
 )
 AND
 (
  @inputQuality IS NULL
  OR
  Quality = @inputQuality
 ) 


That query is synonymous with this approach:

string inputTeacher = Console.ReadLine();
string inputSubject = Console.ReadLine();
string inputQuality = Console.ReadLine();

string filter = "";

if (inputTeacher != "")
 filter = string.Format("Teacher = '{0}'", inputTeacher);
 
if (inputSubject != "")
 filter = filter + (filter.Length != 0 ? " AND " : "" ) + string.Format("Subject = '{0}'", inputSubject);
 
if (inputQuality != "")
 filter = filter + (filter.Length != 0 ? " AND " : "" ) + string.Format("Subject = {0}", int.Parse(inputQuality));
 
string query = "SELECT * FROM SchoolOfThought " + (filter.Length != 0 ? "WHERE " + filter : "");


If the user has input on subject only, say Math, the resulting query is shorter:

SELECT  *
FROM  SchoolOfThought
WHERE Subject = 'Math';


If the user didn't input anything, The resulting query is much shorter:

SELECT  *
FROM  SchoolOfThought;



Even though concatenation approach is performant and lighter on network traffic(but don't do micro-optimizations), you will eschew the concatenation approach in favor of the first code. The reasons are twofold; first, you can't guarantee that you can safeguard your query from SQL-injection; second, code-review-wise, you don't want your code be flagged as having a code smell, the second approach is longer and look every bit as brittle.




Now, everything changes when Linq came to the scene, we no longer have to write our query patterned after the first code. We could now write the code below with a warm and fuzzy feeling that there will be no SQL-injection that could accidentally creep in the code. Lambda-using-Linq:

string inputTeacher = Console.ReadLine();
string inputSubject = Console.ReadLine();
string inputQuality = Console.ReadLine();

var query = s.Query<SchoolOfThought>();

if (inputTeacher.Length > 0)
 query = query.Where(x => x.Teacher == inputTeacher);

if (inputSubject.Length > 0)
 query = query.Where(x => x.Subject == inputSubject);

if (inputQuality.Length > 0)
 query = query.Where(x => x.Quality == int.Parse(inputQuality));

foreach (var item in query)
{
 Console.WriteLine("{0} {1} {2}", item.Teacher, item.Subject, item.Quality);
}


If you only input one variable, say Math on Subject, the resulting query will be this:

exec sp_executesql N'select schoolofth0_.SchoolOfThoughtId as SchoolOf1_3_, schoolofth0_.Teacher as Teacher3_, schoolofth0_.Subject as Subject3_, schoolofth0_.Quality as Quality3_ 
from [SchoolOfThought] schoolofth0_ 
where schoolofth0_.Subject=@p0',N'@p0 nvarchar(4000)',@p0=N'Math'



Linq-chaining has the advantage of preventing Sql-injection while maintaining the advantage of strongly-typed(as opposed to stringly-typed programming, e.g. concatenation) programming, strongly-typed means less error, you have autocomplete at your fingertips when you are using an IDE, and you have a code that is refactoring-friendly anytime. And last but not the least, with Linq you'll have more confidence the program is correct even before it is run.


If the inputSubject and inputQuality are required inputs; compiled-expression-wise, these five code has no differences:

Approach 1
string inputSubject = "Math";
string inputQuality = "80";

var query = 
 from x in s.Query<SchoolOfThought>()
 where x.Subject == inputSubject && x.Quality == int.Parse(inputQuality)
 select x;

Approach 2. Don't worry, parenthesis isn't required, compiler is not confused where the Linq boundaries end, think of from having a built-in open parenthesis, and select having a built-in close parenthesis.
string inputSubject = "Math";
string inputQuality = "80";

var query =
 from x in   
               
      from x in s.Query<SchoolOfThought>()
      where x.Subject == inputSubject
      select x  

 where x.Quality == int.Parse(inputQuality)
 select x;

Approach 3
string inputSubject = "Math";
string inputQuality = "80";

var query =
 (from x in s.Query<SchoolOfThought>()
 where x.Subject == inputSubject
 select x)
 .Where(x => x.Quality == int.Parse(inputQuality));


Approach 4
string inputSubject = "Math";
string inputQuality = "80";

var query = s.Query<SchoolOfThought>()
 .Where(x => x.Subject == inputSubject && x.Quality == int.Parse(inputQuality));

Approach 5
string inputSubject = "Math";
string inputQuality = "80";

var query = s.Query<SchoolOfThought>()
 .Where(x => x.Subject == inputSubject)
 .Where(x => x.Quality == int.Parse(inputQuality));


All the five code approaches above is compiled to this code:
exec sp_executesql 
N'select schoolofth0_.SchoolOfThoughtId as SchoolOf1_3_, schoolofth0_.Teacher as Teacher3_, schoolofth0_.Subject as Subject3_, schoolofth0_.Quality as Quality3_ 
from [SchoolOfThought] schoolofth0_ 
where schoolofth0_.Subject=@p0 and schoolofth0_.Quality=@p1',N'@p0 nvarchar(4000),@p1 int',@p0=N'Math',@p1=80 


Lastly, if you want your Linq-chaining to look as query-like(instead of Lambda-ish approach) as possible:


string inputTeacher = Console.ReadLine();
string inputSubject = Console.ReadLine();
string inputQuality = Console.ReadLine();


var query = s.Query<SchoolOfThought>();

if (inputTeacher.Length > 0)
 query = 
  from x in query 
  where x.Teacher == inputTeacher 
  select x;

if (inputSubject.Length > 0)
 query = 
  from x in query 
  where x.Subject == inputSubject 
  select x;

if (inputQuality.Length > 0)
 query = 
  from x in query 
  where x.Quality == int.Parse(inputQuality)
  select x;

I deliberately wrap the Linq clauses on their own line; so as to sway you to use the Lambda-ish approach instead, which arguably is way much shorter some of the times :-) Some of the times only, not all the times ;-)

Monday, November 8, 2010

Simulate nested recursive function in C#




This topic was inspired from search keywords that hit my site. I'm wondering why the simulated nested recursive function has a problem in C#. It turns out that compilation problem for recursive lambda in C# is isolated on Microsoft C# compiler only, that wasn't the case for Mono C# compiler (or Mono does an extra mile of performing compiler magic). This works fine on Mono C# (doesn't work on Microsoft C#):

using System;

namespace Craft
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            Func<int, int> fib = n => 
            {
                if (n == 0 || n == 1)
                    return 1;
                else
                    return fib(n - 1) + fib(n - 2);
            };
            
            
            for(int i = 0; i < 10; ++i)
                Console.WriteLine ("Hello World! {0}", fib(i));
        }
        
        
    }
}



To make that work in Microsoft C#, "forward declare" the recursive lambda(e.g. Func<int, int> functionNameHere = null) before defining the lambda.

using System;

namespace Craft
{
    class Program
    {
        public static void Main (string[] args)
        {
            // forward declarations evokes C college days :-)
            Func<int, int> fib = null; 

            fib = n => 
            {
                if (n == 0 || n == 1)
                    return 1;
                else
                    return fib(n - 1) + fib(n - 2);
            };
            
            
            for(int i = 0; i < 10; ++i)
                Console.WriteLine ("Hello World! {0}", fib(i));
        }
        
        
    }
}

Wednesday, March 31, 2010

Power of lambda










Lambda is like sudo make me sandwich:  ^_^
string prefix = "tm";

this.GetAllControls().OfType<CheckBox>()
    .Where(cx => cx.Name.Substring(0, 2) == prefix)
    .ForEach(cx => cx.Visible = false); // do something here in ForEach

The above code reads as: prepare me a list of checkbox which starts with letters tm, and i'll do something on those checkboxes. You can concentrate on things you want to do.

I'll make it myself(without lambda):
string prefix = "tm";

foreach(Control cx in this.GetAllControls())
{
    if (cx is CheckBox && cx.Name.Substring(0, 2) == prefix)
    {
        // payload here, er.. do something here
        (cx as CheckBox).Visible = false; 
    }
    
    // who can be possibly sure that prefix wasn't altered here
    // prefix = "ax";
}

The above code reads as: i'm looking at all controls, check if control is checkbox and starts with letters tm, then i'll do something on that checkbox. And because it is loop, programmers tend to re-read the loop header's condition if all corner cases are covered.