Tuesday, June 30, 2009

Amoeba Fever Problem

My brother, Chris, sent me this interesting math problem:

Toby has a jar with one amoeba in it. Every minute, every amoeba turns into 0, 1, 2, or 3 amoebae with a probability of 1/4 for each case (dies, does nothing, splits into two, or splits into three). What is the probability that the amoeba population eventually dies out?

I initially threw out a guess of “slightly more than 25%”. I figured that the amoeba population either dies out right away (1/4 chance) or starts growing rapidly.

I was up a bit with Maya and thought about this some more and revised my guess to somewhere between 25% and 33%. My reasoning was looking more professional (but not actually any more accurate, as we’ll discuss). I reasoned that the change of an amoeba population die out after n iterations is

clip_image002

So the chance of the first 3 iterations leading to die out would be something like:

clip_image002[4]

Or more generally:

clip_image002[6]

This converges very rapidly so any additional terms beyond n=3 are insignificant here.

This approach is not very accurate as it assumes linear growth of the population which is not promised, though I figured it’d be close. Being a programmer, I decided to write a simple simulator to just brute force the answer.

This little in-browser JavaScript application runs through hundreds or thousands of “jars” to see how often the jar flourishes with life or dies out. I assume that if the population reaches 1000 amoebae that it will *never* die off (that is, the chances of it are small enough to consider it a win). In fact, flipping through my results shows that if a jar can survive 9 iterations, it’s almost certain it will flourish (a much lower standard would probably suffice).

Anyway, so after 10000 jars are tested, I get a number of about 41%. (note: don’t use the 10000x button unless you’re using FF3.5, Chrome, or a recent Safari…it’s too slow for less recent browsers including IE8).

Chris has promised to check the math later and determine if I’m close.

Feel free to do a view-source, or look at the page in edit mode. It won’t let you overwrite my version so hack away. When readying to criticize my code, keep in mind that I wrote it at 4am and haven’t prepared it for public scrutiny. The fact that it’s so slow tells me I’m doing something horribly inefficient somewhere…

Monday, June 29, 2009

Diagnosis II: Why Can’t LiveWriter Post from Work?

The remote server returned an error: (403) Forbidden.I’m at working trying to toss up blog post here and there and things are coasting along smoothly with Windows Live Writer when I see this when I hit publish (bonk):

image (The remote server returned an error: (403) Forbidden.)

This was working fine yesterday so I’m assuming I’m being blocked by my corporate firewall. OK, let’s confirm that.

I can access blogger.com, mharen.blogspot.com, my dashboard, the post editor…everything’s fine through the browser, just not through Live Writer. I fired up Fiddler to see what LW’s doing and saw the problem right away:

image

It seems that even none of the blogger/blogspot domains are blocked here, blogger ships its images to http://picasaweb.google.com/, which is blocked. No matter, I asked our friendly IT admin to unblock it. Now I can publish. But did it work?

Sort of. The publish worked but the image wasn’t coming through. It seems that the img src is actually on another domain. e.g. http://lh3.ggpht.com/…. In my case, lh3 is blocked but lh5 isn’t. So I switched the images to lh5 and they all work just fine from within my corporate firewall (for now).

Highlight all matching words

Here’s a handy feature of Notepad++ that I’ve come to love: automatically highlight whatever text I’ve selected (see below).

image

I wanted that feature in Visual Studio so I searched and my favorite tech site delivered. Here’s what RockScroll does (I double-clicked dQty on line 2):

image

RockScroll is actually advertised as providing a thumbnail picture of your code instead of a scrollbar as shown (borrowing Scott’s image):

image

The highlighting stuff I wanted is just a hidden gem. By the way, if you’re getting ready to criticize my use of Hungarian notation in the above screenshots, please save your energy. This is legacy code and our current software standard explicitly forbids its use. I think this essay describes a very good application for it in modern programming, though (i.e. how to use Hungarian notation properly).

Publishing Code to Blogger

Publishing code to a blog can be tough. On my old blog engine (wordpress), I felt like I had more control with respect to plugins, javascript, css, etc. Here, on blogger, things are a little different.

I’ve turned to Windows Live Writer. It’s actually pretty slick and integrates well with Blogger. I added the Code Block plugin which does syntax highlighting pretty well.

A Few Gripes and Gotchas

Live Writer comes with a whole suite of “Live” tools. After installing Live Writer, I had MSN popping up and new addons in outlook wanting my attention. It is certainly not the light and easy text editor I was hoping for.

Next, posts published with Live Writer will often have a bunch of extra newlines in them. This can be fixed by telling Blogger not to convert line breaks:

image

Finally, I’m not a big fan of the way the code block plugin I mentioned earlier handles CSS. It inserts a new block of styles with every single code block. The workaround seems to be simple enough, though: add the CSS block to the template’s styles and make sure to uncheck “Embed Stylesheet” each time you insert code.

On a Positive Note

It handles images well (I can paste in images from other programs). It handles links well. It blends the WYSIWYG/HTML editing well and with a pretty good plugin community, I’m liking it better than other editors I’ve used in the past.

I’m a fan—I’m using it to write this post!

Friday, June 26, 2009

Troubleshooting an Elusive Site Slow Down

What follows is a long chronological account of a recent problem I ran into at work and how I diagnosed it (but have yet to solve!). I’m posting it here for many reasons:

  • to offer some insight into the mind of an engineer as a problem is dissected and diagnosed
  • to reiterate the importance of the fundamentals of problem solving
  • to show that everybody lies (even us, to ourselves) and it really does get in the way of problem solving
  • to show that supporting legacy browsers is a major pain
  • as a reminder to my future self how to do some of the things documented herein

Now onto the story.


One of the projects I maintain is a corporate website used internally to track all sorts of things. It’s pretty much a web-based data entry system implemented in ASP.NET 3.5 (upgraded from 1.1, 2.0…it’s an oldie).

Recently a user started reporting some odd behavior. She reports that after five minutes of work, one page (out of 10-20) starts slowing down to the point where she can’t use it any longer.

Assuming this was a simple problem, I asked some follow up questions:

Does restarting the browser fix the problem? Yes (for five minutes).

Does it happen all day long? Yes (not just during busy times).

Does it happen just to you? Yes (but on many machines!).

How does the rest of the site work when it happens? Just fine (it’s only the one page? Crap).

How long has this been happening? At least a month (ouch)

What OS/browser are you using? Windows 2000 with IE6 (ouch)

So at this point I had no idea—no clue whatsoever—what the problem was. I asked around to see if any of my coworkers had any thoughts and we came up with a plan to narrow down the possibilities.

First, I needed to determine if the slow downs were visible from the server. If not, we could eliminate the server from consideration. The ultimate fix might be in the server, but determining where the slow down occurs should help me pinpoint the problem and ultimately craft a solution.

Bryan suggested I use IIS logs for this. If you didn’t know, IIS (like all web servers) can keep a record of every single hit to your site. This record typically includes all sorts of details about the hit like date, time, IP address, port number, URL, browser, etc.

It turns out there are lots of things you can enable that are not on by default. The key metric I wanted was “Time-Taken”. I enabled it on the server and asked the user to let me know the next time the slow down occurred. Now I waited.

Later that day, it happened again. She sent me an email with the exact time the problem occurred with her IP address. I VPNed into the web server and pulled down copies of the recent log files to peek at (NB: never work with the actual log files—always make copies!).

I honed in on the time she provided (making an adjustment for UTC, which reminds me—I’ve been meaning to do a post about time-zones which will be riveting, I’m sure), and found a bunch of activity from her IP address. Here’s what I found:

Query (normally all on one line):
C:\...>LogParser.exe "
SELECT EXTRACT_FILENAME(TO_LOWERCASE(cs-uri-stem)) AS Page
 ,AVG(time-taken) AS [Average Time Taken]
FROM C:\001_Logs\Slowdown\ex090625.log
WHERE c-ip='10.0.0.2'
GROUP BY TO_LOWERCASE(cs-uri-stem)
ORDER BY AVG(time-taken) DESC"

Results:
Page                          Average Time Taken
----------------------------- ------------------
dailyproductionreporting.aspx 876
productionschedule.aspx       375
classifyevents.aspx           282
sourceoflossevents.aspx       240
calendaricon.gif              23
wait.gif                      11

Statistics:
-----------
Elements processed: 7874
Elements output:    6
Execution time:     1.06 seconds

This handy query looks at all 7874 hits in the given log file, groups them by page, and averages the time taken. The user’s complaint focused on classifyevents.aspx and these results clearly show that it’s in the middle of the pack in terms of time—certainly not an outlier as her report would suggest.

These times are in milliseconds and while I’m not too happy about the top result taking nearly 1 second on average to reach the user, an average result of 282ms for the page in question is perfectly normal.

But wait! What if most of the time the numbers are low, but sometimes they are really bad. OK, let’s just look at the top 20 worst hits to that page:

Query (normally all on one line): 
C:\...>LogParser.exe "
SELECT TOP 20
EXTRACT_FILENAME(TO_LOWERCASE(cs-uri-stem)) AS Page,
time-taken AS [Time Taken]
FROM C:\001_Logs\Slowdown\ex090625.log
WHERE c-ip='10.80.85.110'
AND EXTRACT_FILENAME(TO_LOWERCASE(cs-uri-stem))
   = 'classifyevents.aspx'
ORDER BY time-taken DESC"

Results
Page                Time Taken
------------------- ----------
classifyevents.aspx 2359
classifyevents.aspx 1875
classifyevents.aspx 765
classifyevents.aspx 703
classifyevents.aspx 593
classifyevents.aspx 546
classifyevents.aspx 515
classifyevents.aspx 500
classifyevents.aspx 468
classifyevents.aspx 468
classifyevents.aspx 453
classifyevents.aspx 453
classifyevents.aspx 437
classifyevents.aspx 421
classifyevents.aspx 406
classifyevents.aspx 390
classifyevents.aspx 375
classifyevents.aspx 375
classifyevents.aspx 375
classifyevents.aspx 375

Statistics:
-----------
Elements processed: 7874
Elements output:    20
Execution time:     1.89 seconds

So it looks like there are a couple slow hits to the page (2.4s, 1.9s) but that’s nothing like the 10-20s the user was seeing. This might be good news as I can now, for the most part, focus on the client—she’s getting the pages quickly, but for some reason things feel slow to her.

All this time, I’ve been running under the assumption that it’s got to be something about this user or her computers that cause the problem. This is based on the fact that we have a couple thousand people use this system every day and surely they aren’t all so patient as to never complain.

The fact that she was running IE6 bothered me a little bit. Everything is tested in IE6, 7, 8 but we don’t spend lots of time doing things over and over again as a single session so I thought that might have something to do with it. The biggest change we made in May that might make trouble with IE6 was the enabling of http compression.

So I turned to my pal Google. and eventually this page jumped out at me. It’s a set of instructions for disabling http compression for IE6 clients. Interesting…but most of my users use IE6. Here’s the part that peaked my interest (in blue):

RewriteEngine on
RewriteCond %{HTTP:User-Agent} MSIE\ [56]
RewriteCond %{HTTP:User-Agent} !SV1
RewriteCond %{REQUEST_URI} \.(css|js)$
RewriteHeader Accept-Encoding: .* $1

What this does is look at the User-Agent header of any incoming request. If it’s IE5 (just to be safe) or IE6, and the User-Agent doesn’t contain SV1 (which indicates IE6 SP2), and if the requested page is a .css or .js file, then we rewrite the Accept-Encoding header to a blank string (normally it would be gzip/deflate, which indicates that the browser can handle those compression methods).

Aha! Maybe most of the clients are running IE6SP2, but she’s running IE6-sans-sp2! I checked the logs again and looked at her user agent string, hoping it’d be IE6-sans-SP2:

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)

Awesome—no “SV1” so now, let’s just make sure that there aren’t many people in the same boat (if there were and this was the problem, I’d have more reports of the slow down). I turned to LogParser again, this time extracting user-agent strings and a count of how many times they came up from 14 days of logs:

Query (normally all on one line):
C:\...>LogParser.exe "
SELECT [cs(User-Agent)],Count(*)
FROM C:\001_Logs\ex090613\*.log
INTO UserAgents.csv
GROUP BY [cs(User-Agent)]
ORDER BY COUNT(*) DESC" -i:IISW3C -o:csv

Results:
Count   User Agent (cleaned up with Excel)
279859  MSIE 6.0 Windows NT 5.1 SV1
249747  MSIE 6.0 Windows NT 5.0
162945  MSIE 6.0 Windows NT 5.1 SV1
152893  MSIE 6.0 Windows NT 5.1 SV1
84220   MSIE 6.0 Windows NT 5.1 SV1
44532   MSIE 6.0 Windows NT 5.0
41528   MSIE 6.0 Windows NT 5.2 SV1
38485   MSIE 7.0 Windows NT 5.1
24308   MSIE 6.0 Windows NT 5.1 SV1
21001   MSIE 6.0 Windows NT 5.1 SV1
19200   Windows XP 5.1 Java/1.4.2_08
17536   MSIE 6.0 Windows NT 5.2
14766   MSIE 6.0 Windows NT 5.1 SV1
14440   MSIE 6.0 Windows NT 5.1 SV1
11835   MSIE 6.0 Windows NT 5.1
10561   MSIE 7.0 Windows NT 5.1 Trident/4.0
8944    Windows 2000 5.0 Java/1.4.2_04
7616    MSIE 6.0 Windows NT 5.0
6399    MSIE 6.0 Win32
5886    MSIE 6.0 Windows NT 5.1 SV1
5384    MSIE 6.0 Windows NT 5.1 SV1
4931    MSIE 6.0 Windows NT 5.1 SV1
4675    MSIE 6.0 Windows NT 5.1 SV1
4260    MSIE 6.0 Windows NT 5.1 SV1
3859    MSIE 6.0 Windows NT 5.0
3647    MSIE 6.0 Windows NT 5.1 SV1
3295    MSIE 7.0 Windows NT 5.1
3146    MSIE 6.0 Windows NT 5.1 SV1
3027    MSIE 6.0 Windows NT 5.1 SV1
2917    MSIE 6.0 Windows NT 5.1 SV1
2835    MSIE 6.0 Windows NT 5.1 SV1
2283    Windows XP 5.1 Java/1.6.0_07
2211    Windows XP 5.1 Java/1.6.0_13
2040    MSIE 6.0 Windows NT 5.1 SV1
1971    MSIE 6.0 Windows NT 5.0
1560    Windows 2003 5.2 Java/1.4.2_04
1237    MSIE 7.0 Windows NT 5.1 GTB6
1191    MSIE 6.0 Windows NT 5.1 SV1
1179    MSIE 6.0 Windows NT 5.2 SV1
1141    MSIE 6.0 Windows NT 5.1 SV1 3P_UVRM 1.0.22.0
1111    MSIE 6.0 Windows NT 5.1 SV1
1019    Windows XP 5.1 Java/1.4.2_07
1011    Windows XP 5.1 Java/1.5.0_06
872     MSIE 6.0 Windows NT 5.1
857     MSIE 6.0 Windows NT 5.1 SV1 GTB6
849     MSIE 6.0 Windows NT 5.1
826     MSIE 6.0 Windows NT 5.1 SV1
772     MSIE 6.0 Windows NT 5.1 SV1
759     MSIE 7.0 Windows NT 5.1
752     Windows XP 5.1 Java/1.4.2_03
740     MSIE 6.0 Windows NT 5.1 SV1
691     Windows XP 5.1 Java/1.5.0_04
658     MSIE 6.0 Windows NT 5.1 SV1
640     Windows XP 5.1 Java/1.6.0_12
602     MSIE 6.0 Windows NT 5.1 SV1 MS-RTC LM 8
595     Windows 2000 5.0 Java/1.6.0_11
507     MSIE 6.0 Windows NT 5.1 SV1
485     MSIE 6.0 Windows NT 5.0
469     Windows XP 5.1 Java/1.5.0_11
432     Windows 2000 5.0 Java/1.5.0_11
379     MSIE 6.0 Windows NT 5.1 SV1 R1 1.3
377     MSIE 6.0 Windows NT 5.1 SV1
372     Windows XP 5.1 Java/1.6.0_02
371     Windows XP 5.1 Java/1.6.0_11
328     MSIE 6.0 Windows NT 5.1 SV1
326     MSIE 6.0 Windows NT 5.1 SV1 GTB6
290     MSIE 6.0 Windows NT 5.1 SV1
271     Windows 2000 5.0 Java/1.5.0_06
204     MSIE 6.0 Windows NT 5.1 SV1
184     Windows XP 5.1 Java/1.6.0_14
176     Windows XP 5.1 Java/1.5.0_09
152     Windows XP 5.1 Java/1.6.0_03
110     MSIE 6.0 Windows NT 5.1 SV1 GTB6
109     Windows XP 5.1 MSIE 7.0.5730.13
108     Windows XP 5.1 Java/1.5.0_07
92      MSIE 6.0 Windows NT 5.1 SV1
92      Windows XP 5.1 Java/1.6.0_10
82      MSIE 6.0 Windows NT 5.1 SV1
66      Windows 2000 5.0 Java/1.6.0_07
65      Windows 2000 5.0 Java/1.6.0_05
65      MSIE 6.0 Windows NT 5.1 SV1
55      MSIE 6.0 Windows NT 5.1 SV1 MS-RTC LM 8
51      MSIE 6.0 Windows NT 5.1 SV1 GTB6
50      Windows XP 5.1 Java/1.6.0_05
42      Jakarta Commons-HttpClient/3.0.1
41      Windows 2000 5.0 Java/1.6.0_03
32      MSIE 6.0 Windows NT 5.1 SV1
30      Windows 2003 5.2 Java/1.5.0_11
26      MSIE 6.0 Windows NT 5.1 SV1
26      Windows XP 5.1 MSIE 7.0.5730.13
20      MSIE 6.0 Windows NT 5.1 SV1 GTB6
17      MSIE 6.0 Windows NT 5.1 SV1
15      MSIE 8.0 Windows NT 5.1 Trident/4.0
13      Windows XP 5.1 Java/1.5.0
10      Gecko/2009060215 Firefox/3.0.11
10      MSIE 6.0 Windows NT 5.1 SV1  MS-RTC LM 8
9       MSIE 6.0 Windows NT 5.1 SV1  

Since there are so many different ways a client can report themselves, I dumped the results into excel and used some PivotTable magic to get this:

Browser % of total
IE6SP2 65.81
IE6 26.74
IE7 4.21
JAVA 3.23
Unknown 0.01
FF 0.00

I dumped that into the Google Charts API to get this:

It’s not the overwhelming result I had hoped for with 27% of traffic over the last 2 weeks coming from the defunct browser I was trying to blame. Again, it seems unlikely that 27% of users are experiencing the same problem without reporting it.

But what the hell, I turned off http compression on one of the web servers anyway. I had no other leads at this point so I might as well. As expected, though, the user reported that it didn’t help.

It’d still be nice to narrow this down to a browser so I’ve asked the user to see if they can get a hold of another machine with IE7. If things work well on that machine at least I’ll know it’s either her machine or possibly her machine plus her browser.

It’s also very possible it’s something she’s doing. Maybe she clicks things just the wrong way or performs some operation that others don’t.


It’s at this point where I started gathering all my notes together and reviewing everything to see what I missed. And I missed something huge.

I took the user’s comments at face value and coupled them with a very strong assumption. Here are the predicates that led me away from the diagnosis:

  1. User: the problem only affects one page
  2. User: when the problem occurs on said page, other pages are fine
  3. Me: if all users on similar machines were having this problem, too, there’d be more people complaining about it.

I might be counting my chickens a little early yet but I’m pretty sure I have this problem figured out, and each of those three “facts” are wrong.

After talking with the user, she revealed that other areas of the site do slow down, just “not as bad”. Number 1 and 2 gone.

When reviewing her computer (Windows 2000, IE6, tiny amount of memory), and recalling the amount of patience users have with this product (a lot), I realized that assumption 3 isn’t very solid either.

Once I ignored those three items, it was obvious that the application itself had a problem that could likely be reproduced by me, in house. So that’s what I did—something I should have tried in the very beginning. I dug out an ancient laptop with Windows 2000 and IE6SP1 and started running the app. Much to my surprise (though I guess I should have expected it by this point), after 10 minutes, the app started to crawl. Badly.

Being the computer person, I immediately saw why in the little hard drive light. Internet Explorer was leaking memory like crazy and eventually, when the system ran out, caused the disk to thrash as Windows actively consumed and grew the page file. Watching the task manager, I could see a 1-2mb jump in memory usage with every click.

yikes

I tore the page apart and was able to create a simple page to reproduce the problem and share. The above chart (generated with Perfmon—a sweet tool on most windows machines) shows that simple page being executed over a period of about 3 minutes. You can see memory usage rose to about 90%, with the page file in tow. Each dropped quite suddenly when I terminated Internet Explorer.

Here’s the simple page that produces the above behavior in IE6SP1 (but not Opera 9.5, Firefox 3.5, Chrome 2, or Internet Explorer 8):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<link type="text/css" href="jquery-ui-1.7.1.custom.css" rel="stylesheet" />
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="jquery-ui-1.7.1.custom.min.js"></script>
<script type="text/javascript">
   $(document).ready(function() {
       $('.DatePicker:enabled').datepicker();
       setTimeout("Form1.submit();", 500);
   });
</script>
</head>
<body >
<form id='Form1' action='LeakTest2.htm'>
   <input class='DatePicker' />
   <input type='button' value='Refresh'
          onclick='Form1.submit();' />
</form>
</body>
</html>

The problem is jquery. It's not really jquery's fault--this is a documented bug with IE that's being triggered by jQuery. I hopped onto Google and started looking for solutions to “IE6 jquery memory leak”. I made another bad assumption when I wagered that there’d be an easy fix for this problem.

After trying a bunch of things, I opened a question on Stackoverflow and that’s where I stand now. My leads are currently:

  1. Keep googling for a solution
  2. Wait for someone to answer my question on SO
  3. Post on the jquery mailing list for help
  4. Learn a lot more about IE6’s memory leaks and attempt to patch jQuery myself

When I resolve this problem, I’ll post a follow up. Hopefully soon!

Wednesday, June 24, 2009

Thanks for Sharing…

…but Seriously Please Don’t Share.

Overheard on Sunday:

“I was washing them this way to try to get the hair off.”

…coming from the kitchen while eating in the dining room at Arby’s. Actually, as my wife recalls, this employee had just returned from the bathroom. I’m not sure if that’s better or worse. Trying to reason about it just makes my head hurt and my stomach sad.

“…washing them…”? “…hair off.”?! <Shudder> Pardon my harsh letters*, but WTF does that mean?

Not to let that ruin a perfectly mediocre meal, I went to refill my tasty beverage on the other side of the restaurant where I overheard another gem (from another employee):

“Actually I’ve had some bad luck lately with boy friends—two committed suicide. The first one shot himself and the second one hung (sic) himself. My boyfriend now’s in rehab.”

Are you kidding me? Like is this one of those times that people make up ridiculous stuff to say, hoping to be overheard? Something along the lines of: “and I’m like, ‘how do you expect me to remember where we buried her?’” I hope so…

Really I have only myself to blame. As we were driving home from church, Sarah suggested the nearby Arby’s for lunch. We’ve been to this location before and had previous regretful experiences (slow, a little dirty…or sticky…what is with that at fast food places? Did a shaggy dog take a bath* in some full-sugar Pepsi and shake/dry off all over the restaurant? Yuck.).

Nah, I thought, this will be different. And it was…different. I might never eat roast beef again. At least not until I forget all this in a few weeks and accidentally eat at Arby’s again.

On a barely related note, check out this ad-vs-actual round up of fast food sandwiches.

*Hat-Tip to Dane Cook

Monday, June 22, 2009

C# and VB.NET Compared

C# (and .NET) has come a long, long way since the early days of .NET 1.1. Let me start by clearing up some confusion about version numbers, quoting:

These are the versions of C# known about at the time of this writing:

  • C# 1.0; released with .NET 1.0 and VS2002 (in 2002)
  • C# 1.2 (bizarrely enough); released with .NET 1.1 and VS2003 (in 2003). First version to call Dispose on IEnumerators which implemented IDisposable. A few other small features.
  • C# 2.0; released with .NET 2.0 and VS2005 (November 2005). Major new features: generics, anonymous methods, nullable types, iterator blocks
  • C# 3.0; released with .NET 3.5 and VS2008 (November 2007). Major new features: lambda expressions, extension methods, expression trees, anonymous types, implicit typing (var), query expressions
  • C# 4.0; to be released with .NET 4.0 and VS2010 (release date unknown). Major new proposed features: late binding (dynamic), delegate and interface generic variance, more COM support, named and optional parameters
  • C# 5.0; unknown time frame. Major new speculated features: metaprogramming

There is no such thing as C# 3.5 - the cause of confusion here is that the C# 3.0 is present in .NET 3.5. The language and framework are versioned independently, however - as is the CLR, which is still (at the time of .NET 3.5) at version 2.0, service packs notwithstanding.

Now to the topic of the day: a few things that VB.NET has that C# lacks:

XML Literals

XML Literals are definitely worth checking out if you do much with VB. Here's a snippet to give you an idea of what they look like:

Function ExportAsXml(ByVal invoices As List(Of Invoice)) _ 
As String
  Dim XDoc As XElement = _
      <Invoices xmlns="http://tempuri.org/Schema/…">
          <%= From invoice In invoices Select _
              <Invoice ID  = <%= invoice.ID %>
               DueDate     = <%= invoice.DueDate %>
               Amount      = <%= invoice.Amount %>
               Customer    = <%= invoice.Customer %>/> %>
              </Invoices>
  Return XDoc.ToString
End Function

The effect is a little subtle at first—look closely and you’ll see something sweet: there is XML floating around in there without quotes. This feature won’t be coming to C# anytime soon, but similar functionality can be achieved.

Optional and Named Arguments

Another nice feature of VB, optional and named arguments is coming to C# later this year in C#4. While optional arguments can be largely avoided with overloading (and are not very popular to begin with), named parameters are nice. They provide a lot of clarity to maintenance programmers by calling our what means what. For example:

var Invoice = new Invoice(
CustomerID, InvoiceTotal, false, new DateTime(2009,6,23));

var Invoice = new Invoice(
customerID: CustomerID, total: InvoiceTotal,
isCanceled: false, dueDate: new DateTime(2009,6,23));

The second version is clearly more verbose but I think it provides some clear benefits. We can now immediately see what the boolean and date parameters were for without hovering or using variables just to get nice names.

IsNumeric and DateDiff are among many common functions that are actually available in C# if you add a reference to Microsoft.VisualBasic. I avoid doing this because without optional argument support, they can be a little awkward to use. C# and .NET now also include other options like TryParse on most types and date arithmetic with TimeSpans.

Overflow/Underflow Checking

There are also a few semantic differences between the two languages. For example, VB checks mathematic operations for overflow and underflow whereas C# does not. C# allows you to control this very easily with checked/unchecked blocks:

// will raise a System.OverflowException exception
int input = int.MinValue;
checked {
 input--;
}
return input;

// will overflow/underflow silently
int input = int.MinValue;
unchecked {
 input--;
}
return input;

As far as I can tell, VB doesn’t provide this level of control—it’s either on or off for the whole project.

Automatically Implemented Properties

Another feature exclusive to C# is automatically implemented properties. For example, here’s the old style:

// C#2
private string name;
public string Name
{
  get { return this.name; }
  set { this.name = value; }
}

and the new style available in C#3:

// C#3
public string Name { get; set; }

// C#3: or, with narrower set scope
public string Name { get; protected set; }

I love when I can reduce boilerplate/housekeeping code like this. Less code is better code.

Coalesce

C# also has VB beat with it’s coalesce operator, though admittedly I don’t use this very often:

// (C#3) returns the first non-null object 
// or null if each is null
return object1 ?? object2 ?? object3;

That requires a much less elegant approach in VB or C#2.

Iterator Blocks

C# majorly trumps VB with iterator blocks using the yield keyword. I’ve been using these more and more lately and am surprised they aren’t in VB yet. I didn’t really do them justice in my last post so look elsewhere for in depth examples.