Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Sunday, December 18, 2011

LINQ and Functional Object-Oriented Programming

It took me a while to come around to the "functional turn" in object-oriented programming. This includes the growth of Clojure and Haskell, as well as Microsoft's new LINQ and F# languages. I've been familiar with functional languages like LISP for some time, but it was hard for me to see how such an austere and limited paradigm could be fruitfully imported into the world of polymorphic objects. Furthermore, as someone well familiar with the dangers of bad SQL programming, the last thing I wanted was to allow a Zelda character to write my queries for me.

I haven't changed my mind about using LINQ to access a database, because database performance is too important to me. However, I have found LINQ to be extremely useful for shredding and joining data into custom data structures made up of generic data types. I do this to pass information between layers of abstraction, such as through WCF, or between classes. For example, you could turn a data table into a list of dictionaries, which could be serialized easily into a custom contract. You could then shred that returned structure into whatever you want, such as key value pairs in an IEnumerable of an anonymous type defining points in a chart.

Many of the recent changes to the C# language have been to make it more functional. C# 4.0 is mostly about dynamic typing, but 3.5 is all about LINQ--or rather, the typing and syntactical changes that make LINQ possible. If you've been away from C# for a few years, the language might look almost completely alien to you due to the introduction of Lambda expressions, expression trees, extension methods, implicit typing, nullable types, anonymous types, and anonymous functions. These features let you do pretty much anything you want with data on the fly.

var Points =
   from DataRow dr in dt.Rows
   where (String)dr["Program"].Trim() == Program
   select new
   {
        Date = (DateTime)dr["Date"],
        Value = Convert.ToDouble(dr[Metric] ?? 0.0)
   };
Though applications like this are where I use LINQ primarily, I can see its attraction for database querying. One of the ugliest and most difficult-to-debug pieces of OO code is SQL statements defined as string literals in application code. It's particularly ugly in VB.NET, since you have to include ampersands and end-of-line characters. The solution has always been to used stored procedures for all data access, but this best practice is not always practiced. LINQ provides you with strong typing, which is nothing to sneeze at. One of the biggest problems with SQL is its lack of type checking, especially when creating dynamic SQL. You could create some really cool data access classes that use LINQ instead of dynamic SQL.

Whether or not you use C#'s LINQ or Java's Clojure, the functional turn in object-oriented programming is interesting for its own sake. On the one hand, languages are becoming more and more flexible and intuitive. They allow you to do a lot with a few lines, and in an intuitive manner that abstracts away details. On the other hand, languages are becoming more complicated than ever. In reading Jon Skeet's C# in Depth, I kept thinking how much more information it provided than I needed to get the job done. I'll be very interested to see how further hybridizations of language provide ever more useful tools, especially for manipulating data.

Sunday, November 6, 2011

A Typology of Type Systems

When talking about type systems, a lot of terms get thrown around--strong, dynamic, safe, etc.--and it's often not clear what we're talking about. Jon Skeet provides a useful set of categories in his C# In Depth, a book so good that it's not just of use for C# developers. How a language handles types is a big part of what separates it from other languages, and it largely determines how it feels to code in it. It's important to remember that languages don't have to be typed, but typing creates a useful layer of abstraction that helps optimize performance, readability, and safety.

Static vs. Dynamic Typing: A language has static typing if the type of a variable must be known before run time. Compiled languages are statically-typed, whereas dynamic languages are dynamically-typed. For instance, Pascal, C++, and Scala are statically-typed while JavaScript, Ruby, Erlang, and PHP are dynamically-typed. The main advantages of static typing are: avoidance of runtime errors, memory optimization, and IDE features like auto-completion. Dynamically-typed languages let you do things like metaprogramming and duck-typing, which helps with code reuse. Explicit vs. Implicit Typing: Static languages can be either explicitly or implicitly typed. If a language is explicitly-typed, you must declare a variable with a type, such as:
var int = 1;
If a language is implicitly-typed, you can declare variables like so:
var = 1;
The compiler can figure out what the type is from the context. I'm not sure if there is any advantage to a language being explicitly-typed. Implicit typing improve readability when you have complicated types.

Type-Safe vs. Unsafe Typing: A language is type-unsafe if you can convert completely unrelated types. C and C++ allow you to do this, and there are some odd situations when it might be useful. Type-safe languages prevent you from referencing out-of-bound array locations, converting classes to dates, or adding strings and integers, though the latter could be useful for a language geared for beginners like Visual Basic. The difference between type-safety and type-unsafety is largely a matter of the conversions that a compiler or interpreter knows how to do. If it knows how to turn a string into an integer, and it knows to try this when doing operations with integers and strings, then there should be no issue with adding "5" and 3. However, there is nothing obvious about such conversions. It makes just as much sense to a compiler to add the byte values of the two variables, where you might end up with a value like 119.

Strong vs. Weak Typing: Strong and Weak typing pretty much only refer to collection types. Object arrays in C# are weakly-typed, but other array types are strongly-typed. So, while you could add all kinds of different types to an object array, you could not do this if you first assigned a string array to an object array. This is because the reference is still a string array. I don't know how often anyone would do this, but it suggests that the language of 'strong typing' should be avoided except in rare situations.

It's interesting to note that over time C# has become more and more dynamic, with C# 4 even having a dynamic data type. We now have implicit typing to support data-centric operations through LINQ. As I discussed in a previous post, dynamic typing allows you to mold your data types to those stored in databases without necessarily knowing much about what you're going to get from the database. It's interesting that the TIOBE report categorizes languages according to whether they are static or dynamic. This line is becoming increasingly blurred, just as language paradigms are becoming less rigid as OO languages like Java and C# incorporate elements from functional programming.

Incorporating dynamic typing in compiled languages is part of a trend in which languages are becoming more complex, but also more intuitive and readable. For example, why should you have to know what type a variable will take at code-time, especially when communicating with web services or databases? Though it's easy to just start using LINQ, for example, it's important to understand the problems these developments are meant to solve and the sources of their solutions in order to truly understand them.
Related Posts Plugin for WordPress, Blogger...