Using Interactive C# (REPL)

The REPL, that is Read Eval Print Loop, is a feature provided by many programming language environments today, such as Python, Ruby, Scala and Haskel. For those who are not familiar with the notion, you could think of REPL as an interactive interpreter (even though it’s not always implemented as one). You can find more info here.

It practically is an interactive prompt (like a UNIX shell, or Windows PowerShell), that accepts expressions in your favorite programming language syntax. There was no practical implementation of a REPL for C# until the Mono project implemented a C# Interactive Shell in Mono 2.2, called csharp. It comes with two flavors: 1). as a command line shell under the name csharp and 2). with a graphical front end called GSharp.

I am sure that every developer, novice or seasoned, needs to test out some small snippet of code, from time to time, to make sure that it does what it is supposed to do. This is also true for C# developers. However, in the absence of a REPL for C#, the only way to do that was by creating a whole new project in Visual Studio or MonoDevelop with a very simple console application. Not only it seems like an overkill if you just want to test a few lines of code, but you also end up with a bunch of little test projects that you are never going to need.

However, now that Mono implemented a C# REPL there is no need to create a test console project for everything. It is extremely useful if you want to test out some piece of code.

An example from my own experience is when, in a C# project I have been working on, I needed to dynamically create a list of enum field values and their string names. I was not 100% percent sure of the way I thought of implementing this, so I wanted to test it out first.

Here it is, in the csharp interactive C# shell, running from a Linux command line:

anirothan@netbook:~$ mono-2.4 csharp
Mono C# Shell, type "help;" for help

Enter statements below.
csharp> var fileModeNames = Enum.GetNames(typeof(System.IO.FileMode));
csharp> fileModeNames;
{ "CreateNew", "Create", "Open", "OpenOrCreate", "Truncate", "Append" }
csharp> var fileModeValues = Enum.GetValues(typeof(System.IO.FileMode));
csharp> fileModeValues;
{ CreateNew, Create, Open, OpenOrCreate, Truncate, Append }
csharp> var pairs = new Dictionary<string, System.IO.FileMode>();
csharp> for(int i=0; i<fileModeValues.Length; ++i)
 > pairs.Add(fileModeNames[i], fileModeValues.GetValue(i));
{interactive}(2,7): error CS1502: The best overloaded method match for `System.Collections.Generic.Dictionary<string,System.IO.FileMode>.Add(string, System.IO.FileMode)' has some invalid arguments
/opt/mono-2.4/lib/mono/2.0/mscorlib.dll (Location of the symbol related to previous error)
{interactive}(2,7): error CS1503: Argument `#2' cannot convert `object' expression to type `System.IO.FileMode'
csharp> var pairsCorrect = new Dictionary<string, object>();     
csharp> for(int i=0; i<fileModeValues.Length; ++i)               
 > pairsCorrect.Add(fileModeNames[i], fileModeValues.GetValue(i));
csharp> pairsCorrect;
{{ "CreateNew", CreateNew }, { "Create", Create }, { "Open", Open }, { "OpenOrCreate", OpenOrCreate }, { "Truncate", Truncate }, { "Append", Append }}
csharp> pairsCorrect["CreateNew"]
 > ;
CreateNew
csharp> quit;
null

That was fairly easy and simple. The intention was to create a dictionary of enum field names and values. For the sake of testing I used the System.IO.FileMode enum.

The flexibility of the csharp REPL does not end there. Here is an extract from a session in gsharp (The gtk+ graphical front-end to csharp) which actually creates a window with a dropdown list.

csharp> LoadPackage("gtk-sharp-2.0");
csharp> using Gtk;
csharp> var window = new Window("Simple dropdown list binding test with csharp REPL");
csharp> var vbox = new VBox();
csharp> var label = new Label("This is a simple test.");
csharp> vbox.PackStart(label);
csharp> var model = new ListStore(typeof(System.IO.FileMode), typeof(string));
csharp> var fileModeNames = Enum.GetNames(typeof(System.IO.FileMode));
csharp> fileModeNames;
{ "CreateNew", "Create", "Open", "OpenOrCreate", "Truncate", "Append" }
csharp> var fileModeValues = Enum.GetValues(typeof(System.IO.FileMode));
csharp> fileModeValues;
{ CreateNew, Create, Open, OpenOrCreate, Truncate, Append }
csharp> var model = new ListStore(typeof(System.IO.FileMode), typeof(string));
csharp> for(int i=0; i<fileModeValues.Length; ++i)
 > model.AppendValues(fileModeValues.GetValue(i), fileModeValues[i]);
{interactive}(2,48): error CS0021: Cannot apply indexing with [] to an expression of type `System.Array'
csharp> for(int i=0; i<fileModeValues.Length; ++i)
model.AppendValues(fileModeValues.GetValue(i), fileModeNames[i]);
csharp> var dropDown = new ComboBox();
csharp> var renderer = new CellRendererText();
csharp> dropDown.PackStart(renderer, true);
csharp> dropDown.AddAttribute(renderer, "text", 1);
csharp> dropDown.Model = model;
{ { CreateNew, "CreateNew" }, { Create, "Create" }, { Open, "Open" }, { OpenOrCreate, "OpenOrCreate" }, { Truncate, "Truncate" }, { Append, "Append" } }
csharp> vbox.PackEnd(dropDown);
csharp> window.Add(vbox);
csharp> window.ShowAll();
csharp>
The GSharp C# Interactive Shell in action.

The GSharp C# Interactive Shell in action.

There are some limitations though. For example, you cannot create classes (but you can put .cs files in the ~/.config/csharp directory that will be loaded automatically to the interactive shell) and there is an apparent lack of code completion features. However, these limitations are already being worked on and I hope they will become available with mono 2.6.

Share and enjoy Wink
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • MySpace
  • Reddit
  • Technorati
  • TwitThis

Tags: , , , , , , , , ,

Leave a Reply