Spaces in identifier names in C#

While I’m a fan of descriptive member names for testcase classes and test methods, there wasn’t a great way to create readable text.  Text in code editors is almost universally monospace, which reads very well for languages with lots of syntax.  But when it comes to stringing several words together to form a phrase, things get ugly.  Here’s a test I found in the StructureMap source code:

Or, let’s try that one converted to PascalCase:

As I see it, both of these options aren’t optimal.  It’s still work for me to read them, as each style is still only geared towards smallish groups of words.  But they don’t gel well to how people actually read, which is by groups of words, by scanning.  These naming styles simply don’t scan well, and to be honest, give me a headache after awhile.

While I’d rather not re-train myself to read with underscores, we can however do this:

Yes, this compiles.

Yes, it runs, in TD.NET and nunit-console.

Yes, it’s completely compliant to the ECMA C# language specification.   It still suffers from the same monospace issues, that monospace text is still more difficult to read than non-monospace text.  But I do find it visually less distracting.  Here’s how it’s done:

AutoHotKey fun

First, you’ll need to use either a VS Macro or AutoHotKey to help.  I use AutoHotKey to switch into a “Test Naming Mode”, borrowed from JP Boodhoo’s great start on the subject.  Mine is a little different at this point, as I have my R# template shortcut keys for generating BDD-style tests also kick off my AutoHotKey script.  “spec+TAB” creates my whole context base class, plus AutoHotKey listens to this same keystroke combination.  Otherwise, I can still use the same “Ctrl+Shift+U” keystroke to switch in and out of the test naming mode.

Somewhere along the line, you’ll see a method that either sends an underscore or a space to the target application:

;==========================
;Handle SPACE press
;==========================
$Space::
  if (IsInTestNamingMode) {
    Send, _
  } else {
    Send, {Space}
  } 

That first part, “Send, _” is what we’ll need to change.  Once we have our AutoHotKey script up and going, we can change it to send a very different character, a Unicode character instead of the underscore.

Trolling through Unicode

We can’t pick just any Unicode character of course.  First, it needs to be a valid C# identifier.  To find what a valid C# identifier is, we can reference the ECMA C# language specification, specifically section A.1.6, “Identifiers”.  In that section, it details what exactly a valid identifier can look like, described as the set of valid Unicode characters.  It’s much more than your traditional ASCII characters as well.

What I needed to find was a valid character for an identifier that looked like a space for the font I used.  There, it was simply a matter of trial and error going through the various categories allowed by the C# specification.  Some characters worked for some fonts and sizes, others did not.  Finally, I settled on one that worked for me at Consolas 10pt and 14pt, the font and size I use the most: UTF-16 0x200E, or “Left-to-right mark”.  I have zero idea what this character means, nor do I care, other than it’s a valid identifier character and it looks like a space in VS 2008 and most other text editors (and Word, Notepad2, Notepad++, etc.).

Once I found the right character, which I tested by copying and pasting into the editor, I was ready to change my AutoHotKey script to use the Unicode character instead of the underscore.

Sending Unicode through AutoHotKey

Unfortunately, AutoHotKey does not support sending Unicode characters very well out of the box.  From this forum post however, I found a great solution.  This code added to my AutoHotKey script:

EncodeInteger( p_value, p_size, p_address, p_offset )
{
   loop, %p_size%
      DllCall( "RtlFillMemory"
         , "uint", p_address+p_offset+A_Index-1
         , "uint", 1
         , "uchar", ( p_value >> ( 8*( A_Index-1 ) ) ) & 0xFF )
}

SendInputU( p_text )
{
   StringLen, len, p_text

   INPUT_size = 28
   
   event_count := ( len//4 )*2
   VarSetCapacity( events, INPUT_size*event_count, 0 )

   loop, % event_count//2
   {
      StringMid, code, p_text, ( A_Index-1 )*4+1, 4
      
      base := ( ( A_Index-1 )*2 )*INPUT_size+4
         EncodeInteger( 1, 4, &events, base-4 )
         EncodeInteger( "0x" code, 2, &events, base+2 )
         EncodeInteger( 4, 4, &events, base+4 ) ; KEYEVENTF_UNICODE

      base += INPUT_size
         EncodeInteger( 1, 4, &events, base-4 )
         EncodeInteger( "0x" code, 2, &events, base+2 )
         EncodeInteger( 2|4, 4, &events, base+4 ) ; KEYEVENTF_KEYUP|KEYEVENTF_UNICODE
   }
   
   result := DllCall( "SendInput", "uint", event_count, "uint", &events, "int", INPUT_size )
   if ( ErrorLevel or result < event_count )
   {
      MsgBox, [SendInput] failed: EL = %ErrorLevel% ~ %result% of %event_count%
      return, false
   }
   
   return, true
}

Allowed me to call one method to send the right Unicode value to my editor:

$Space::
  if (IsInTestNamingMode) {
    SendInputU("200E")
  } else {
    Send, {Space}
  }

Instead of sending an underscore character, I send the Unicode “200E” value, which happens to look just like a space.  Presto chango, my code now looks like it has spaces, but is still able to compile and run without skipping a beat.

Some major caveats

I’ve only played with this for a day or so, so I don’t know all the ramifications of going with these quasi-spaces in test class and method names.  Some things I’ve noticed so far:

  • R# Smart completion works some of the time (V4.5)
    • I don’t care
  • Test names are output without spaces or underscores
    • Could be a problem, maybe I just need to find a better space substitute
  • Anyone that wants to write test or method names like this NEEDS to have a macro or AutoHotKey script to convert spaces to the special character.  I haven’t found a way to easily, directly input this character inside the IDE.

This type of technique should not be used in any production, public API.  I’m targeting simply my test method and class names, which tend to get rather long and don’t have RSpec’s advantage of being able to use string literals.

It’s weird, but it works.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in BDD, C#. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Nolan Egly

    First off, I “watched” you work on this most of day via twitter and hats off for mostly figuring it out. Cool hack.

    I’m not sure I’d want to roll it out to my team though. I can see the confusion, especially in several years if all of the original team is gone.

    You haven’t gotten used to reading pascal case yet? With variable names like debitAccount and creditAccount or theSuperSecretMessageToEncrypt?

  • http://Http://www.theimes.com Anderson Imes

    While this is certainly a clever hack I have to agree with the previous commenter that you will likely have trouble when working with coworkers and onboarding new ones.

    This doesn’t negate the fact that for unit tests these names are a hair unreadable, however you are typically reading these names in post-run test reports. I would probably look at modifying how the test results are displayed to automatically parse method names into something more readable or perhaps being able to provide a more descriptive name in an attribute or XML comment and having that be read by your test runner or choice.

    Clever though… And thorough.

  • Jeremy Gray

    @Anderson – MbUnit has a Name attribute for doing just that. Its runners, reports, etc. also do a nice job of displaying the Name attribute value for tests (or fixtures) that have one.

    If there’s one thing I love about MbUnit it is how whenever someone does something new or even wants to do something new with a test framework I can just look over at MbUnit, turn back, and say “yup, MbUnit already does that. Has for a while now.” :)

  • http://iridescence.no Fredrik Kalseth

    Very cool :)

    However, what about just creating a special version of your VS font which renders for example ‘-’ as if it was a space?

    so when you write “some-test-name” it just *looks* like “some test name”

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Nolan

    I don’t really have to worry about onboarding. We use underscores in test names, which almost requires some sort of macro/AutoHotKey script as the underscore is annoying to get to. We can also put our AHK executable right with our source code, along with our R# templates etc.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Anderson

    I gotta be honest…I look at a unit test report at most once a week. I do however look at test names in code far more often. Probably just me, but this is definitely an optimization towards reading the tests in code.

    @Jeremy

    Yeah, I know that one. The Name attribute I see as merely a workaround for creating readable test names, as you still have to name your method something.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Frederik

    Now _that_ sounds like an interesting idea!

  • MarcT

    @Frederik

    In your font:

    int x = 5 3;
    printf(“%d”, x) // Prints “2″

    Invisible subtraction – Genius!

  • Caotain obvi0us

    @MarcT

    I think you mean “Invisible subtraction Genius!”

  • zihotki

    What about to change color of ‘_’ to some like on this picture – http://i43.tinypic.com/29zbzv9.png ? We’ll see underscores and easily can read code. But I didn’t know whether this possible or not with VS.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @zihotki

    Yeah, that’ll definitely do the trick too! We use underscores a lot in other places, so it might not work for us. Colors are less intrusive, however. Thanks!

  • Jeremy Gray

    @Jimmy – I hear ya. I have scripts that generate both the method name and the Name attribute, the former with spaces and the latter with underscores, and as much as that does help the situation I still cringe when I have to use it. :)

    I’m liking zihotki’s colour recommendation, as it could be applied selectively to just method and class names, though Fredrik’s font-based approach would do in a pinch also. I wonder if Jon (of ViEmu fame) could be convinced to modify CodeKana to do the colouring (as it would seem to be the closest applicable add-in off the top of my head)? ;)

  • http://scottbellware.com Scott Bellware

    Jimmy,

    If you’re not reading the report, you’re sacrificing a good bit of the methodology to a presumption.

    The purpose isn’t “test names”, it’s design, and the perspective of language on design and productivity. If you’re not using the report, then there’s more finer understanding to be cultivated through practice.

    It sounds like you’re making the mistake of presuming an understanding of BDD because you’ve done TDD. This is the same pattern as people presuming to understand TDD because they’ve done unit testing.

    Just like the beginning days with TDD, there are aspects of TDD that are only going to become visible and then repeatable after having practiced them.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Scott

    Maybe I can get more out of this in your March class but…

    On a recent project with around 1000 specs, I just couldn’t get good information out of the reports. They were just too big. And any information I wanted to know, I knew the codebase in and out to know exactly where to look.

    I find the spec names very helpful when I’m writing them, and as I’m working on a story, but not much more afterwards. Note: I’m talking about the default NUnit test output in CCNet, not yours or Aaron’s tools.

  • http://scottbellware.com Scott Bellware

    Ah! Well, without a reporting tool, there’s no way to view the language outside of the code and outside of code’s influence on cognition. Without that tool, a good chunk of the practice is just out of reach.

  • Yvonnedujali

    nice!!!!!!!

  • Pingback: The Split is Not Enough: Unicode Whitespace Shenigans for Rubyists

  • Pingback: Books about developing » Blog Archive » The Split is Not Enough: Unicode Whitespace Shenigans for Rubyists