StyleCop and F#
StyleCop is a tool that analyzes your source files with the default Microsoft coding conventions describing how code should look like.
It’s not that I agree with every StyleCop rule, but there are more rules that I do agree on then otherwise.
FAKE already had support for FxCop, but since ReSharper had Intellisense support for StyleCop in place, I found it reasonable that my automated build (local and remote) is depending on an analyzing tool that I both can use in my development practice as in my automated build.
StyleCop Command Line
FAKE is written in F#, which means the whole .NET framework is available to us. Besides working with FAKE and some personal fun-projects, I didn’t have much experience with F# so it was a fun challenge.
StyleCop already has some command line tools that you can use to analyze your source files, so in theory my StyleCop implementation of F# could just use some of those tools and pass the right arguments with it?
F# is a functional language with imperative features (such as mutable values, foreach…). My goal was to write a purely functional implementation of the command line tools that analyzed the source files.
I’m not going to run through every bit of the code, you can do that yourself with the link on the end of this post.
Before we get started, some practical numbers:
- I wrote the implementation in 2-3 hours (so it certainly can be improved)
- The single file contains around 100 lines of code
Just for fun, I checked the length of some C# implementation, and found that all together they had 650 lines of code.
Imperative to Functional
For Each For Each
One of the things I had to implement, was the possibility to analyze Source, Project and Solution Files. Source files could be analyzed directly; project files must first be decomposed in source files and solution files must first be decomposed in project files.
When I looked at the C# implementation, you could see that they had implemented a foreach, in a foreach, in a foreach, to get the three different levels of lists.
Each source file must be wrapped in a StyleCop Project object so it can be analyzed, so you must indeed go through every project file and solution file to obtain all those underlying source files.
Functional programming has different approaches. What we want to do is: “create a StyleCop Project for every source file”. That was my initial idea. I don’t want to know where those files came from (project, solution). I came up with this solution:
Every StyleCop Project must have an identifier which must be incremental by each source file it analyzes.
In my whole file, there are no foreach loops, but this function is called three times directly and time indirectly. So, you could say it’s the core of the file.
The function takes a start ID, together with the files to run through, to create StyleCop Project instances. It’s a nice example of the Tail Recursion in Functional Programming, where you let a function run through every element in a list (via the tail).
At the end, we combine all the projects to StyleCop Project instances and return that list.
In the C# implementation, they used the shorthanded increment (++) to assign the next integer as the Project Id. In the previous snippet, you see that the ID is also sent with the function and is increased internally. This way we can reuse this function because we could start from zero, but from any valid integer number. And that’s what I’ve done.
The source files can call this function directly, project files go through the source files and the solution files go through the project files but they all uses this function, the Tail Recursion. At the end, we combine all the StyleCop Projects created from the source files, project files and solution files.
I could have created a counter function that has a Closure inside to count the ID’s though:
This would have reduced the arguments we must send with the function, and would remove the implicit reference to the project ids and the project length.
Feel free to contribute!
The assemblies used in this file, are also written in C#. So, this is an example of how C# assemblies can be used in F# files without much effort. The bad side is that a “list” in C# isn’t the same as a “list” in F#, so some conversions are needed.
Also, Currying or Partial Functioning in F# isn’t possible with C# objects. If this was possible, I think my implementation would look just that bit more Functional than now.
Personally, I was surprised that I could write a full implementation in just 2 - 3 hours. F# is a fun language to play with, but also to write solid declarative implementations quickly. I hope that I can use my functional skills more in actual production projects.
My interest in functional programming has increased by implementing an implementation for StyleCop and I expect that not only my functional programming skills will become better in the future but also my object-oriented programming skills.
Thanks for reading and check the implementation on my GitHub.
Remember that I only worked for 2 - 3 hours; so, contribute to the FAKE library if you have any suggestions because EVERYTHING can be written better.