I have several situations where I need to control timeouts in a technical application. Either in a loop or as a simple check. Of course – handling this is really easy, but none of these is looking cute.

To clarify, here is some C# (Pseudo) code:

private DateTime girlWentIntoBathroom;
girlWentIntoBathroom = DateTime.Now;

  // do something
} while (girlWentIntoBathroom.AddSeconds(10) > DateTime.Now);


if (girlWentIntoBathroom.AddSeconds(10) > DateTime.Now)
  MessageBox.Show("Wait a little longer");
  MessageBox.Show("Knock louder");

Now I was inspired by something a saw in Ruby on StackOverflow:

Now I’m wondering if this construct can be made more readable using extension methods. My goal is something that can be read like

“If girlWentIntoBathroom is more than 10 seconds ago”

1st attempt

if (girlWentIntoBathroom > (10).Seconds().Ago())
  MessageBox.Show("Wait a little longer");
  MessageBox.Show("Knock louder");

So I wrote an extension for integer that converts the integer into a TimeSpan

public static TimeSpan Seconds(this int amount)
  return new TimeSpan(0, 0, amount);

After that, I wrote an extension for TimeSpan like this:

public static DateTime Ago(this TimeSpan diff)
  return DateTime.Now.Add(-diff);

This works fine so far, but has a great disadvantage. The logic is inverted! Since girlWentIntoBathroom is a timestamp in the past, the right side of the equation needs to count backwards: impossible. Just inverting the equation is no solution, because it will invert the read sentence as well.

2nd attempt
So I tried something new:

if (girlWentIntoBathroom.IsMoreThan(10).SecondsAgo())
  MessageBox.Show("Knock louder");
  MessageBox.Show("Wait a little longer");

IsMoreThan() needs to transport the past timestamp as well as the span for the extension SecondsAgo(). It could be:

public static DateWithIntegerSpan IsMoreThan(this DateTime baseTime, int span)
  return new DateWithIntegerSpan() { Date = baseTime, Span = span };

Where DateWithIntegerSpan is simply:

public class DateWithIntegerSpan
  public DateTime Date {get; set;}
  public int Span { get; set; }

And SecondsAgo() is

public static bool SecondsAgo(this DateWithIntegerSpan dateAndSpan)
  return dateAndSpan.Date.Add(new TimeSpan(0, 0, dateAndSpan.Span)) < DateTime.Now;

Using this approach, the English sentence matches the expected behavior. But the disadvantage is, that I need a helping class (DateWithIntegerSpan).

Has anyone an idea to make checking timeouts look more cute and closer to a readable sentence? Am I a little too insane thinking about something minor like this?

  • Why is your helper class a problem? You'll find most "fluent" interfaces (which is what you're building here) involve a command builder class which implements several syntax interfaces. – pdr Sep 6 '12 at 12:54
  • I think that trying to write code as actual English sentences won't work well, no matter what you try. – svick Sep 6 '12 at 13:02
  • @pdr: I'm not familiar with "fluent" interfaces. It just "feels" superfluous creating a class just for this single usage – Markus Sep 6 '12 at 13:02
  • It seems superfluous to change the syntax of the language/framework, to make it read like English (Ruby is an entire language designed based on a desire to do that, so of course its metaprogramming ability is more easily flexed). But that doesn't mean you shouldn't. :) – pdr Sep 6 '12 at 13:09
  • @pdr: So you recommend to handle it "old style" because everything else is possible but more like violating the language? – Markus Sep 6 '12 at 13:14

You are trying to solve a none existent problem. Programming is not about writing proper english sentences (and I'm not a native english speaker, so pardon the english).

I find this code hard to read:

if (girlWentIntoBathroom.IsMoreThan(10).SecondsAgo())

I have no idea that girlWentIntoBathroom contains a date/time. I have to read the method SecondsAgo to udnerstand that, and then go back to the beginning of the line and re-read everything to understand what it does.

if (girlWentIntoBathroom > 10.Seconds().Ago())

Is more readable, I can by looking at 10.Seconds() tell that girlWentIntoBathroom is some kind of date/time unit.

While this is enough for me:

if (girlWentIntoBathroom > TimeSpan.FromSeconds(10).Ago())

Since I'm used to the TimeSpan structure.

This is just fine too:

if (girlWentIntoBathroom > DateTime.Now.AddSeconds(-10))

Since we are after all programmers and AddSeconds(-10) will therefore make sense.

  • Your first example should read if(girlWentIntoBathroom.MoreThan(10).SecondsAgo()) Fluent interfaces are not about understanding the underlying code; it's the difference between Linq sugar (which is more English-like), and Linq Extension methods (which are more programmatic). But, like you, I dislike this kind of obfuscation. – Robert Harvey Sep 6 '12 at 18:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.