Showing posts with label vs. Show all posts
Showing posts with label vs. Show all posts

Monday, August 26, 2013

Visual Studio error message template

Visual Studio (among others) will recognize lines that follow a certain pattern in the output window and turn them into links that open an editor to the file and then position the cursor where the error occurred.

The general pattern used by the tools and recognized by Visual Studio is:

fileName(startLine,startColumn[,endLine,endColumn]): error errorCode: errorMessage
An example message would look like:

C:\Source\path\to\solution\project\FileWithCompileError.cs(154,20,154,26): error CS0103: The name 'result' does not exist in the current context
The endLine and endColumn are optional; presumably not all errors can be pinpointed to a range so accurately.

Monday, February 02, 2009

Ego-driven software development

(or "How M.C. Escher Would Have Packaged His Software")

This was too "good" to not blog about. I heard about IronPython Studio, a Visual Studio-based IDE for writing Python code for/with .NET tools. In order to install this interesting gem, you first need to install its pre-requisites, which is one of flavors of the "Visual Studio 2008 Shell": Isolated Mode or Integrated Mode. Sounds easy, right? Wrong!

The actual downloads seem innocent enough (I got both, just to be safe -- as an aside it was hard to tell which one would suit me best): they arrive as executables. Here's how many levels of "packaging" there are:
  1. Running either of vs_AppEnvRedist.exe or vs_ideredist.exe will create a temporary directory where the EXE's files are extracted and an "installer" is launched

  2. You accept the EULA and click next a few times and what do you end up with? "The redistributable package has been installed". That's right, you ran an installer that installed another installer. Total disk space needed for this (at apogee): 400 MB for the original download, 400 MB for the temporary files and 400 MB for the "redistributable package" = 1200 MB

  3. As you finish the first "installer", the temporary files are cleaned up, so we're back to consuming 800 MB. You run the second installer and the first thing it does is check its signature, which consumes 400 MB of RAM. It then proceeds to extract files to another temporary directory (400 MB again, although this time it's in a bunch of smaller files - 286 MB of which is various versions of the .NET framework), thus bringing our used disk space back up to 1200 MB. Those of you following at home will notice that I haven't actually installed anything useful yet. Accept another EULA, select the only feature (wut?), pick the destination folder and go (again)! At apogee: 400 MB + 400 MB + 400 MB + whatever installed size it was (I didn't check)

  4. Oh, it looks like we're actually done! What was I installing, again?

I'm reminded of Adobe Acrobat Reader installers from, oh, I don't know, ten years ago, before one-file installers were even invented. IronPython itself is available in a single MSI file, while IronPython Studio's download options are both available as an MSI file in a ZIP file.

There is no technical reason for this. There simply is no excuse for these fractal installers except that someone (or an entire team of someones) at Microsoft decided they needed to be involved in the supply chain that brings us internauts this bare Eclipse-wannabe that does not even include a text editor. I mean, seriously, the only thing that could have been worse would have been to wrap the whole thing in a "downloader" (like Visual Studio Express) or in an ISO 9660 file (like Visual Studio 2008 Service Pack 1).

I have a special offer for the person in charge of the Visual Studio team: I will personally come over and deliver atomic wedgies to everyone responsible for these shenanigans! Just give me a call; you know how to find me.

There is some good news after all this: IronPython Studio not only just works, but so does its debugger. Kudos to that team.

Saturday, July 26, 2008

I got in a "jam"...

Round 1A of Google's Code Jam programming contest (in which I participated) ended about an hour-and-a-half ago (there are three sub-rounds of Round 1 and contestants can compete in two of them to try to move on to Round 2).

A failure (on my part) to pay close attention to the requirements of the first problem meant I implemented an algorithm with a complexity of O(n! * n!), which means 25 401 600 iterations for n = 7 (sort of reasonable) but 1 625 702 400 iterations for n = 8, something my laptop wouldn't be able to finish in any reasonable amount of time. It's much worse when you consider that n was expected to go as high as 800! Once I read that, it occurred to me that I had been going at it entirely the wrong way... About an hour-and-a-half of going the wrong way, which involved implementing (and debugging) a nice "permute the items of this list" method.

You see, there was a trick to the problem. Once I realized this, I replaced the double permutation loop with two calls to Sort() and a single O(n) loop. D'oh! My solution to the small input was judged as correct, so I proceeded to the large input. It ran just as fast and so I submitted its output, too. Well, again, I screwed up with the requirements and it turns out my math was overflowing left, right and center and thus, when the contest ended, I got a measly 5 points (out of a possible 15 for that problem and out of a possible 100 for all 3 problems!), which means I ranked 2363 out of 2394. (you don't find out if your submission to the large version is correct until the end of the contest - I also only attempted the first problem)

Oh, well... I might try again in Round 1C (Sunday at 05:00 local time!), but in the meantime I thought I'd publish some of the source code that came out of this. I used Visual Studio 2008, which meant I could try out the neat features of the C# that came out with .NET 3.5, such as:
  • the var keyword
  • extension methods
  • LINQ

OK, so I didn't need to use LINQ, nor did I use extension methods until after the contest, but here's my touched-up Permutations iterator method, generalized to any IList<T> instance:
public static class Extension {
public static IEnumerable<IList<T>> Permutations<T> ( this IList<T> input ) {
int numElements = input.Count;
var slotOffsets = new int[numElements];
var slotBusy = new bool[numElements];
bool allDone = false;
while ( !allDone ) {
#region Set slotBusy flags to false
for ( int i = 0; i < numElements; i++ ) {
slotBusy[i] = false;
}
#endregion

IList<T> permutation = new List<T> ( numElements );
int lastSelected = -1;
for ( int i = 0; i < numElements; i++ ) {
for ( int j = 0; j < numElements; j++ ) {
int selectedSlot = ( lastSelected + 1 + j + slotOffsets[i] ) % numElements;
if ( !slotBusy[selectedSlot] ) {
slotBusy[selectedSlot] = true;
permutation.Add ( input[selectedSlot] );
lastSelected = selectedSlot;
break;
}
}
}
yield return permutation;

#region Update offsets
for ( int i = 0; i < numElements; i++ ) {
slotOffsets[i]++;
if ( slotOffsets[i] < ( numElements - i ) ) {
break;
}
else {
if ( i == numElements - 1 ) {
allDone = true;
}
else {
slotOffsets[i] = 0;
}
}
}
#endregion
}
}
}

...which you can use as follows (notice how it's magically a method on any IList<> implementation?):
IList<int> inputList = new List<int> ( new int[] { 1, 2, 3 } );
foreach ( List<int> permutation in inputList.Permutations ( ) ) {
StringBuilder sb = new StringBuilder ( );
sb.Append ( "[" );
bool isFirst = true;
foreach ( var item in permutation ) {
if ( !isFirst ) {
sb.Append ( ", " );
}
else {
isFirst = false;
}
sb.Append ( item );
}
sb.Append ( "]" );
Console.WriteLine ( sb.ToString() );
}

...and it should produce the following output:
[1, 2, 3]
[2, 3, 1]
[3, 1, 2]
[1, 3, 2]
[2, 1, 3]
[3, 2, 1]

I just wish I had prepared this method before the contest, although I think some actual practice in solving these kinds of problems would have helped me more. Maybe next time... :)