LINQ, Lambda expressions, functional programming, F#, C# 3.0, VB 9.0 and what the heck of these guys are related? (part one)
Yeah. I know. It's quite noisy, either in INDC's mailing list, or in many web that says cool features in VS 2008.
But let me straighthen up first, why I choose LINQ first? It's because becoming hot buzzwords number one. And it can get many wrong views.
UPDATE:
27th March, 2008: fixing typos, code samples are now in C# 3.0 and VB 9.0, not just C# 3.0.
LINQ views and what comes in a single query of LINQ
Ah. Language INtegrated Query. Everyone has been becoming crowded and many shouting at me, "I know it! Of course I know!" But many don't know, it's not just a new essential features of VS 2008, but it's more like one of new features of .NET 3.5.
I also often heard many mumbles that said, "LINQ is the only way","LINQ is the newest concept from Microsoft's family of programming languages", blah, blah, blah, and many leads to almost false altruism.
It can be a sad fact for us but it's true, LINQ is not all that new! In "C Omega", or Cω, the notion that you can include SQL query such as Select is already available before C# 3.0. The name itself is new. Yes, the term LINQ is new, but the concept behind it it's not new. But why I say, not all? The concept of bringing Lambda expressions to LINQ queries are new. I'll try to explain it after this LINQ views.
LINQ it's not exclusive of .NET 3.5, though. Because it's simply a set of new language features capabilities that built into the fabric of C# 3.0 and VB 9.0 language specifications in terms of new keywords and new syntaxes. Most of all, it's simply a syntactic sugar, to ease all of us writing codes especially when dealing with SQL query language syntaxes. And don't forget one thing, .NET 3.5 is still .NET 2.0 lies beneath. So, .NET 3.5 was built on top of .NET 2.0 added with .NET 3.0. It's not exclusive, right?
Since LINQ is not exclusive of .NET 3.5, it's also implied that you can still can do your hard work in doing querying data. Still, you can do many things in ".NET 2.0 ways". But we, as software developers, tend to be more productive, and can be we're obligated to be always more productive and also more innovative in doing our core responsibilities, solving business problems and coding.
So, I strongly suggest that you use LINQ if you have Visual Studio 2008, and please upgrade to VS 2008 if you have 2005 since your new learning curve is not that new. Why? I'm not a strong opponent of using LINQ. In fact, I (again) strongly suggest you to use LINQ as appropriate and wisely for your development. It's helpful. It's not a must, but it eases our coding, and also promoting easier to read and then to code (can be the other way around).
Why? Because you'll get compile time checking and Intellisense in your query syntaxes! This means less error, more focus to the query logic. Also another why is, it's a way to compose pieces of arcane nested select queries, which can have many side effects. This concept comes from functional programming, and later I'll explain this after LINQ stuffs.
But be prepared to dive the concept behind LINQ uses first. You have to know it. I strongly suiggest you to learn it also. There are some facets of many programming paradigm "hidden" from us!
A quick LINQ to SQL
First, easier to code. Why? Let me give you a basic example of LINQ querying a LINQ to SQL (formerly DLINQ)generated class that represents Customers, from our good old sample database of Northwind (it's not installled by default in SQL Server 2005, you can get it here).
These are quick step by step to get your feet wet quickly:
In this sample, I create a LINQ to SQL classes and name it Northwind.dbml
Now let's use this new classes, but please pay attention that you have to understand what really is "LINQ to SQL Classes" is.
Basically LINQ to SQL is a quick "one stop shopping ORM" tool that maps your SQL Server database, tables, relations, and also stored procedures into hierarchical objects and CLR methods.
Your database will be mapped into a DataContext, your table will be mapped to
Just add these tables from Northwind to the Northwind.dbml:
- Customer
- Order
- Order_Detail
Just for fun, add the SalesByCategory stored procedure into Northwind.dbml and you'll see this:
Now... it's quite straightforward, right? But, where's the real LINQ?
Ah, LINQ is not pictures and models. This tool simply helps us visualize this code: (in the Northwind.designer.cs)
These are the code that represents Northwind database (also conceptually):
public partial class NorthwindDataContext : System.Data.Linq.DataContext
{
private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();
#region Extensibility Method Definitions
partial void OnCreated();
partial void InsertCustomer(Customer instance);
partial void UpdateCustomer(Customer instance);
partial void DeleteCustomer(Customer instance);
partial void InsertOrder(Order instance);
partial void UpdateOrder(Order instance);
partial void DeleteOrder(Order instance);
partial void InsertOrder_Detail(Order_Detail instance);
partial void UpdateOrder_Detail(Order_Detail instance);
partial void DeleteOrder_Detail(Order_Detail instance);
#endregion
public NorthwindDataContext() :
base(global::WinFormDLinq.Properties.Settings.Default.NORTHWNDConnectionString, mappingSource)
{
OnCreated();
}
public NorthwindDataContext(string connection) :
base(connection, mappingSource)
{
OnCreated();
}
public NorthwindDataContext(System.Data.IDbConnection connection) :
base(connection, mappingSource)
{
OnCreated();
}
public NorthwindDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
public NorthwindDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
public System.Data.Linq.Table<Customer> Customers
{
get
{
return this.GetTable<Customer>();
}
}
public System.Data.Linq.Table<Order> Orders
{
get
{
return this.GetTable<Order>();
}
}
public System.Data.Linq.Table<Order_Detail> Order_Details
{
get
{
return this.GetTable<Order_Detail>();
}
}
[Function(Name="dbo.SalesByCategory")]
public ISingleResult<SalesByCategoryResult> SalesByCategory([Parameter(Name="CategoryName", DbType="NVarChar(15)")] string categoryName, [Parameter(Name="OrdYear", DbType="NVarChar(4)")] string ordYear)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), categoryName, ordYear);
return ((ISingleResult<SalesByCategoryResult>)(result.ReturnValue));
}
}
In VB:
Again, quite straightforward, eh?
The rest of the code is the declaration of tables.
Now, again, where's the LINQ, or query, or the code thingy?
I simply use the NorthwindDataContext and create a new instance of it. Then, just get Customer table from it! With a hint from Intellisense. Yes.
Okay! Now the LINQ!
In this quick sample, I dump the output of the LINQ to SQL of Customer to an IEnumerable and then put it as a DataSource of a Windows Forms GridView:
in C#:
private void Form1_Load(object sender, EventArgs e)
{
NorthwindDataContext dbnorth = new NorthwindDataContext();
var qry = from c in dbnorth.Customers
select new { c.CustomerID, c.ContactName, c.CompanyName, c.City };
this.dgvCustomer.DataSource = qry;
}
In VB:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim dbnorth As NorthwindDataContext = New NorthwindDataContext
Dim qry = From c In dbnorth.Customers _
Select c.CustomerID, c.ContactName, c.CompanyName, c.City
Me.dgvCustomer.DataSource = qry
End Sub
Run it, you'll get the same column results from the select query above:

What if I want to filter it? Hmm... Let's just say I want to get data of customers in London.
Change the code above to this:
In C#:
private void Form1_Load(object sender, EventArgs e)
{
NorthwindDataContext dbnorth = new NorthwindDataContext();
var qry = from c in dbnorth.Customers
where c.City == "London"
select new { c.CustomerID, c.ContactName, c.CompanyName, c.City };
this.dgvCustomer.DataSource = qry;
}
In VB:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim dbnorth As NorthwindDataContext = New NorthwindDataContext
Dim qry = From c In dbnorth.Customers _
Where c.City = "London" _
Select c.CustomerID, c.ContactName, c.CompanyName, c.City
Me.dgvCustomer.DataSource = qry
End Sub
you'll get this:
Voila!
More productive, right? I just create this sample code less than 5 minutes!
As you see, the "select" is now keyword. So is "where" and "from". But from comes before select, which is different from the original SQL query of SELECT.
Why? Because SQL language is not quite natural in the way the ordinary compiler process. You can't put the "select" first, since you have to know from what kind of set of data you want to manipulate or to select.
The quick notion is: I have to know from what set of data I want to select, then select it. Not the way that SELECT SQL works. Because compiler can't know at first the variables you want to select if you don't define from what data first. Now, enter the world of Declarative Programming!
Why? Because you think what you want to, not how it can be done. Declarative programming is everywhere, from WPF's XAML, to XML Schema, and to quite old domain specific language such as Prolog and our old data centric language (and also domain specific language), SQL query.
Quite funny, isn't it? You've used SQL but you didn't know what kind of taxonomy SQL query was.
But don't be happy soon, C# is not entirely Declarative Programming. It's an imperative programming family member, same as VB.NET.
See? This is why I told you up front, you have to know some concept first. And the depth doesn't stop here. Let's see how the code above is translated into, and I call it, "first phase". But before that, enter another new cool features of C# 3.0 and VB 9.0: type inferencing.
Type inferencing
See this:
var qry = from c in dbnorth.Customers
where c.City == "London"
select new { c.CustomerID, c.ContactName, c.CompanyName, c.City };
You may wonder, is it still type safe? Variable qry has no type defined up front! If you debug and hover your cursor to qry variable, you'll get IEnumerable. Actually, the code above says, "give variable qry the type of the right hand expression has". So, qry has the type of IEnumerable.
I can also create this variable x as Int32 using type inferencing:
var x = 1;
It's using var and it functions the same as Dim in VB. VB also have it. But var looks like Javascript, and Javascript is dynamic language family member. Enter the world of dynamic language!
But, again, it's up to you to decide whether this is a good or bad news, since C# is not purely dynamic language. For me this fact can be understood perfectly, because C# is intended strongly typed at first, unlike Javascript.
Now, the query code above is translated into this first phase:
var qry = dbnorth.Customers
.Where(c => c.City == "London")
.Select(c => new { c.CustomerID, c.ContactName, c.CompanyName, c.City });
Or in VB:
Dim qry = dbnorth.Customers _
.Where(Function(c) c.City = "London") _
.Select(Function(c) New With {c.CustomerID, c.ContactName, c.CompanyName, c.City})
Have you seen this syntax above before? The "c=>"?
In C#3.0 and VB 9.0, it is called Lambda Expressions. But VB is not taking the same syntax, it's written as new Function which is then translated into Lambda function. VB programmer prefers syntax that's more verbose.
The idea of Lambda Expression itself was taken from a topic of Lambda Calculus, from mathematic foundation. We now turn our journey to the world of exotic Lambda Calculus, but only as an overview in C# or VB view. Now, we're now walking towards new world of Lambda Calculus.
Lambda Calculus (or Lambda Expression in C# 3.0 and VB 9.0)
Now, what is Lambda calculus anyway? It is simply a functional view of expressing your code. But in a deep glass magnifier view, it's a formal system (as in Wikipedia) to investigate function applications and recursion.
In C# and VB, it's a functional way to express delegate and expression tree types.
(To be continued..)