Update from the United States

Well I have not posted for a while, and that has mostly been because I have been getting ready for, traveling, or just being in the States.

So far I have had a grill (NZ BBQ) in Livermore (San Francisco), CA

Visited a mine site (but not gone out into the actual Mine) in Gillette, WY

Visited Caterpillar’s massive proving grounds in Peoria, IL

Gotten bored in Las Vegas, NV (where I currently am)

After a couple of Hotels with free Wifi/Internet, free breakfast and free local calls, Las Vegas is to be a huge disappointment of what it deliveries and a huge just pay more at each step.

However, MinExpo 2008 is fantastic, and I’ll take my camera tomorrow and capture many great big machines close-up.

TimeDirection graph

A work college was wanting some trivial code to draw a time based direction plot, and insisted that I do it.

So here is my drawing class:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace LineCurve
{
    public class TimeDirection
    {
        public void Draw(Graphics g, Panel pnl, List<KeyValuePair<int,float>> data, int maxtime)
        {
            using (Brush brush = new SolidBrush(Color.Blue))
            {
                float halfx = pnl.Width / 2.0f;
                float halfy = pnl.Height / 2.0f;
                float scale = Math.Min(halfx, halfy) / (float)maxtime;

                foreach (KeyValuePair<int, float> kvp in data)
                {
                    int time = kvp.Key;
                    double dir = kvp.Value / 180.0 * Math.PI;

                    // subtrack y as 0 is top, and +y is bottom.
                    float fx = (float)(halfx + (Math.Sin(dir) * scale * time));
                    float fy = (float)(halfy - (Math.Cos(dir) * scale * time));

                    g.FillRectangle(brush,fx, fy, 1.0f, 1.0f);
                }
            }
        }
    }
}

And given the input:

List<KeyValuePair<int,float>> data = new List<KeyValuePair<int,float>>();
for (int i = 0; i < 40; i++)
{
    data.Add(new KeyValuePair<int, float>(i, i * 9.0f));
}

Looks like this:

time/direction based graph

This code is released under the MIT license, except it may not be used for web-based weather applications.

Learning to use foldl and map

I have been working on a small line drawing project, and part of that project is indexing nested lists based on sets of indices.

Firstly I wrote a function to return the recursive nth item.  So for this data [[[1,2],[3,4]],[[5,6],[7,8]]] and the input [1,2,1] the value 3 is returned.  Here’s my original function:

point(Cube,[First|Rest]) ->
point(lists:nth(First,Cube),Rest);
point(Cube,[]) ->
Cube.

I then had a couple of functions to return point lists for each list of points look-ups.  The first line was for connected points, and the second lines to draw separate lines.  So using the same data above, and the input [[1,2,1],[2,2,2],[1,1,1]] to line would generate [3,8,1], and lists of that input to lines creates lists of results.  Brilliant I know, here’s my code:

lines(Cube,Lines) ->
    lines(Cube,lists:reverse(Lines),[]).

lines(_Cube,[], Output) ->
    Output;
lines(Cube,[First|Rest], Output) ->
    lines(Cube,Rest,[line(Cube,First)|Output]).

line(Cube,Points) ->
    line(Cube,lists:reverse(Points),[]).
line(Cube,[First|Rest],Output) ->
    line(Cube,Rest,[point(Cube,First)|Output]);

line(_Cube,[],Output) ->
    Output.

I used a wrapper function to reverse the input, to solve the list construction order.  I was quite proud of my groking tail recursion.  But couldn’t help notice line and lines are the same, but not the same.  While reading how to do the output formatting, I came across some good examples on using foldl and map.  Surprise, the examples where like my functions, so I rewrote them like this (renaming point to nth_nth):

lines(Cube,Lines) ->
    lists:map(fun(Line) -> line(Cube, Line) end, Lines).

line(Cube,Points) ->
    lists:map(fun(Point) -> nth_nth(Cube, Point) end, Points).

nth_nth(Vals,Nths) ->
    lists:foldl(fun(Nth,List) -> lists:nth(Nth,List) end, Vals, Nths).

Much better, but I started to have a nagging feeling about using anonymous functions to just call a single function.  I then found the way to refer to other functions by name, but this does not work for the map as I am binding an extra variable, but for foldl it does work as it’s arity is 2, thus nth_nth can be written as:

nth_nth(Vals,Nths) ->
    lists:foldl({list,nth}, Vals, Nths).

I thought the use of the fold function to return nested look-up results was clever. The new functions have less total lines, but each line is much denser, so may appear harder to read, but I am using standard functions so the cost to comprehend should be lower.

Evils of typedefs and legacy code

Our legacy C++ codebase once was a C codebase.  Way back then, there was no standard boolean type.  So in the wisdom of the day a type was declared

typedef int tBool;

The major problem with tBool’s is that over time enums, #define or magic constants get assigned to them, or they can be compared to said enums, #defines or magic constants, as they are all int’s.

Which works, but years later *somebody* came along and replaced the tBool for bool, and we started getting issues.

Now as in a lot of large codebases there tends to be a large amount of ignored warnings, and not enough daylight hours to remove them all.

So given that, and that your using Visual Studio 2005, here are the ones you should find and remove.

#define NON_BOOL_DEFINE 42
bool boolValue;

boolValue = NON_BOOL_DEFINE;

Warning C4305: ‘=’ : truncation from ‘int’ to ‘bool’

if( boolValue == NON_BOOL_DEFINE )

Warning C4806: ‘==’ : unsafe operation: no value of type ‘bool’ promoted to type ‘int’ can equal the given constant

Another hint your boolean types are being used wrong is this warning

Warning C4800: ‘const int’ : forcing value to bool ‘true’ or ‘false’ (performance warning)