Cliché Developer Blog

Adding to the swarm of developer blogs since 2007

Tuesday, March 13, 2012

Dabbling

The Pragmatic Programmer is a great resource for any developer; on the subject of learning new programming languages it states:
Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut.
Generally I try to follow this advice as best I can (although the real world can often put a damper on such things). Recently at work I've had the pleasure of getting to learn Ruby (and by extension, Rails) and I thought I'd share some brief thoughts on the language. Some background might be in order; I already know Python and use it quite regularly so I have some preconceived notions of what a dynamic scripting-type of language should be. That said I've thoroughly enjoyed what I've seen of Ruby so far. Some things I've noticed:
  • Strong OO constructs: I love that Ruby embraces OO and things like encapsulation on a first-class level (without all the _nonsense_). The pythonic way of doing OO always annoyed me. The ability to monkey patch a class is neat but I'll have to spend a lot more time with it to see a great use beyond occasional bug fixes.
  • Truly functional: Actual first-class functions in a language--impossible you say! I am finding more and more that I want to be able to pass and store functions and Ruby makes it a breeze. Python's sad and limited
    lambda
    construct is woefully inadequate in far too many scenarios (I understand why they limit it however it still cripples the language).
  • Documentation leaves something to be desired: Don't get me wrong, there are a ton of great Ruby resources, however when you get to the meat and potatoes of how some of the functions work I've had a hard time understanding some of the documentation that's out there.
I read a blog recently that mentioned a quick exercise for a programmer new to a language--write a run-length encoder for simple text-only strings. Figuring this was pretty simple I wrote up the first thing that came to mind in a little function:

def rle(str) token = nil counter = 1 out = str.split("").reduce("") do |cur, obj| if obj == token counter += 1 cur else if token != nil out = cur + counter.to_s + token else out = cur end token = obj counter = 1 out end end if token != nil out += counter.to_s + token end out end


This is the standard imperative way to do things, and the most obvious for many programmers. Something interesting is that Ruby's
string
doesn't appear to implement a generic sequence type (
Enumerable
in Ruby) in 1.9.3; hence the
str.split("")
to convert the string into an
Array
. I don't quite understand the logic there; my personal favorite language C# makes sure that the string type implements
IEnumerable<char>
so you can do some fancy stuff with LINQ. The mutability of strings in Ruby may play a role here but I haven't explored it fully.

I'm pretty unhappy with something that's so verbose and filled with plumbing. So I ran off and wrote a new run-length encoder that's a bit more terse:

def rle2(str) processed = str.split("").chunk {|l| l}.reduce(:<<) if processed.count > 0 output = processed[1].count.to_s + processed[0] end output += processed[2..-1].reduce("") {|out, item| out += item[1].count.to_s + item.first } end


I was pretty happy with this solution however you'll notice that it could be quite a bit shorter if I didn't have to special-case the first chunk. The problem is the
reduce(:<<)
is appending to a list with the first element, causing it to be flatted into the array. The solution is to add an initial empty list to the reduce call so the first item won't be hijacked. We can now also get rid of the two-pass reduce and get this nice little function:

def rle2(str) str.split("").chunk {|l| l}.reduce("") {|out, item| out += item[1].count.to_s + item.first } end


All in all a good time, I hope to be getting really dirty with Ruby in the future but I thought I'd share some thoughts about my first experience.

Tuesday, March 16, 2010

What a cruel fate, to be Ctrl-V'd

Questions like this pop up now and again over at StackOverflow and usually I find myself agreeing with the majority; copy-paste coding leads to smells and all sorts of nastiness. In our current code base here, I have had the joy task of refactoring some C# code that looks something like:

switch (caseName) {
  case "First":
    // Many lines of boilerplate
    break;
  case "Second":
    // Many lines of the same boilerplate with a single value changed
    break;
  // and so on
}

Inexcusable? Perhaps. However, sometimes the reality of business hits and you've got a day to implement a new feature for a demo tomorrow and right about then you start clinging to the Ctrl-C chord pretty hard. After all, shipping the product is a feature. So sometimes you suck it up and paste that switch statement together and hope for the best.

There is a line I like to draw, and that is when you start duplicating code that you don't understand. Recently I stumbled across the following blog post detailing a method to hide the checkbox from arbitrary items in a TreeView. I'll duplicate the important part of the code here (C#):

TVITEM tvItem = new TVITEM();

tvItem.hItem = node.Handle; 
tvItem.mask = TVIF_STATE;
tvItem.stateMask = TVIS_STATEIMAGEMASK;
tvItem.state = 0;

IntPtr lparam = Marshal.AllocHGlobal(Marshal.SizeOf(tvItem));
Marshal.StructureToPtr(tvItem, lparam, false);
SendMessage(this.treeView1.Handle, TVM_SETITEM, IntPtr.Zero, lparam);

What's missing here? Why that's correct, we're missing a call to Marshal.FreeHGlobal since MSDN says we need to free that memory. Now this is just sample code so you might be tempted to say that it is the reader's burden to interpret and understand the code (and I would agree with you). Looking at the comments to this post however, I see many individuals that seem to have taken the code literally and no doubt used it without thinking through it. As if further proof was needed I recently found nearly that exact same code polluting our own code base and fixed it. Now many of our developers are new to C#, and indeed, to Windows programming in general so I can't entirely fault them. I just find it hard to consider oneself a software developer (or moreso, an engineer) when actual design and engineering principles are ignored as often as they are in this field.

In case you were wondering, the correct code for hiding a checkbox on a TreeView doesn't need to allocate any unmanaged memory directly at all:

public const int TVIF_STATE = 0x8;
public const int TVIS_STATEIMAGEMASK = 0xF000;
public const int TV_FIRST = 0x1100;
public const int TVM_SETITEM = TV_FIRST + 63; 

[StructLayout(LayoutKind.Sequential)]
public struct TVITEM  {
  public int mask;
  public IntPtr hItem;
  public int state;
  public int stateMask;
  [MarshalAs(UnmanagedType.LPTStr)]
  public string lpszText;
  public int cchTextMax;
  public int iImage;
  public int iSelectedImage;
  public int cChildren;
  public IntPtr lParam;
}

[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, ref TVITEM lParam);

private void Hide_Checkbox(TreeNode node) {
  TVITEM tvi = new TVITEM();
  tvi.hItem = node.Handle;
  tvi.mask = TVIF_STATE;
  tvi.stateMask = TVIS_STATEIMAGEMASK;
  tvi.state = 0;
  SendMessage(this.Mission_treeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
}

It's almost funny to note that this code is both simpler and more efficient (although I haven't proved it) than the other (broken) code.

Thursday, March 11, 2010

Blog Post Mark II

Wow, 2007.

So it has been a while since this was updated; and yes I know it's pretty standard to say that but we're going on 3 years here so bear with me.

What has happened in all this time? Well PixelRPG ran out of the traditional developer resources (willingness to write mounds of boilerplate code) and is stalled pending further time and energy.

So where does that leave me? Well I'm working for a little company called Northrop Grumman and in doing so get to work with some talented folks writing software to display and manipulate some pretty big images. How big? Well I will say that our software has managed to load a 17 gigabyte file and display it at interactive framerates. I'll touch on some of the interesting things that can be done when you can't load an image into memory in a future post.

So lets get down to the motivation for this entry: blogs. I've noticed in my blogspace (blogsphere? blogodome?) traversals that there is some art to posting interesting and informative blog posts some people get, and some don't. You have people like Joel who may not post often but really truly put that extra effort in to make sure their post is fun to read and poignant. On a different side of the coin, you see people like Raymond who have an enormous backlog of posts coming at you every (work)day that are informative but not always fun. On the third side of our bizzare blog-coin you see the people that don't manage to nail the fun or the informative portion (I'm going to avoid naming names here but I think we've all see couple of these).

That said, here's what I've seen as important points to make a great blog:

  • Talk to your strengths: The classic advice given for speeches applies doubly so when people have time to really think about your posts. I've found it enjoyable to read what knowledgeable people have to say about subjects they've studied for ample quantities of time, or even smaller things like new usages for old tricks. Stay away from ranting about things that you clearly have very little idea about (for me, cooking).

  • Analogies are great (sometimes): If you've never had an analogy run away from you, you're probably in the minority of people. Sticking too hard to analogies can leave you trapped in a confusing world where you have robots applying lambda functions to sheep and now you've lost me. This post by Joel is an excellent example of how to set up an analogy effectively without running away with it.

  • Pictures! (or images, if you're a programmer): Images really make reading a blog feel less like a chore. Even pointless block pictures taking up space can exercise the reader's eyes and visually draw their attention down the page. I can't count the number of times I've stopped reading a blog that had Wall 'o Text syndrome.

  • Talk about ME: I'll end this short list with the most important one; we aren't too different, you and me, so use language that is personal and reflects that we're on similar footing. Relate challenges and interesting occurrences to common programmer experiences and issues. Don't just talk about how great your pet project Foo is, let us know how that dynamic event-based DSL parser threw you for a loop when it deadlocked every fifth run. Programmers that have been there can relate and (I would like to think) we appreciate that you are a human and not a marketing robot.

I would like to flesh this list out much more, however I'd need to go back and relive many of the blogging nightmares and that's too much for one work day.

Friday, April 20, 2007

First!

Hi, this will be my new devlog, just to track projects I'm working on and collect thoughts on them and so forth. First up, PixelRPG! This is a little side project I've been working on amidst school projects and some other miscellaneous things. Currently it's looking like it's got a shot at being a reasonable game, so I'm actively looking for input on good traditional RPG gameplay, combined with more modern concepts like a full paperdoll for inventory and complex character/world development.

As of right now, the game consists of a rudimentary GUI written in C++ with SDL, using the default SDL blitter (although I've set the foundations for a GL renderer, but that'll take a while). The world of PixelRPG is a big one; the map is an image 2400x1800 wide (by default, the game supports maps up to 4096x4096). Each pixel on this map is translated into a cell 800x800 pixels wide, composed of 10x10 tiles, each of which is 80x80. If that's not enough numbers, i'll put it into simple terms: at 2 tiles per second (about average walking speed) it will take you 26.67 hours to walk across the map. I believe this is pretty representative of a large enough world. The big trouble in dealing with a map of this size is making it feel like enough work went into every area. Each 10x10 cell of tiles is randomly populated with tiles (using the tile's world position as a seed in order to make sure the tile will always use the same graphic) from a tileset determined by the pixel color of the main map. This means a ton of pixel work, but hopefully will end up with a very personalized world. The end goal is for the generator to recognize cell transitions and use tiles designed for borders appropriately, as well as randomly inserting neighboring cell types into the border to create an uneven transition area.

In addition to the random elements of the map, statics can be positioned anywhere using a cell-relative position (that is, using the cells of the main map to position elements relative to). Buffering for these objects will be managed by a static loader that loads statics within a certain cell range -- this will ensure that thousands of statics across the world won't bog down the system unnecessarily.

Currently the project is in need of sprite artists and good ideas, apply at my blog e-mail: ERASEMErwarho1@gmail.comNOSPAM (eliminate the capitals, I'd rather my e-mail not get scraped).