Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Friday, July 08, 2005

I spent (wasted?) some time trying to make a satisfactory revision of the program I wrote a year ago to play song samples from CDUniverse. It took me far longer than expected, but it's done with some degree of decency. I'm disappointed that I didn't follow a test-driven approach, because even though the program is trivial, I can easily see myself wanting to extend it in the future, and maybe even use it as part of my other not-so-secret project. The problem with tests here is that it would involve interaction with WMP, and it seems to me that actually writing tests would be far harder than the code I've already got. For instance, the code to test whether "Play Songs" really does play songs strikes me as being rather nasty - I don't see an elegant way of doing it. That dreary technical note aside, my first stab ended up with something like this:



I was quite happy with this, but it only worked with CDUniverse, which was the original intent. The problem with this is of course that CDUniverse's repository of sound clips is hardly complete, in fact the AllMusicGuide database seems to have much more. I thought it would be easy to allow one to choose to use AMG, but in fact I came across something unexpected - now that AMG requires registration for access to most of its content, the program was shot, because merely copying the URL from my browser would lead to a innocuous enough page where the links to the sound clips were blank! (The way the program works is quite primitive - one has to actually navigate to the sample page via a browser, and then paste the URL into the program. The program isn't sophisticated enough to just get an album name and then determine the URL automatically - that, of course, has been left as a job for my other project) This morning, I chose the tried and true method of the cop-out, where I decided that for AMG, one would have to copy the source as an HTML file stored on the client's hard-drive, and then use that as the "URL". Messy, no?! Of course, it works, but I am disappointed that I haven't been able to come up with an unified interface for these two providers. I'd imagine that the music catalogue program would solve these problems because of the generality of the data you feed it, but still, I'd like for this stand-alone program to be cleanly designed too. At the very least, of course, I managed to implement a simple MVC pattern here, which was something painfully missing from the previous incarnation of my catalogue program.

As for where this fits in with the catalogue program, it should be fairly obvious - the idea is that one should be able to retrieve album information and play sample clips from the catalogue program. The problem I foresee is providing a nice way to give the user the choice of getting the samples from AMG or CDUniverse (or some other provider). I'm fairly confident that AMG has samples for most clips, but there are a few (from memory) where AMG doesn't even have a review, let alone clips. And, of course, the bigger problem is this whole registration business, and quite frankly I am at a loss as to how I can solve this problem. Ah, but I probably won't work on this for a while now, because my goal now is to try to use C# to make a revised version of something else I've worked on a lot - Tetris! I can't count the number of times I've started and stopped with this game, but darn it, this time I've got to be serious about finishing it and making sure it has no bugs!

I actually used the program as an excuse to try out the beta of Visual Studio .Net 2005 (the C# express edition, to be precise). My impressions so far have been quite favourable, indeed it seems to be at an almost equal footing with Eclipse in my eyes. The IntelliSense functionality seems to be vastly improved, and I feel that Eclipse would do well to add autocompletion at least after new statements. VS.Net also keeps local variables in the autocomplete list, and remembers your last selection, which I find very useful - it saves a lot of typing, especially when doing many Console.WriteLines!



I was going to say (before I realized how ludicrous the idea is) that the one little thing that annoys me is that double-clicking on a control (such as a textbox) automatically causes the editor to create an OnClick event, and take you to the code screen. Of course, this behaviour is a perceived benefit to users, but I wish there were a way for me to change the default behaviour to be merely editing the "most common" property - f'rinstance the Text property of a textbox. As I write this, and as I begin to comprehend how stupid and unfeasible this sounds, and wonder how on earth I come up with such thoughts.

I see that in this beta, C# supports generics, which is a welcome change; indeed, I thought they would have included it in the first standard, after seeing Java's approach. Indeed, with delegates in the mix, C# allows for statements much in the vein of STL algorithms, such as songs.ForEach (delegate (Song s) { Console.WriteLine (s.Name) }) - the fact that the delegate is anonymous is very convenient! Anonymous functions/functors are definitely something I'd like in C++ - speaking of changes to C++, Stroustrup has written an article detailing the design of C++0x. He admits that C++ as it stands can be a bit intimidating for novices, and seems to want to correct that to some extent. It sounds like one of the motivations behind Java - hiding the complexity of C++ so that programmers and non-programmers alike can write code at a reasonable level of abstraction, but I don't think we're going to see C++ morph slowly into Java*. Stroustrup has said many times that Java's goals are vastly different to that of C++, and that even if he could make C++ without maintaining backwards-compatibility with C, Java is not the language he would have come up with. Some of the tweaks he introduces in the document would be quite welcome. For instance, the vector initializer list. Boost of course provides the assign library that tries to do something similar, and my knowledgeable tutor tried to make a container that supported such initialization through a cunning use of the comma operator, so the desire for such a feature is clearly present.

* But are all languages morphing into Lisp? Again, I wish I would stop procrastinating and just learn the darn language already, so that I can make up my own mind instead of relying on other people's speculations.

Friday, April 22, 2005

Another post intended for the future-me, but I don't mind at all if you read it, gentle reader! Yet it is long, and ultimately but an expression of happiness at having found some joy with programming, for the first time in a long time!

The latest assignment for software has provided an excellent opportunity to try out test-driven development. I started off well enough, writing a decent (if excessively verbose) set of tests. A little background on the project - it is meant to be an implementation of a mathematical set. Fairly interesting, and it seems reasonably doable to boot. I learnt an important lesson, and that's that it's good to design your test suite too! I had the impression that I could get away with hacking it together, but aside from the fact that it's "good practice" to have clean design, there are the obvious benefits that come with clean code; primarily among them, reduced repetition and updating.

I could have been fancy and used std::map to help automate the tests completely, but I decided that it would be simpler and quicker to just hand code the tests and the desired output. It seemed easy enough, so I rushed in and made a few tests for equality and subset testing. It all worked, and I was happy. However, there were a few problems; chief among them was that I was having to initialize the set like so:


int elements [] = { 0, 1, 2, 3, 4 };
IntSet set (elements, 5);


As you can see, I was forcing myself to manually specify the length of the array. This could be overcome by using the sizeof (elements) / sizeof (elements [0]) trick, but it still didn't seem "right". Since arrays are evil, I thought there must be an elegant way to do it with a vector instead. No luck, because a vector can be initialized "as-is" with an array: so,


IntSet set (std::vector <int> ({ 0, 1, 2, 3, 4 }));


doesn't compile.

It dawned on me that an easier way would be to read in data from a file, as then I could read directly into a vector and then everything would be automated, and I wouldn't have to specify array lengths and muddy up the code. But I plodded on anyway, with the (very dangerous) thought that it would be too much effort to change. This is usually a very bad mistake to make! There are too many places to name where this very style of thinking is rejected completely, but reading and rationalizing is never quite enough for me. It took me a few hours to see that I was digging myself into a hole, because there seemed to be no end to the amount of repetition in the code. The turning point was when I had made a mistake in one of the statements which led to an obscure bug with one of the tests. Much toil and sweat later, I decided it was time to refactor.

So, last evening, I spent a good hour or so trying to get the tests to be read in from a file. In the process, I realized that this allowed me to be far more flexible with my tests - it became trivial to add new tests, and maintaining them was again a piece of cake. Previously, I was comparing each set to the very first set in the test method; I thought then I would code up separate tests for separate first sets. Terrible idea! With a test file, it took a few minutes to make the code able to read in a pair of sets, and perform the needed comparison. All of a sudden, the tests became much more robust! But I'm jumping ahead of myself, because there was another interesting problem to tackle - how could there be a generic method that worked for all the operator comparisons? I needed the code to work for equality (==), less than equals (<=), and so on - the basic idea was the same, but a different operator needed to be invoked in each case. "Pity you can't pass in an operator", I said to myself, before suddenly remembering the documents I'd read on SGI's STL reference about functors. I was overjoyed, because thanks to std::equal_to and friends, I could effectively pass in an operator as a functor! At this point, I recalled the older days of programming, the unbridled joy to be found when discovering something new. Here, I was realizing how something I'd seen so many times before could be of practical use and massively reduce the work needed.

I was quite satisfied with the progress made, and so I was prepared to move on and test more operators. Again, I came across a design flaw that I should have paid more attention to at the start - all my code was built under the assumption that the return type of the operators being tested was a boolean. When it came to set unions and what have you, the code had no chance of working. You'd think by now I'd learnt the art of patient design, but I was on a roll, and thought to myself "This can't be too hard to fix". Bold words! I quickly wrote up something that would work where the result was another set. It all seemed to compile, and I thought by now that I must be done.

But this time I decided not to let repetition go unnoticed; the code was full of it now, since the method for a boolean comparison and a set comparison were nearly identical, except for a few lines. Essentially, there are two things that are different. First, that we must read in the data from the file differently - namely, we should make sure that we read into a set, not to a boolean. Secondly, we should invoke the appropriate comparisons. Similar behaviour, yet different types..ring a bell?

Templates! I'd used them before, but not very seriously, definitely not with anything of any practical use. So it was rough going at first, trying to make it work. It seemed first that I needed a template of templates: sounds nasty, but it isn't really. Essentially, I needed to make sure that the invoked function could be called either for a pair of sets and a bool, or for a pair of sets and a set. "Seems easy enough", I said, and tried to do this in a few minutes. But I came across a brick wall - since we can't overload based on return types, my code didn't know which function to invoke in order to read the test data. I had originally given them the names getBoolData () and getSetData () (not very informative names, I know), and I obviously needed some way of making them have the same name if I were to invoke a different one based on type. However, the prototype for both methods was identical, except for the different return type, so the compiler couldn't decide which one to choose.

At this point I thought to myself "Let's look at what's different with these two functions". They were virtually identical, except that they have different ways of converting the result of the test-operation (equality would convert it to bool, since the result of equality is a bool). Common functionality everywhere else, so I was pleased with myself and thought "Easy enough, let's move the conversion code outside and merge both methods together". Sounds good, but I ran across the same problem - the comparison code was also being overloaded based on type! So again, the compiler was at odds to choose the right function.

Faced with the bleak prospect of giving in to mindless repetition, I flipped through Stroustrup's book, hoping to find some clues to help me. I came across template specialization, and it struck me that it could be useful - define a generic conversion function like template <class T> convert (const string &);. Then define specializations for bool and IntSet. It seemed easy enough to code, but I was skeptical as to whether this would work. But it did! The now generic getData () function was able to call convert <T>, and the appropriate type was filled in at compile time! Very nice!

Once this was done, the code looked much neater. It worked seamlessly for comparisons returning either booleans or sets, and there was no further redundant updating required. All this effort just for a test mechanism, yes, but it was a valuable learning experience. And, to boot, I can save myself the future worry of a buggy program, thanks to an automated suite!

One might be tempted to say that the proof really lies in the final mark, but I disagree. I found this to be a very valuable learning experience, and that, I think, is what matters more, even if it's very easy to be led otherwise.

There are probably lots of errors in the code fragments, most of them are off the top of my head.

Saturday, July 24, 2004

I think God's in the details. Why? Because I think if you look close enough at anything, you are bound to be amazed at what you find. I have this tendency to experience momentary drop-outs in my connection with reality (no surprise, eh?), after which, for a few seconds, I just stand still in awe of the nature of this world. I mean, everything about this existence is fascinating. But at the same time, the very energy (for lack of a better word) that causes this fascination also causes me to frequently wonder why. I suppose the two are interlinked; I am both fascinated and repulsed at the idea that right now I am sitting in my room, punching away at these keys that make words appear on the screen. Words that are going to be read by you, my imaginary audience, who cannot prove that they really exist. It's amazing to think that man has gone from living in caves and hunting everyday for survival to this life of comfort (and superficiality, it must be said). Geez, I mean, think about it, clear your mind and think about it. That part amazes me, but for some reason, abstracting away the whole mechanism of existence (which I suppose translates to just over-simplifying it?) makes me wonder what it's all for. They say people spend their whole lives searching for meaning. I think that's possibly the most focussed goal I have ever set for myself, and the only goal that has lasted all these years - to find out just what this crazy world's all about.

And now let's tie that in with programming. I sometimes wonder about programming and whether it's what I really want to do. The passion is still there, but, me being the obsessive maniac that I am, I often think about programming and its place in the rest of the world. Can I look back at my life and be happy with what I've done? What mark have I left if I become a programmer? I suppose if one became the best-darn programmer there ever was, that's sort of leaving a mark on the world, but I am driven by a search for something more, something greater. Usually people advise that by having a family that loves and cares for you, and children to carry on the torch as it were, that's enough of a legacy. But it should come as no surprise that that doesn't satisfy me. I am unfortunately completely ego-centric, I do treat the world as though it revolves around me, and sometimes I wonder "Well, why not?". Armed with recurring thoughts of solipsism, I often think that the universe does indeed revolve around me (never totally seriously, but still, I believe this is indicative of full-blown dementia). No, I feel as though my mark ought to be directly related to me, as though I want people to chant my name for all eternity.

The fact that this is not going to happen only serves to upset me at times; not times like this, for now I am in a wonderfully mellow mood, contrary to whatever tone may be implied by my writings. Does it all have a meaning? I'd sure love to know. I only hope that I never lose the urge to find out what it all means, because for me, it's a powerful driving force, although sometimes it gets in the way of me living a proper life (whatever that is).

Friday, June 04, 2004

I am ready to dive into Python (witty, witty), thanks to my shameless abuse of the university's print quota. Actually, it's hardly an abuse since they offer us a 1000 pages to print out whatever we want. But nonetheless, the act of printing out a whole book seems a bit excessive, and hence wasteful. Yet of course a book is worth far more than a tutorial sheet (let's see what I say to this come exam time - oh wait, it is exam time). Now I have no excuse not to read it - it's printed and just waiting to be read. Chances are of course that it will stay that way till the end of the year. Such is life.

But anyway, I wish I could print out The Structure And Interpretation Of Computer Programs. Also known as the bible of Scheme, and the greatest computer science textbook of the last 20 years. I can't quite explain my fascination with these sorts of books that are revered as being brilliant texts in the way of programming itself - the book, from what I've read, tries to use Scheme to push the reader onto the path of becoming a good computer scientist, not just a good Scheme programmer. Which is of course what we need today, texts that teach you more than syntax, that go beyond the details of a language and look at the high level issues that are arguably much more important.

A digression - are all Scheme programmers good? Or more generally, are all functional programmers good? Probably not, but they seem to be such an exclusive group that I'll wager that most of those who do program in such languages are really good. Just read some of the newsgroups on Lisp, those guys are crazy! After all, one must be reasonably motivated to choose such an obscure language paradigm - obscure in the modern day business sense. How many job offerings for Lisp programmers have you seen lately, hmm?

So is this all an attempt to apply the flawed logic of "If I were a Scheme programmer, I would be a good programmer"? Quite possibly, but I would like to think that I am trying to elevate my knowledge and understanding and become one, without the naive assumption that by merely learning Scheme I will magically transform. That ain't so bad, now is it?

On a related note, three volumes of The Art Of Computer Programming lie in a bookshelf in my house, never read once. Glanced at, yes, but never read. I wonder if I will ever be able to comprehend a whole chapter of this intriguing bible of computer science (everything seems to be a bible today). Knuth reminds me how little I truly know, both in mathematics and computer science. Is that a good thing?

Oh, why can't I print the book out, you ask? Because the chapters (and pages?) are individual HTML files, and the book is not available as a convenient PDF. It is available in printed form for US $75. A bit expensive, wouldn't you say?