its proving fairly useful to me thus far. If I am further motivated in this direction I may add functionality to more easily track comments in other peoples journals since checking if the journal author has responded to your comment can get a bit bothersome if you have posted in multiple journals. Meh, maybe the new site will fix this better ... someday...
I spent a couple hours doing minor tweaks on Mike's Line Counting app last night. His app filled a gap I needed between useless and overpriced and too antiuseless to be useful. One thing I am happy about is I got it to output csv so I can have graphs like:
figure 2.
Yay :s.
Anyways this post is mostly to highlight the fact that functional programming in C# 3.0 is not so bad. I implemented a feature, which counts lines of source code in folder(s) instead of projects. I was able to do this hassle free both cause Mike had had already done all the hard work and cause I used functional programming paradigms. In functional programming the ultimate goal is in being able to come up with a *useful* mathematics for specifications (based on category theory) and being able to easily translate this back and forth to algorithims and final language. The less the distance between these concepts the more elegant logical and behaviourally correct code you can write. The programming paradigm which is so far closest to this ideal is the one called 'functional'. Where the word functional is used to emphasize that statements and assignments are replaced with functions and composition and that functions can be be passed around and bound to variables.
I like functional programming not because of some highbrow nonsense like lack 'o state but because humans are much worse at tending to details than automatrons. Every less line of code, every bit of irrelevant implementation detail I can leave off my hands and relegate to the computer is the probability of an error and mistake reduced and my productivity and efficiency increased. Also perhaps due to my training in maths I may be more inclined towards the paradigm since I just may be afflicted by 'Deformation professionnelle'.
The basic/core concepts of functional programming are fold, map and filter. In basic terms map is a function which applies a function of type (a -> b) to a Collection (often a list but may be a tree or other graph) of type a and returns a collection of type b. What good is this? In C# Select stands in for map.
var sourceFilesbyExtensions = new List(); //list of allowed extentions (e.g. cs, cpp, etc) fileTypes.ForEach (ext => sourceFilesbyExtensions.Add(System.IO.Directory.GetFiles(folder, "*"+ext, searchOp ))); var statsOfNodes = sourceFilesbyExtensions.Select( sourceFilesArray => sourceFilesArray.Select(sourceFile => { var fn = new FileNode(); fn.Name = Path.GetFileName(sourceFile); fn.Path = sourceFile; fn.ChildNodes.Add(fn); CountFile(fn); return Count(fn, (new StringBuilder()), (new StringBuilder()), (new FileNode())); }).ToList()).ToList ();
With select I take a List and a function from string [] to List and get a List>. Fold is a an aggregating function. It takes a list/Collection of say type TypeA, an initial value for an accumulator of type TypeB and a function f(TypeB x, TypeA y) -> TypeB and so returns a value of type TypeB. It uses the function you passed to combine the accumulated value and an element from the collection till every element in the collection has been gone through and one arrives at its aggregate via your function. It expands out like this: f(..., f(x' ', f(x', f(x,y))) or f(x' ' ', f(x' ', f(x', f(...))).
A typical example of fold is how to sum a list of integers. C#'s fold is the Aggregate Function. IntList.Aggregate(0, (x,y)=>x + y); I use aggregate to Create a summary string from the individual summary strings held in each FileNode. I also use the Aggregate function to flatten a list of lists into one list. Google's mapreduce refers to the concept of Map and Flatten.
var undistinguishedNodeStats = statsOfNodes.Aggregate((p, q) => p.Concat(q).ToList()); Summary = undistinguishedNodeStats.Aggregate("", (s, n) => n.summary + s);
I will not go over filter because I have no example since I made no use of it here but it does what it sounds like it does. The whole source:
public void CalculateFromFolder(string folder, bool allDirectories) { var searchOp = (allDirectories) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; var sourceFilesbyExtensions = new List(); fileTypes.ForEach (ext => sourceFilesbyExtensions.Add(System.IO.Directory.GetFiles(folder, "*"+ext, searchOp ))); var statsOfNodes = sourceFilesbyExtensions.Select( sourceFilesArray => sourceFilesArray.Select(sourceFile => { var fn = new FileNode(); fn.Name = Path.GetFileName(sourceFile); fn.Path = sourceFile; fn.ChildNodes.Add(fn); CountFile(fn); return Count(fn, (new StringBuilder()), (new StringBuilder()), (new FileNode())); }).ToList()).ToList (); var ssb = new StringBuilder(); var undistinguishedNodeStats = statsOfNodes.Aggregate((p, q) => p.Concat(q).ToList()); CodeLines = undistinguishedNodeStats.Sum(n => n.CodeLines); Comments = undistinguishedNodeStats.Sum(n => n.Comments ); BlankLines = undistinguishedNodeStats.Sum(n => n.BlankLines); TotalLines = undistinguishedNodeStats.Sum(n => n.TotalLines); Summary = undistinguishedNodeStats.Aggregate("", (s, n) => n.summary + s); CsvOutput = undistinguishedNodeStats.Aggregate("", (s, n) => n.csvOut + s); statsOfNodes.ForEach(fileNodes => { if (fileNodes.Count > 0) { var codeLines = fileNodes.Sum(n => n.CodeLines); var totalLine = fileNodes.Sum(n => n.TotalLines); ssb.AppendFormat("{0} files, Count {1}, Total Lines {2}, Code Lines {3} [Percentage: {4} %]", Path.GetExtension(fileNodes[0].Path), fileNodes.Count, totalLine, codeLines, Math.Round((double)codeLines/CodeLines * 100),1); ssb.AppendLine ("\r\n");} }); Summary += ssb.ToString(); }
Also, maybe you could take your project in the next level and work for any arbitrary thread on GameDev.