Saturday, August 29, 2015

Small but powerful UI highlight decorations in WinForms with closures

I've been working so much recently with languages for which closures is the norm - Node (which, if you haven't heard yet, is a useful JavaScript platform that obviates the need for a browser), Go, Ruby - that it's easy to think of this as the natural way to program.

In this post, and a follow-up to come in a couple of days, I'll talk about use of closures in languages for which it's not so natural. Next time, I'll talk about C++'s support, which is only very recent (in consideration of its age) with the advent of C++ 11 / 14; I'll also show how they can be synthesised with some locality (but a lot of messing around) in "old" C++ (C++'98 and before).

First, C#, which has great support in recent forms of the language, but didn't start out that way.

A while back I was helping out a buddy with a WinForms scientific application, which involved a large and sophisticated amount of user input, spread over numerous forms (separated by a two-level nesting of tabs). The challenge was that inputs in many parts of each form depended on the presence and on the values of input in other parts of each form, and there were also such dependencies between parts of different forms.

Dealing with invalid user input follows the established troika of detect, report, respond (just as it does for dealing with failure). For a UI program in the activity of eliciting user input, detection and response are pretty run of the mill:
  • Detection, is simply determining whether the given input is (in)valid, such as negative numbers or alpha/punct in a numeric field. This may be done when a control is being populated, when focus leaves the input control, or when a button is pressed (whether to dismiss a dialogue or to fill out a further portion of the form). Doing so on button pressing is the easiest, and that was the case here;
  • Response, for user input, is, of course, in the purview of the user. The key to eliciting a good  response (and resulting in good user experience) is good reporting.
From experience - think MFC programming a long time ago - I've found it useful to report invalid input in forms to users by two simultaneous actions:
  • set the focus to the control containing the "offending" values (which may include just missing values); and
  • change the control background to an eye-catching colour, and then set it back when focus leaves the control (presumably with a correct value, set there by the now, ahem, focused user).
Back in the days of Windows UI programming in C/C++, whether straight to the Win32 API, using MFC, ATL, or whatever, setting up such functionality involved a lot of coding and the involvement of multiple components. (Dare one remind gentle readers about control reflection ... ???)

In WinForms, it's straightforward enough to go to a control - just call ctrl.Focus() - and to set the background colour - just assign to ctrl.BackColor - but how do we get it to change back when the focus leaves the control without involving the rest of the program?

Here's where C#"s closures come to the rescue. Rather than any more waffle, let me just present the solution (coded for TextBox) as it appears in the utility code:

public static void FocusAndHighlight(TextBox tbx, Color highlightColour)
{
  // Have to declare these two as variables, since they
  // will be "closed over" by the lamdba (aka closure)

  Color         originalClr = tbx.BackColor;
  EventHandler  handler     = null;

  // Note that handler has to be initialised and then
  // separately assigned

  handler = (object sender, EventArgs e) =>
  {
    tbx.BackColor = originalClr;

    tbx.Leave -= handler;
  };

  tbx.Leave += handler;
  tbx.BackColor = highlightColour;
  tbx.Focus();
}

I trust the logic here is pretty straightforward:

  • remember the original background colour of the control;
  • create a handler, using lambda syntax, that returns the background colour to its original and attach it to the control's Leave event;
  • set the background colour to the required highlight;
  • set focus to the control.
The key to making this work is to declare two local variables - originalClr, which stores the original colour, and handler, which allows the handler to be removed from the control's Leave events, returning it to its original state entirely when the focus is left. 

Declaring the variables is essential, and this is something you must remember when working with closures in C# (and in many other languages): closures closes around variables, not values.

With this component, getting the user's attention and taking them to where they need to be is a single call:

if(0 == tbx.Text.Length)
{
  ControlUtil.FocusAndHighlight(tbx, Color.Yellow);
}



Wednesday, August 26, 2015

Simple cat in Node


I have a longstanding interest in writing system tools in different languages. In this post, I'll look at implementing a simple cat written in JavaScript and executed on Node.

The implementation is pretty succinct:


#! /usr/bin/env node

const
  fs = require('fs')
, readline = require('readline')
, paths = process.argv.slice(2)
, cat = function(path) {

    const stm = path ? fs.createReadStream(path) : process.stdin;

    readline.createInterface({
      input: stm,
    }).on('line', function(line) {

      process.stdout.write(line + "\n");
    });
  }
;

if(0 == paths.length) {

  cat(null);
} else {

  // process each one at a time
  paths.forEach(function(path) {

    cat(path);
  });
}

We start with requiring two standard components: fs and readline (which I won't explain further here, because they're standard, so you probably should know them, and because the docs are great, so you can get to know them easily if you need to). Both of these are not going to be reassigned, so I define them const.

Also defined in this way is the paths variable, which obtains all the arguments given on the command-line (excepting the script name, of course), and a cat() function, which takes a single parameter, path. If path is null, cat() uses the standard input stream (process.stdin()); if not, a stream is created on the file (via fs.createReadStream()). (Naturally, if the file does not exist or cannot be accessed for reading by the calling process, an exception will be thrown.)

Inside cat() we invoke readline.createInterface(), specifying our discriminated stream for input and standard output stream for output, and then specify a handler for the 'line' event that writes out the line.

With cat() so defined, we invoke according to the number of arguments we're given. If we're given one or more arguments, then invoke cat() for each; otherwise we pass null to read from standard input.

Note that this may have a concurrency vulnerability, insofar as the contents from multiple paths may be interleaved when the fs components' buffering limit is exceeded, due to Node's concurrency model, but I have yet to experience it in testing. Just don't treat this as production code.