LINQ (Language-Integrated Query) is a .NET query language that lets you work seamlessly with collections of objects (and other data sources). It revolutioned .NET by bringing functional programming concepts to the masses and providing an alternative to the prevalent imperative style programming in C#.
Let’s take a look at them!
One popular style of functional programming is applicative programming when working with collections. In this context applicative programming consists in a function
f calling a function
g that was given to
f originally as an argument. This is easier to understand if we switch
Where in LINQ) and
g for an arbitrary predicate
x => x.status === 'poisoned':
1 2 3 4 5 6 7 8
When you get a little bit away from the world of OOP for a moment, away from objects and their characteristic per-piece-of-information micro-language, where you need a specific mini language to speak to or interact with each separate object. When you start moving towards one single data structure, like a collection, and a legion of functions that can operate on this same data structure you can get very interesting results in terms of reusability, flexibility, readability and consistency in your code.
It is better to have 100 functions operate on one data structure than 10 functions on 10 data structure.
LINQ with Array Prototype Functions
array.prototype provides several methods that let you perform operations on array elements in much the same way than LINQ does. For instance:
Selectgives you the possibility to perform transformations in each of the elements of an array and create a new array with these transformed items
Whereallows you to filter the elements of an array based on a predicate of your choice
truewhen an array contains items that match a given predicate
You can use them like you would in LINQ method syntax:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
In this example above we augment the
Array.prototype object with a series of LINQ aliases to make the existing
filter and the
find methods are part of ES2015 (ES6), so you’ll need babel to run these examples (and if you want to use these features in production today).
And the same example written using arrow functions where I have just switched the anonymous function expressions for arrow functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
LINQ Deferred Execution with ES2015 Generators
There’s something I failed to tell you about in the previous section. The
Array.prototype methods are executed as they are called, so every filter, every transformation is executed on every item of an array as soon as the methods are called. That is, there is no concept of deferred execution like we have in LINQ when you use these
Or there was… ES2015 generators bring the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
In this example we created several generators that allow us to iterate over an array in the manner of our choosing and with deferred evaluation. In order to get the fluent API experience, we also extended the prototype of each of these generators using a mixin and the new Object.assign native ES2015(ES6) method that let us extend any object with new properties and methods (like
But this feels a little bit unwieldy, doesn’t it. To make it more usable, we could add these new LINQ capabilities to the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Without a doubt, the two most popular libraries for writing LINQ-like expressions are underscore and lodash. They provide very similar APIs and you could consider lo-dash a superset of underscore. You can read this great article by @ben336 where he compares both libraries.
Let’s take a look at how the previous example would look when written in underscore:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
Since lodash is a superset of underscore, if you switch libraries in the previous example it will just work. One cool thing that you can do with lodash that you can’t with underscore is implicit chaining (by losing deferred evaluation):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
... spread operator.
LINQ Query Syntax with ES2016 Comprenhensions
A new super-duper-useful feature that will come with ES2016(ES7) are comprehensions. They provide a query-like syntax to operating with arrays (or any iterable data structure). If you are familiar with Python, Ruby or CoffeeScript you may have encountered comprehensions before. They look like this:
1 2 3 4 5 6 7 8 9 10
And another example working on nested collections:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Additionally, ES2016 (ES7) will also bring generator comprehensions that will look like array comprehensions but between parenthesis
(<my comprehension here>) instead of square brackets
. They will behave just like array comprehensions but with deferred evaluation.
- We saw how you can use the
Array.prototypemethods for a native implementation of LINQ-like functionality. One the plus side, since they are native you can assume that they’ll be faster that non-native implementations and they don’t require you to add any additional library. On the minus side, there are not so very many methods, some of them are only available from ES5, and others from ES6, so there are various degrees of support depending on the browsers that you are targeting. They are also executed as they are called, so you don’t get deferred evaluation.
- We saw how you can use ES6
generatorsto add deferred evaluation into the mix. Nice to know how generators work but you’ll probably don’t want to roll and maintain your own implementation of LINQ, instead you’ll probably…
Array.prototypemethods, they behave consistently across many browsers and will usually provide pollyfills and fall back to native APIs if they exist. On the minus side they are an additional dependency that you need to manage, and a new library to learn how to use.
In the next chapter of this series I will digress a little bit from functional programming and take a look at ES2015 (ES6) iterators and generators, to later come back to functional programming with function composition and building abstractions on top of abstractions on top of abstractions :).
Have a great day and a even greated summer!
Want to Learn Some More?
Here you can find more information related to this article:
- MDN on the Array.prototype object
- Kyle Simpson’s Great Series on Generators
- 2ality on ES6 Generators in Depth
- MDN on Comprehensions
- ECMAScript proposal for array comprehensions
More Articles in These Series
- Object Oriented Programming
- White Tower Summoning Enhanced: The Marvels of ES6 Classes
- Black Tower Summoning: Object Composition with Mixins
- Data Structures
- Functional Programming
- And more stuff to be shaped out:
- Asynchronous Programming