Sergio and the sigil

Language Envy - C# needs Ranges

Posted by Sergio on 2010-01-02

As soon as I started learning Ruby, a few years ago, I got immediately hooked on its Range class. I could not believe I had been programming in .NET without them for so long.

I like to think of range objects as the specification for a for loop, packaged in an object that can be passed around. That's not the whole story, though. Ranges also represent sequences or intervals, which can be queried for intersection or containment. See the following Ruby sample code.

#declare a Range object
summer_months = 6..9
#enumerate it
summer_months.each {|m| puts "#{Date.new(2000, m, 1).strftime('%B')} is a Summer month." }
#other handy features
summer_months.include? 7 # ==> true
summer_months.to_a # ==> [6, 7, 8, 9]  (converted to array)

I needed that in C#

That was back when the CLR 2.0 was just about to be released and I ended up writing my own Range

CouchDB Presentation

Posted by Sergio on 2009-10-01

In this month's Chicago ALT.NET meeting we will be taking a look at Apache CouchDB. I quote from the official site:

Apache CouchDB is a document-oriented database that can be queried and indexed in a MapReduce fashion using JavaScript. CouchDB also offers incremental replication with bi-directional conflict detection and resolution.

CouchDB provides a RESTful JSON API than can be accessed from any environment that allows HTTP requests.

Get Comfy With CouchDB

6:00 pm
Pizza and networking time

6:30 pm

CouchDB is one of the more mature schema-less map/reduce object dbs out there. In this talk we'll cover the basics of what CouchDB is, and why it's cool, and then we'll run through a sample application. The application will show off LINQ to Couch, basic persistance, views and full-text search with CouchDB-Lucene.

Alex Pedenko has been in software development for about 13 years, starting off on Borland Delphi, then spending about 4 years in Java and finally making the switch to .net around '03

Currently, he is the director of software architecture and chief architect at a healthcare services company. He has used that role as an opportunity to inject some modern ideas into an otherwise lagging industry, moving the company from a classic "giant web-app strapped to an even more giant db", to a distributed, service-oriented environment utilizing RESTful services, and rich-client applications.

Alex is also involved in a number of Open Source projects like Bistro and NDjango, and the .net side of CouchDB via Divan and LoveSeat

It's Generic, not Multipurpose

Posted by Sergio on 2009-09-09

There's something that has been bothering me with many .Net APIs that are Generics-based (or that at least try to be.) I might be totally off or just nitpicking but I could not find any reference agreeing or disagreeing with the opinion I'm about to give.

Generic parameters are not data

Well, that pretty much summarizes what I think and I could stop right here. On the other hand, doing that would make for a pretty lousy blog post. Let's elaborate on that statement a little more.

The way I like to see the generic parameters in a function declaration (those that go inside the < and >) is akin to modifiers. They modify the function's data parameters (the normal parameters) and/or return value's data type.

Here are some examples, loosely based on some APIs you may be familiar with but changed to avoid singling out anyone. Some of the examples are really popular.

The typeof hater

Take a look at this generic function call.

cachedData.DeleteAllInstances<Book>();
// or even
cachedData.DeleteAllInstancesOf<Book>();

I could almost bet that the generic methods above only use the Book generic parameter in a statement like typeof(T). So what they really need is the Type object not the type identifier, and that's exactly what the following non-generic version asks for.

cachedData.DeleteAllInstances( typeof(Book) );

The Stringophobic

It always feels weird when I find something like this:

var list = container.FindInterfacesInNamespace<IOneOfThose>();
// or even
var list = container.FindInterfacesInNamespaceOfType<IOneOfThose>();

That function call feels like someone is desperately trying to avoid passing the namespace string as a data parameter, possibly thinking that could hurt automated refactoring. I'd just go with this:

string interfacesNamespace = typeof(IOneOfThose).Namespace;
var list = container.FindInterfacesInNamespace(interfacesNamespace);

The thumb buster

Sometimes I think API designers are just trying too hard to use generics. I mean, if there's a way to get the data they need by way of a type identifier, no matter how unnatural that be, a generic function will be born. Paraphrasing what someone already said: When a new language feature is your hammer, everything starts to look like your thumb.

var list = container.
    FindAllImplementationsOfTypeAinTheAssemblyOfTypeB<IDoStuff, ConcreteDoer>();

You see, the first generic parameter in this example is fine (assuming the function returns something like IEnumerable<IDoStuff> ). The problem is the second one. If all you really need is an Assembly object, just ask for it, I'd say.

var asm = typeof(ConcreteDoer).Assembly;
var list = container.FindAllImplementationsInAssembly<IDoStuff>(asm);

How to avoid that

Here are some symptoms of function declarations that may be suffering from generic parameter over-excitement.

  • There's no way to skip explicit generic parameter passing, i.e. it's impossible for the compiler to infer the generic parameter from the data parameters.
  • The only usages of the generic parameter in the function implementation involve the typeof operator.
  • The generic parameter in question doesn't have any constraints (the where keyword in C#) in its declaration. Or maybe it does have but it's not being leveraged at all in the implementation and can be safely removed (maybe there's a Resharper code inspection suggestion for that.)
  • Because the generic parameters are being used in an unnatural way, the function name and/or the generic parameter name become much longer than the usual, in an attempt to explain the unexcusable.

As I said, I may just be too sensitive or completely missing the point, neither of which would be their first time. Worst case someone chimes in with clever remarks and I learn something new, which again would not be the first time.

ASP.NET MVC with jQuery SuperLoad

Posted by Sergio on 2009-08-23
The other day I wrote about the jQuery SuperLoad plugin but I couldn't offer any real working sample of an application using it. Today I'm here to rectify that and talk about the new sample code I've recently added to the project repository.

Adding products to your shopping cart

The application has a single page, which lists a few books that you can add to your shopping cart. The cart is initially empty and when we add items to it, both the cart item list and the total price (at the top of the page) get updated from a single Ajax call.

The client side

Here's sample of what each of the products' HTML looks like. They each are inside a div which's id contains the product's id.
<div id="product_8" class="product">
	<img src="../../Content/images/prod_8.jpg" align="left" />

	<div class="title">Product 8</div>
	<div class="prodPrice" >$8.88</div>
	Qty: <input type="text" size="2"  maxlength="3" 
				class="quantity" value="1"/>
	<input type="button" value="Add to cart" class="addButton" />
</div>
We just need to fire one Ajax call whenever one of those "Add to cart" buttons is clicked. Here's the code that does that.
$('.addButton').click(function() {
	var prod = $(this).parent('.product');
	var prodId = prod.attr('id').split('_')[1];
	var qty = prod.find('.quantity').val();

	$.superLoad({
		url: '/Shopping/AddItem',
		type: 'POST',
		data: { product: prodId, quantity: qty },
		success: function() { $('#empty').remove(); }
	});
	
});
As you can see, we are making a superLoad() call to the AddItem action in the ShoppingController. Since this is a data modification call, we chose to use an HTTP POST request. The posted data goes in the data option. To tidy up things, we delete the empty text from the cart (if it's still there) once the call completes successfully.

Multiple results from a single action

The challenge on the server side is to come up with a sustainable method of reusing existing actions and combine them in a single action result, formatted to SuperLoad's liking and returned to the browser. To address that issue the sample comes with an implementation of a composite action result class specifically built for the response format we are trying to create. That class is the SuperLoadResult, listed below.
public class SuperLoadResult : ActionResult
{
	public IEnumerable<SuperLoadAjaxContent> ContentItems { get; private set; }

	public SuperLoadResult(params SuperLoadAjaxContent[] contentItems)
	{
		ContentItems = new List<SuperLoadAjaxContent>();
		((List<SuperLoadAjaxContent>)ContentItems).AddRange(contentItems);
	}

	public override void ExecuteResult(ControllerContext context)
	{
		context.HttpContext.Response.ContentType = MediaTypeNames.Text.Html;

		context.HttpContext.Response.Write("<div class=\"ajax-response\">");
		foreach (var item in ContentItems)
		{
			context.HttpContext.Response.Write(
				string.Format("<div class=\"ajax-content\" title=\"{0} {1}\">",
			                  item.Command.CommandText, item.Selector));
			item.GetResult().ExecuteResult(context);
			context.HttpContext.Response.Write("</div>");
		}
		context.HttpContext.Response.Write( "</div>");
	}
}
I bet things will become clearer once I show it being used from the AddItem action. So here it goes.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddItem(int product, int quantity)
{
	var sku = GetProduct(product);
	var item = new CartItem(sku, quantity);
	var cart = GetCurrentCart();
	cart.Items.Add(item);

	//add all the separate action results that we want into 
	// a SuperLoad result, mapping each one to the right 
	// selector and update type.
	return new SuperLoadResult(
		new SuperLoadAjaxContent("#cartTotal", 
		                  SuperLoadCommand.Update, 
						  () => CartTotal(cart)),

		new SuperLoadAjaxContent("#cart", 
		                  SuperLoadCommand.Append, 
						  () => CartItem(item))
		);
}
That last parameter to the SuperLoadAjaxContent's constructor is what will be invoked to provide an ActionResult-derived object, which will be executed and injected in the right place of the combined response. If I needed to update more elements, I could simply pass more instances of SuperLoadAjaxContent to my SuperLoadResult. Both CartTotal and CartItem are regular action methods that return a partial view from an .ascx template. Here's how simple the CartItem action is.
public ActionResult CartItem(CartItem item)
{
	return PartialView("CartItem", item);
}
Again, the entire sample is available for browsing, forking, or downloading at the repository page.

Resharper Test Runner in 64-bit Windows

Posted by Sergio on 2009-07-20

In the spirit of helping the next guy, here's some explanation for a problem that was surprising to me.

We have recently upgraded our product to 64-bits and all developer workstations to Windows 2008 x64. The transition was easy and most things worked with minor or no tweak at all. We're still battling a TFS issue but that will be the subject for another day, once we figure it out.

I noticed that a bunch of my unit test cases were failing when I ran them using Resharper's test runner. I traced the problem down to missing registry values that were needed by the tests. The intriguing part was that I could see the registry settings there (see image below) and the tests were working fine using NUnit's GUI runner.

After a little poking around, I saw this in Process Explorer:

Hmmm. Visual Studio and Resharper run as 32-bit processes and NUnit's (and my application itself) as 64-bit ones. Could there be a difference between Registry access for 32-bit vs. 64-bit processes? Yessir. It turns out that my settings were in the right place but Windows was redirecting the 32-bit Registry accesses to the path shown below, which is obviously empty.

I don't know of any elegant work-around for this issue but for now I'm simply duplicating the values in both places for the sake of testing. I'm not happy with this duplication but it's got me back on track until someone bright chimes in with a better alternative.