Phillip Trelford's Array

POKE 36879,255

String and StringBuilder revisited

I came across a topical .Net article by Dave M Bush published towards the tail end of 2014 entitled String and StringBuilder where he correctly asserts that .Net’s built-in string type are reference types and immutable. All good so far.

The next assertion is that StringBuilder will be faster than simple string concatenation when adding more than 3 strings together, which is probably a pretty good guess, but lets put it to the test with 4 strings.

The test can be performed easily using F# interactive (built-in to Visual Studio) with the #time directive:

open System.Text

#time

let a = "abc"
let b = "efg"
let c = "hij"
let d = "klm"

for i = 1 to 1000000 do
   let e = StringBuilder(a)
   let f = e.Append(b).Append(c).Append(d).ToString() 
   ()
// Real: 00:00:00.317, CPU: 00:00:00.343, GC gen0: 101, gen1: 0, gen2: 0
   
for i = 1 to 1000000 do
   let e = System.String.Concat(a,b,c,d)
   ()
// Real: 00:00:00.148, CPU: 00:00:00.156, GC gen0: 36, gen1: 0, gen2: 0

What we actually see is that for concatenating 4 strings StringBuilder takes twice as long as using String.Concat (on this run 0.317ms vs 0.148ms) and generates approximately 3 times as much garbage (gen0: 101 vs gen0: 36)!

Underneath the hood the StringBuilder is creating an array to append the strings into. When appending if the current buffer length is exceeded (the default is 16) then a new array must be created. When ToString is called it may, based on a heuristic, decide to return the builder’s array or allocate a new array and copy the value into that. Therefore the performance of StringBuilder is dependent on the initial capacity of the builder and the number and lengths of the strings to append.

In contrast, String.Concat (which the compiler resolves the ‘+’ operator to) calculates the length of the concatenated string from the lengths of the passed in strings, then allocates a string of the required size and copies the values in, ergo, in many scenarios it will require less copying and less allocation.

When concatenating 2, 3 or 4 strings we can take advantage of String.Concat’s optimized overloads, after this the picture changes as an array argument must be passed which requires an additional allocation. However String.Concat may still be faster than StringBuilder in some scenarios where the builder requires multiple reallocations.

But wait there’s more, going back to the ‘+’ operator, if we assign the integer literal expression 1 + 2 + 3 the compiler can reduce the value to 6, equally if we define the strings as const string then the compiler can apply the string concatenations at compile time leading to, in this contrived example, no cost whatsoever.

The moral of the story is when it comes to performance optimization - measure, measure, measure.

Fun Basic Preview

Fun Basic is an extended clone of Microsoft’s Small Basic programming language that runs as an app in the Windows Store. The app provides a range of sample programs from simple turtle graphics through to video games and physics simulations. The samples have been selected from programs in the public domain created by the Small Basic community. Each sample is presented with it’s corresponding source code allowing you to edit the code and run the program.

FunBasic Entry Screenshot

The concept is that you can learn elements of programming by reading the provided programs and editing and enhancing them. The inspiration comes from the type-in programs circulated in computer magazines throughout the 80s, and through which I had some of my earliest forays into programming.

The editor on the other hand affords more modern conveniences including syntax colouring, code completion and tooltips over API calls.

FunBasic 1942 Screenshot

Why not head over to the Windows Store and try the preview (new features will be appearing weekly).

It’s free and there’s games to play! http://tinyurl.com/funbasic

Language resources

Fun Basic provides all the language features of Small Basic and it extends the language with parameters on subroutines. You can learn more about language features in the Small Basic Tutorial.

The app is currently a preview, in future releases extended support for function return values, tuples and pattern matching (using Select Case) will be enabled.

Technical bit

Fun Basic is an offshoot from an extended Small Basic Compiler project I wrote for fun in early 2014 while learning FParsec, a parser combinator libraryfor F#. You can learn more about that effort in my presentation at NDC London “Write Your Own Compiler in 24 Hours” and an interview on .Net Rocks on “Writing Compilers”.

My kids (8 & 12) have been enjoying programming and downloading apps from the Windows Store so last month I set out to cover both of these interests with a Store app version.

Interpreter

The Windows Store sandbox doesn’t support compilation within apps so the compiler was out. Fortunately I’d also knocked together an interpreter for Small Basic during early prototyping so I used this as a basis for the runtime. The interpreter simply pattern matches over the Abstract Syntax Tree (AST) generated by the parser, executing instructions and evaluating expressions.

Library

The next challenge was supporting Small Basic’s runtime library which provides simple graphics and text based operations. This had to be written from scratch as it needed to work against the Windows Store API and run in process with the app. All API calls are made asynchronously and I’ve employed separate canvases for the drawing, shapes and text layers. There’s also support for the Flickr API which unfortunately at the time of writing is broken in Small Basic.

image

Editor

The editor employs the ActiPro SyntaxEditor control to provide syntax colouring, code completion and tool tips. ActiPro’s Language Designer wizard meant I had syntax colouring set up in minutes, and it was relatively easy to set up the code completion and tooltips using my existing parser and AST. I’m planning to enable more of the SyntaxEditor’s features in future versions.

App

To build the app I used the Windows Store Grid App project template that’s built-in to Visual Studio. All that was needed was to customize the grid items with pictures and descriptions for the master view and add the editor and program panels to the detail view.

Logo

Special thanks to Sergey Tihon,, author of the excellent F# Weekly, for putting together a nice logo for the app!

Source Code

The source is open and available on BitBucket, see http://bitbucket.org/ptrelford/funbasic

If you delve in you’ll find a mixture of F#, C# and VB.Net. F# is used for the parser and interpreter, C# for interfaces and small imperative functions and VB.Net for gluing the app together.

Releases

I’m currently releasing new features weekly, let me know if there’s a feature you “must have” via Twitter @ptrelford :)

Find the last Sunday of each Month

Rosetta Code has a number of programming tasks with example solutions in multiple languages. One of those tasks is find the last Sunday of each month. Here’s a sample in C#:

DateTime date;
for (int i = 1; i <= 12; i++)
{
   date = new DateTime(year, i, DateTime.DaysInMonth(year, i), System.Globalization.CultureInfo.CurrentCulture.Calendar);
   while (date.DayOfWeek != DayOfWeek.Sunday)
   {
      date = date.AddDays(-1);
   }
   Console.WriteLine(date.ToString("yyyy-MM-dd"));
}

I thought it might be fun to write an F# version, code golf style, that fits in a tweet:


The general gist of that solution was to create a list of all days in each month in reverse order and find the first Sunday (which will be the last):

[for month in 1..12->
   [for day in System.DateTime.DaysInMonth(2014,month).. -1.. 1->
      System.DateTime(2014,month,day).DayOfWeek,(month,day)]
   |> Seq.find (fun (dayOfWeek,_) -> dayOfWeek = System.DayOfWeek.Sunday)
]

 

Enter Petricek

Then Tomas Petricek came up with a neat solution that had enough space left over to execute against @fsibot:


Tomas’s solution evaluates each day of the year, yielding the last Sundays as dates:

[for days in 0.0 .. 365.0 do 
   let day = System.DateTime(2014,1,1).AddDays(days) in 
   if int day.DayOfWeek = 0 && day.AddDays(7.).Month <> day.Month 
   then yield day
]

 

Wellum Reprise

Meanwhile Richard Wellum suggested an alternate solution in C#, which I was able to translate to standalone F# with space left over for a pretty print:


Richard's solution is to calculate the last day of the month, find the day of week and subtract that value to reach the Sunday. Here's a version with variable names:

[for month in 1..12->
   let lastDay = System.DateTime(2014,month,1).AddMonths(1).AddDays(-1.) in 
   lastDay.AddDays(-(lastDay.DayOfWeek|>int|>float)).ToString("m")
]

Conclusion

Finding the last Sunday of each month in a tweet now appears to be a solved problem :)