15 Nov 2008

When you buy Intel, you get what you pay for

After all that drama with trying to get cheap laptops on specials, it's time to return them! At least most of the ones I'm returning are unopened, so they can resell them ‘as new’.

Okay, okay, the one I got from Noel Leeming (HP Pavilion dv6914tx), that was my bad, for not checking out on the Core 2 Duo specifications on the CPU first. That CPU (T5750) was listed in the table, as one that doesn't support hardware virtualisation.

But I also took advantage of a couple of other specials too (HP Pavilion “Influx” SE dv6819tx, and Sony VAIO VGN-NS15G), and their CPUs (T5850 and T5800 respectively) aren't even listed! How could I know whether a CPU supports hardware virtualisation if it isn't listed?!

Now, reading up on the web revealed that I could replace the CPU (the HP manuals go into great lengths to explain how to accomplish this, so it's obviously a supported procedure), but the only comparable CPU currently available, a T7500, will cost me $400 to get, which would completely negate the savings I made from the specials, and put me back to square one.

In comparison, my current laptop (which I got for even cheaper), a Compaq Presario F573AU (with an Athlon X2 TK-53 processor, i.e., not even a Turion), is the dinkiest laptop of all the ones we have at home; it also happens to be the only one that supports hardware virtualisation (being the only laptop here with AMD instead of Intel).

So, that's why AMD rocks, and Intel can eat a donkey or something. :-)

13 Nov 2008

A short little appeal to programmers

Please, please, please, before you check in your changes, make sure you've updated your working copy and merged in changes made by other developers first! Enough said. :-)

On online auctioning and people's strategies

I've used online auction sites a little, mostly to buy stuff, but soon we'll have stuff to sell, so I've been doing more thinking about it. More specifically, how to set the reserve price, relative to how much we actually want to get out of the item.

See, my philosophy is this. The reserve price should be slightly lower than the price you want, to hook people in (or, for a really popular item, set the reserve to $1, and let the fun begin), then watch the price skyrocket. Well, that's the idea anyway.


One of the things I enjoy doing at eBay is something called bid sniping. Within a few seconds of the sale closing, you place a bid higher than the last bid, and hope to win the bid that way. The thing is, though, for a really popular item, others will also be bid sniping too, so you have to be sure to go above their snipe bid (if you want the item enough). It's this counter-sniping that helps drive the price up, and increases the excitement level for everyone involved. To me, bid sniping is one of the main attractions of online auctions.

TradeMe has this option called auto-extend that sellers can use. The idea behind auto-extend is that if a bid is placed within two minutes of the closing time, then the auction is extended for another two. Of course, this completely kills bid sniping (and the resulting excitement), so I will not be using that for any of my sales.

I should explain why I brought up the excitement factor. To me, the risk is part of the online auctioning experience, and why I even bid at all. I actively avoid bidding in sales that don't allow bid sniping. For that reason, by not using auto-extend in my sales, I am betting that it will result in more bidders, and thus a higher sale price in the end.


I have a few things to say about reserve prices and Buy Now prices too. I have seen some people set their reserve price at the Buy Now price. This is completely stupid: if a buyer actually will meet the reserve price, they may as well Buy Now, and not bid at all.

My preference is to set the Buy Now price at, say, twice the value of the reserve price (well, unless I'm using a $1 reserve price, in which case it'll just be a price well above what I expect the final bid to fetch). It's a way to have ‘sure money’ from someone who wants the item enough to pay the price for it, without wanting to risk the chance of being outbid.

In other words, if I use Buy Now at all, I set it at a price that I don't ever realistically expect someone to pay. Say I'm selling my current (one-year-old) laptop, and I want to sell it for about $750. My Buy Now price would be $1000, and my reserve would be about $500.

Some people seem to have this fear of using a low reserve price, as if that will be the final price they will have to sell their item at. I say, if your item is in high demand, you have nothing to fear. And if it's not in high demand, don't sell it via auction.

There, I'll get off the soapbox now. :-P

12 Nov 2008

Little Eats

I just realised that I forgot to blog today, and that I have about 10 minutes left to do so (11.48 pm at the time of writing this), so I thought I'd rant about something quick.

Those of you who live in New Zealand, what do you think of Wattie's Big Eat brand? I understand that Big Eat is marketed, and supposed to appeal, to the more blokey types (what with the tagline Cordon Bloke), but I don't know. I don't consider myself any sort of a bloke, but still I seem to find that their meals are not very…big at all. So I'm kinda stumped here, as to what the point of Big Eat is.

In other news, The Ferret and I went to eat rice noodles at a Vietnamese place today. Now that's what I call a big eat! :-D

10 Nov 2008

Noel Leeming has the most useless call centre ever

Remember the drama I had with Noel Leeming? I thought it couldn't get worse. I was wrong.

So, you remember how 10 days ago, I called the call centre, and they said they found a unit in Christchurch, and that they would courier it to my home? Well, I got a call today, from the Christchurch store in question, saying that the laptop has arrived at their store and is ready for me to pick up.

I appreciated hearing from the lady at the store—it's a nice change from the idiots at the call centre—but I regretfully explained to her that I don't live in Christchurch, and that there's no way I can go there to pick the laptop up. I also explained to her that the call centre has stuffed up yet again. She said she'd follow up with the call centre.

Anyway, 10 minutes later, I got a call from the call centre (for the first time ever!). The guy on the line said he was calling because there was “conflicting notes” on my order and that was why the item got sent to the wrong place, and he wanted to confirm that I was wanting to have it couriered to my home.

Now, I've dealt with him before; he was the one who ‘accidentally’ disengaged my call. So I was disinclined to be kind to him. I asked him just what conflicting notes were on the order, and he mumbled something about how the order said something about shipping it to a store for pickup, but now it's to be couriered. Yes, originally I did request for it to be sent to a store (in North Shore, not Christchurch, mind), but because they've stuffed up and delayed my order so much, the least they could do is send it directly to me instead.

Anyway, he said he could arrange to get it couriered this afternoon, and I asked if, on account of their multiple stuff-ups, they could arrange for it to be urgent-couriered. They couldn't, and said the ETA would be in a couple of days' time.

I'd had enough at that point. I asked, in my usual steely voice :-P, if I needed to speak to his supervisor. He was like, no, escalations have to be done in writing. Oh, I see. Well, then, they'd better expect something ‘nice’ in their letterbox soon.

To end the call, I said to him that I hope that the item will indeed arrive at the correct place, in the stated time; I wouldn't like to have to call again. (There's that glint in my voice that hinted at something very unpleasant should that happen.) By this point, he sounded scared shitless, and just stammered, “Of course not; all right, goodbye,” and couldn't hang up the phone soon enough.

Now, just so you know, I don't especially delight in making customer service people squirm, and had he been someone I hadn't dealt with before, I'd have been far kinder. But, some people just deserve what they get. *shakes head*

On Nikki Kaye's recent victory

I never thought I'd write this post; I mean, between my interests in relationships, programming, and left-wing politics (and that's just the topics I've touched so far in my blog; I'm sure I'll cover my other interests soon enough), surely they'll give me enough to talk about. But no, what with the recent National victory in New Zealand, especially in Auckland Central (which is still getting a lot of media coverage), I figured I'd chip in with a word or two.

Today, while taking The Ferret to the dentist to have her wisdom tooth pulled out and sitting in the waiting room, I saw a big half-page article in the Herald about none other than our favourite Auckland Central MP. I'm very happy for her that she's so much in the limelight; yes, I'm envious. (More on this later.)

You see, I've known Nikki for a couple of years, but we haven't crossed paths for more than 10 years now; and yet after all these years, I still remember what a great friend she was, and I'd find it difficult to imagine anybody who knew her who would say otherwise. I strongly believe that her personable and memorable nature is, and will continue to be, a key ingredient of her success.

10+ years is a long time for anybody to change, and we probably wouldn't recognise each other on the street now, but if she's anything like the person I knew then, then I know Auckland Central is in very good hands.

So, on that note, as someone who knew Nikki and has only good things to say: Nikki, I want to congratulate you on winning Auckland Central; I knew, long before the election, you would succeed where nobody else could. And I mean this as high praise, coming as I do as someone with no love of National's aims or values. But then again, I believe your success was of your own making, and not in any way due to your party allegiance. I have every confidence that you will pave an even greater path of success in the next three years. Keep up the good work!

9 Nov 2008

In JIT we trust

I remember a debate with a colleague five years ago about the merits of dynamic compilation versus static compilation. He was arguing that .NET was ‘better’ than Java because .NET had an ngen utility for AOT native code generation. Of course, he favoured straight C++ even more because it was unmanaged; he felt that the management in managed systems just slowed things down.

I disagreed strongly with him at the time, citing the capabilities of the JIT compiler in Java at the time (it was at 1.4 back in those days, if I remember right; right about the time when there was that big fight between log4j versus java.util.logging). Well, of course, it's improved a lot since then, and I'm especially happy with the capabilities of Java 6 in the performance department!

John Rose (the mastermind behind the Da Vinci Machine project) has a page detailing all the various optimisations currently in place in Hotspot; there are sure to be even more optimisations for dynamic code invocation to come up.


On a related topic, I was perusing the OpenJDK 6 code today, and I learnt about a really cool technique they use in reflection (yes, I'm aware that the technique was implemented even in the 1.4 days, but OpenJDK code is easier to obtain, so that's what I'm looking at). Now, assuming that you, the reader, are not an expert in Java's core library implementation, how would you go about implementing reflection? Have a think about it, then read on (if you want to).

If you've played with JNI at all, I would presume you'd probably be thinking of that. Just write a native method that simply calls the JNI's builtin reflection functionality (or some shortcut thereto in the JVM). This, indeed, does work, and is one way that OpenJDK 6 does it.

It has a much cooler technique, though, called “inflation”. Inflation means that for the first few runs (default 15) of a reflected method/constructor (from now on, any reference to methods applies to constructors too), it does so via JNI; the next time after that, it assembles a class file on the fly, and loads it. At that point, full JITting applies, and further calls to that reflected method has the same performance as directly calling that method.

You can even disable inflation completely (set the sun.reflect.noInflation property to true), in which case the JNI approach is skipped completely, and all reflected method calls are assembled to class files straight away. Alternatively, you can tune the number of runs before the assembly occurs (use the sun.reflect.inflationThreshold property).

If that's not cool, I don't know what is!

8 Nov 2008

A big loss for the left, but hopefully not a victory for the (far) right

Well, New Zealanders have spoken. Not entirely in the way I wanted; I was hoping for a Labour-Green coalition, obviously, but, on the upside, the Greens have two more MPs in the House (even though the polls said they would get six more)! That is, indeed, a victory for the Greens.

With a National government coming up, the interesting part will be to see whom they'll make a coalition with. With Roger Douglas back in parliament, I'm not sure that an alliance with Act will make a very centrist government, but the Maori Party looks pretty strong too; I would be hoping for National to make an offer to them, instead of (or at least in addition to) Act. We'll see.

Winston Peters has lost his seat in parliament, after 30 years. Perhaps not surprising after all the recent dramas surrounding him, but still a shock.

More of a shock, though, is that Helen Clark has announced her resignation as the leader of the Labour Party. Very courageous, I think, and it definitely marks the end of an era. I hope the next leader of Labour will rebuild Labour to a new glory in three years (or whenever)!

Well, here's to a more centrist next three years in New Zealand! With John Key in the lead, I have some confidence this is well within reach.

7 Nov 2008

Do something good—get out of bed and get down to the polls before you start drinking!

It's coming up to midnight here, so I won't risk violating electoral advertising laws by advocating any party this time. :-P No matter what, do something good tomorrow, and be sure to vote!

I hate Noel Leeming, and kids who have no restraint

So, let's start with the kids. Two days after Guy Fawkes Day, the kids are still trying to burn their fireworks like there's no tomorrow. Well, maybe in some cases, if they're incautious, there will indeed be no tomorrow for them!

Right, now for the meat of the post. I totally, absolutely loathe Noel Leeming. I've ordered a laptop from them a whole fortnight ago, and they've managed to balls up my order in perhaps the most spectacular way imaginable.

I placed my order via their website on Friday morning, just at the start of their Labour Day online sale. I knew that it was a clearance product, so the earlier I ordered it, the more likely I'd get it soon. The only branch with units available for immediate pickup was Botany Downs, which was about an hour's drive from home, so I opted to have it delivered to the Wairau Park branch instead. I was told to expect to hear from Wairau Park in about 3 days, when the item would be ready for me to pick up.

Three days came and went. No news. I went to the store to ask about it on Tuesday, and was told by an impatient floor person that they received nothing, because it was a long weekend, and that I will hear from them when it arrives. Clearly, they didn't want to be bothered about it. All right, I thought, let's give them the benefit of the doubt, just in case it was a 3 business day delay.


Well, was I wrong. On Friday, I happened to be at the Lynnmall branch of Noel Leeming, so I took the opportunity to enquire about my order. The store person looked at the details, and said, the item should be available by now—Wairau Park had 7 in stock! So, I called them up and asked what was going on, as I waited a whole week and was sick of waiting.

The person at Wairau Park advised me that those 7 units were not actually for retail sale, but were instead reserved for a corporate order, and that the call centre people (who were in charge of Internet ordering) had stuffed up by listing that branch as a supply branch, when in fact they had no supply. He also said that he would get in touch with the call centre and have them contact me about whether I could pick up a unit from the Manukau branch, that was supposed to have one available.

(For non-Aucklanders: I live in the North Shore, and the Wairau Park branch is one of the closest to home. Botany Downs, Lynnmall, and Manukau are all ‘south of the bridge’, quite far from home, so we try to avoid unnecessary travelling.)

I asked for the call centre to call me back as soon as possible, because we didn't want to get stuck on the city side of the bridge without good reason. Well, most of an hour passed, we heard nothing, and so we went home, disappointed.


Irate, I decided to call up the call centre myself the next day. The first call I made, I got hung up on; the second call I made, the guy on the line expressed his sympathy, and arranged to have a unit delivered from a South Island branch (which I was told to expect by the end of the week). I said, emphatically, that I had waited more a whole week for the laptop, and that I would like it if they could provide me some compensation for the run-around I'd been given all along. I hinted that a spare laptop battery wouldn't be bad for them to throw in.

The call centre guy said, no, they don't do that, but they could provide a refund. And I was like, well, I bought the laptop during the Labour Weekend sale, and if I knew it was going to take that long to get here, I would have taken my fine money elsewhere, so really, because of this lost opportunity, they should refund me the pre-sale price, or offer a store credit with equivalent value.

And he was like, nope, sorry, the most we can offer is an apology, but perhaps you could write a complaint to customer services about this. (As a matter of fact, once I get calm enough to write a professional letter of complaint, I'll just use this post as the basic substance, so consider this the first draft. :-P)

Anyway, I was still expecting the laptop “by the end of the week”. Guess what? It's now Friday evening, and I still have received neither a call, nor a package at my door. This is really shocking, and inexcusable; it's been two whole weeks since I ordered, and never once have they ever called me. I had to be the one to do all the pushing. I dare say that this is the most shocking customer service I have ever encountered in my 20 years of living in New Zealand, topping even Telecom. Think about that.

What's the bet that, if the laptop arrives at all, it was a display unit, and already halfway broken from the rigours of ‘unsupervised test drives’. That would really take the cake, as far as raising my blood pressure beyond whatever notional savings I got from the sale could cover.

6 Nov 2008

On romanticism

Recently, I got into a disagreement with a correspondent because they didn't like the idea that a relationship is like a business transaction, and I stated that that was the honest truth. I still stand by that statement.

Now, the reader could be forgiven for wondering how a romantic cupid like me could get away stating with such supposed heresy. The idea of having to negotiate everything in a relationship, as though you're negotiating your working conditions, appears so unromantic on the surface, so much so that many couples dodge such topics as pre-nuptial agreements (when, in my opinion, they shouldn't). So, what sort of cupid advocates that kind of exchange?!

Well, this one does.

I call myself a cupid because seeing people in a happy relationship makes me happy. The operative word here is happy. To me, it's not enough that a couple appear superficially to be happy; I'm too much of an idealist for that. A relationship is a happy one, in my view, when both parties are getting what they need from it.


See, I hate fairy tales. Perhaps that had something to do with the my upbringing, that I was never exposed to any of them; my mother was a very matter-of-fact person, never really about doing any make-believe things. For example, Christmas was for giving gifts, not having a fluffy figure descend upon non-existent chimneys (chimneys in apartments? surely you jest) to magically deliver your reward "for being good". In my upbringing, there were other "rewards" for being good, such as not getting yelled at. :-P

Anyway, back to fairy tales. The Ferret tells me that fairy tales are evil because they instil into little children this idea of happy-ever-after relationships that magically appear, and these stories never talk about the maintenance and upkeep that go into making and keeping a beautiful relationship that way. It's the biggest crock of bullshit ever.

The Ferret and I have a happy relationship, not because we're "lucky", but because we know from watching other relationships what mistakes and traps we must avoid (and a purpose of this blog is to discuss these), and we work hard to do the right things (ditto). One of the things we do do (which is no doo-doo :-P) is regularly discuss what we need, and work out ways we can fulfil each other's needs.


Really, I think the reason many non-negotiated relationships fail is because many of them are on totally different pages about what each party wants and expects of their partner. Nobody is psychic in a relationship! (The Ferret is psychic, but that's a different story.) If there's something you need in a relationship, especially things that you can't budge on, make sure it's sorted out before you commit. Seriously.

There's nothing romantic about all the these gorgeous five children you've dreamt about for the last 20 years, only to find that you're in love with someone who hates kids and would leave if you actually seriously brought up the topic of kids.

Just don't go there. Please, for the love of cupid.

Important things have to be discussed. Even if you both agree on the number of kids to have, I'm sure there are lots of other things to disagree on, such as what to name them, how to raise them and discipline them, what aspirations you have for them (lawyer? hacker? hooker?), just to name a small handful of items.

And that's just about children. What about what styles you prefer in bed, and how frequently? Which way to you put the toilet seat after use? How compatible are your spending habits? What about the Big Forbidden Topics, politics and religion?


Anyway, I've rambled on enough for now, but I just want to leave a parting thought: romance seldom comes by magic, or luck, or whatever. Most of the time, it takes hard work. Identifying and honestly discussing your needs, and having your partner do the same, is a large component of that hard work. (Being able to listen to honest feedback with sincerity is arguably just as big.)

The reward here is that, once you do complete these discussions, and realise that the person you're with does fulfil your needs, and vice versa, then, you're well on your way to having that successful, life-changing romance. That would make this cupid very, very happy.

5 Nov 2008

On idealistic hope

This is a special post; I suspended my normal topic schedule, just to celebrate a very great event today.

I say this because, in the US, Barack Obama won the presidential election. Of course, he was the candidate I was backing, however, that's not what my post is directly celebrating, but instead:

  1. That there has been a greater turnout to this election than ever before, and
  2. That old-style politics can be laid to rest, clearing the way for a much more constructive style.

I think the speeches from both John McCain and Barack Obama were very touching, for different reasons. I applaud McCain's grace in conceding the presidency; the crowds were booing audibly, but he firmly told them no, we're all Americans, we must all work together for the good of our country. This is a very different line from that taken during a large part of the campaign, and I really do appreciate that.

Obama's speech is about a call to action; that the election is not the change, but just the enabler of the change that everybody must contribute to, and make sacrifices for. It's also a pledge of support to all Americans, be they Obama supporters or otherwise. It's about unity, despite differences. It's tear-inducing material. :-)

I hope, in seeing all the US election coverage here in New Zealand (and everywhere else in the world, but I emphasise NZ because we have a national election coming up in just a couple of days), that there will be more voters here coming out to vote, and that they will vote with their conscience, for the things they believe in, and not just because the media circus managed to make more dirt stick to one party than another.

As a Greens supporter (and maybe soon-to-be member), I would of course hope that more young voters would come and vote; Jeanette Fitzsimons mentioned that when she was campaigning at Auckland University, there was such a great level of support from the students that if their votes were representative of the country, then the Greens would be the clear major party, and all the other parties would become minor parties. :-P Well, it's not that way across the board, but I still hope for a 10%+ party vote for the Greens!

So if you're a New Zealander, be sure to vote! I'd prefer if you voted Greens, however, if you're not a Green supporter, that's fine, as long as you vote. :-)

4 Nov 2008

On food additives

What is with all the things commercial food producers put into food these days? The Ferret and I were shopping today for a cottage pie, and pretty much all the ones contain MSG (621) or similar related flavour enhancers (627 and 631 are the main culprits). So we ended up getting none of them.

The same comments apply to such things as potato chips, instant noodles, etc. Yes, I know some people say that healthy people don't eat such things, so people who eat them are unhealthy and therefore shouldn't care about flavour enhancers. I disagree with that stance, but even so, the use of flavour enhancers has crept into supposedly-wholesome foods too, such as the shepherd's pie I just mentioned, as well as many varieties of supermarket roast chickens, just to name a couple of examples.

Just in case people think this sort of stuff applies to savoury foods only, think again. A lot of desserts I see contain aspartame (951) and/or other artificial sweeteners (950, much of the time). Now, I can understand products made for diabetics and the like, who must watch their sugar intake. However, most of the artificially-sweetened items I see actually contain sugar too, in which case, why the artificial sweeteners?!

The Ferret and I can both taste MSG and aspartame when they've been added to food, and the aftertaste isn't particularly pleasant; furthermore, she is sensitive to these substances, which will give her headaches. So, we avoid any food items that contain them.

But really, why?! Do these additives actually make food that much more saleable? And in that case, why are they less saleable in the first place?

2 Nov 2008

Just another MLP post :-)

Still lots of coding to do today, so I thought I'd pass on another small handful of recent-event items. :-)

  1. If you live in the Auckland area, the Sky Tower will be orange between now and election day, as a commemoration. Take advantage of this once-in-three-years opportunity with your favourite camera!
  2. If you're as big a fan of the Brandenburg Concertos as I am, you might be interested in a sale currently on for an ASMF rendition of the series (1, 2, 3, 4, 5, 6)!
  3. If you're a programmer, may I recommend the Stack Overflow podcast series. I've been too busy to listen to the whole series yet, but I'm currently up to #15, and the dialogue between Joel and Jeff often have me in fits of laughter! The Stack Overflow site itself is pretty neat too, though apt to be addictive; currently I'm going through a somewhat-involuntary recovery, simply due to my workload. :-P

1 Nov 2008

Two public service announcements

At the moment I'm very busy and can't scrape together enough time to write a full blog post (yesterday's one took me 4 hours(!) to write), so I'll instead post a couple of current-event items:

  1. If you're a Green Party supporter (and in my opinion, if you aren't already one, you should certainly consider it), you can make your own Vote for us billboards! There's one that I found that's just as poignant as the original billboard.

    And, if you submit your creation to the Green Party Facebook page by Monday, you're in a draw to win a Greens t-shirt! (6 entries as of this writing, so your chances aren't too bad either.)

  2. WCPE is celebrating its 30th birthday this year! If you love classical music as much as I do, you should definitely tune in. For the values-conscious who choose to use patent-free media formats, WCPE has an Ogg Vorbis stream (in addition to MP3 and other formats); in fact, that's how I found them in the first place, as Vorbis.com linked to them.

On beauty (and related ideas and ideals)

So, I wanna know: what does beauty mean to you? Whom do you consider beautiful, and what do you find beautiful about them?

There's that often-heard saying, beauty is in the eye of the beholder. True enough. Let's set yourself up as the beholder, for the moment. Do you consider yourself beautiful? Why, or why not?


In many ways, I begrudge mainstream society for instilling a narrow view of beauty on everyone, but especially on the young and vulnerable, pushing a standard of beauty that very few can attain, but that many have learnt to lust after. Although the specifics are hard to pin down, I'd still say that looking at pictures of models, mainstream musicians, and Hollywood stars would still provide a fair idea of what I'm talking about.

Perhaps I'm barking up the wrong tree, though. It's easy to argue that in those fields, such standards of beauty are indeed maintained because they have mass appeal, and thus allow for mass promotion. Who am I to argue with products that are designed for mass marketing?

However, we, as individual persons, are not (I hope) supposed to be mass marketed. When we deal with individuals, and especially ourselves, we should carefully maintain a wider view of what constitutes beauty, beyond what we've been taught via mass media. History has been full of examples of society trying to mould everyone into the fashions of the day; ultimately we end up with lots of square pegs being rammed forcefully into lots of round holes, complete with lots of collateral damage in between.


I've had to learn this the hard way. For most of my teenage years, I had not considered myself beautiful; after all, I came into contact with people my own age everyday who were more (conventionally) beautiful and popular. I mention popularity for a reason, too; I feel that popular people, to some extent, mould the notion of beauty being applied by the community in question.

Now, I was completely opposite to that. I was (and still am) a hardcore introvert, and thus not only was I not popular, I also did not have relationships with popular people (from a teenage perspective, this is obvious: being associated with a less-popular person risks diminishing the status of the more-popular one). Really, then, I had no way to be around beautiful people, as far as beauty is meant in the mainstream sense.

At the end of my teenage years, I looked in the mirror one day, studied my face in detail, and saw a glimpse of what I would today consider beautiful. And I said to myself, if I couldn't find anyone beautiful to be with, I'd better make myself beautiful. It was the only kind of beauty I could be sure of.


Making myself beautiful was hard work. I would look in the mirror everyday, seeing how far from the (mainstream) ideal of beauty I was, and feel despondent. I went through a stage where I tried out all kinds of clothes, hair, makeup, and whatever else I could think of, to see how I would come out; I needed to know what worked best for me. In that process, I stopped worrying about how the ever-mystical others had to say or think. I had to, or else I wouldn't have had the courage to discover what I needed to.

At the end of it, five years later in my mid-twenties, I became a different person, and that was something other people noticed too. I was surer of myself, of what I believed in, and in particular what I believed of myself and my notion of beauty. I'd realised that all along I was a beautiful person, but that until that moment, the understanding of beauty was lost to me, awaiting discovery.

That was a major revelation to me, and it helped me feel a lot better about my self-image. But even more importantly, I'd learnt to see beauty in others that I had never in the past been aware enough to see. This is the sort of beauty you seldom see in mass media, but is the sort that enriches your life for good. It helps us see each other as individual persons, each beautiful in his/her/hir own way, and not as just another mass-produced item.


So, at the end of this rather long post, what I've been trying to say is this: I think it's important to understand a notion of beauty beyond what mass media and popular people portray; not only does it provide a stronger sense of self-worth (as far as seeing oneself as beautiful is concerned), but it helps us see people around us as whole individuals, not as just another face to be compared to the latest weekly.

Your mileage may vary, but I hope this post resonates with you more rather than less.

Administrative interlude

I've just signed up for NaBloPoMo for this month. Let's see if I find something to say for every day of November!

I've also picked out a new template, Sand Dollar. It's hard to find a good template on Blogger that uses the full width of the page, so it's nice when I see one. I did tweak some numbers so the sidebar makes more room for the content. (The original template uses 31/66 ≈ 1:2 ratio; my tweaks uses a 24/74 ≈ 1:3 ratio.)

Right! Onward with today's actual post! (I must say, after spending lots of time with my latest addiction, Stack Overflow, I've grown rather fond of Markdown, and would love nothing more than for Blogger to support it!)

14 Oct 2008

More about interfaces than you can throw a HissyFitException at

This post is in response to Mike Stone's Please Hold on the Interfaces.

I believe in judicious use of interfaces. Sometimes it's warranted, such as when it represents concepts that lend themselves to multiple unrelated implementations (e.g., Runnable or Callable).

This is doubly useful in, say, (pre-3.0) GNU C++, where you can cast references of any type to a given interface (or signature as G++ calls it) as long as all members of the interface are implemented. It's much, much more flexible than interfaces as seen in Java or C# (where you have to declare upfront in the implementing class that it's in fact implementing some interface).

Where all implementations are likely to have common functionality, having an abstract class is more sensible, in my opinion. Sometimes (such as in the Java collections framework), having both is sensible, too.


Interfaces do use vtables (in fact all interface method invocations are virtual), so whoever says using interfaces is faster because it avoids virtual calls has never profiled their code before, and worse, has no concept of how high-level source code translates to low-level object code. (Yes, I just downvoted their answer.)

I never see a reason to avoid virtual functions when polymorphism is warranted. Seasoned C++ programmers will tell you that what slows your program down with using virtual functions isn't the indirect function call, but the diminished opportunity for inlining.

However, with a managed platform like Java or .NET, the JIT can easily inline for the common case (profile-guided optimisation for the win!), and deoptimise when the common case is no longer the common case. (For lurkers and archives, what I mean is that if a virtual method is being called mostly through instances of one specific concrete class, that concrete implementation can be inlined into the JITted code until other concrete classes start being used more frequently—in which case the code is re-JITted appropriately.)

In contrast, programmers who think they know where their program's bottlenecks are, without profiling for the common cases, are performing ignorance-guided optimisation.


I don't agree with the "call protected virtual initialisation method from constructor" approach though. Remember that in the superclass constructor, the subclass portion of the object isn't constructed yet, and any such virtual methods you call had better make sure that they only access the superclass portion of the object.

In C++, this is enforced—this is a feature, not a bug. Virtual functions do not exhibit virtual behaviour when called (directly or indirectly) from constructors and destructors. I have some code to demonstrate this:


#include <iostream>

class Base {
public:
    Base() {hw();}
    virtual ~Base() {gw();}

    virtual void println(char const* line) = 0;
    void hw() {println("Hello, world!");}
    void gw() {println("Goodbye, world!");}
};

class Derived : public Base {
public:
    Derived() {}
    virtual ~Derived() {}

    virtual void println(char const* line) {
        std::cout << line << '\n';
    }
};

int
main()
{
    Derived d;
    return 0;
}

Here, even though we're instantiating a Derived object, where the println function is defined, while inside the Base constructor (and destructor) Derived::println is not being used at all.

If the constructor/destructor calls println directly, that will generate a compiler error (since a pure virtual function is being called). In this indirect case, the compilation will go fine, but because Base's vtable is used until execution reaches Derived's constructor, the println() call inside hw() will not work as (naively) expected.

Like I said, this is a feature, not a bug. While the price you pay is that you cannot use virtual behaviour inside constructors and destructors, this actually makes your program safer, by not requiring your virtual functions to be specially coded to only use members in the base class.

So, back to the use of a "protected virtual method" to allow mockable initialisation. The proper way to do this, in my view, is to make an initialize() method, that is called by client code after the object is constructed. Since initialize() isn't being called by the constructor, it means that the object is fully constructed, and that it's safe to call into the appropriate virtual method to do the appropriate type of database initialisation (or whatever).

28 May 2008

Lists and Lists: tail recursive fun

So, who's played Andrew Plotkin's Lists and Lists? It's a Scheme tutorial, and it's written in Inform, a language used to author interactive fiction.

What I find cool is that, despite (intentionally) being written for a platform not designed to host a programming language interpreter, Lists and Lists is exactly that—a very flexible interpreter, that allows you to write whatever program you like to solve its challenges. It simply verifies your programs according to the problem criteria, and you are not required to solve the problems ‘any particular way’.

Lists and Lists also has sample solutions, if you type help enough times for a given problem. These sample solutions are designed to be easy for beginners to understand, but are not necessarily optimised for any other criterion. So, variety being the spice of life and all, I've decided to post my answers to some of the questions. (I'm currently learning Scheme, so these are by no means any sort of ‘optimal’.)

My particular aim with my answers is that they should be tail recursive, so that when given a very large list to process, the programs don't use up huge amounts of stack.

In standard Scheme, the ‘named let’ syntax makes tail-recursive programs quite readable; sadly, this functionality is not available in Lists and Lists, so I also present my solution in both ‘formats’. Additionally, for extra functional-programming goodness, I present SRFI 1 versions where available.

(Sorry about the funny line wrapping; I wanted to help the two-column format display correctly on a variety of screen widths. I used Emacs to do the indentation, so hopefully the result is readable.)

  1. Define sum to be a function that adds up a list of integers. So (sum '(8 2 3)) should return 13. Make sure it works correctly for the empty list; (sum nil) should return 0.

    My approach here is: Why rewrite the + function when you can reuse it? Or, why take the high road when you can take the cheap road? :-P

    Standard SchemeLists and Lists
    (define (sum l)
      (apply + l))
    
    (define sum 
      (lambda (l)
        (eval (cons + l))))
    

    Okay, if I must actually write an iterative solution (if only so that we have something to compare the next problem against):

    SRFI 1Standard SchemeLists and Lists
    (define (sum l)
      (reduce + 0 l))
    
    (define (sum l)
      (let next ((sum 0) (tail l))
        (if (null? tail) sum
            (next (+ sum (car tail))
                  (cdr tail)))))
    
    (define sum
      (lambda (l)
        (letrec
            ((next 
              (lambda (sum tail)
                (cond
                 ((null? tail) sum)
                 (t (next (+ sum (car tail))
                          (cdr tail)))))))
          (next 0 l))))
    

    Yes, I quite deliberately reused the symbol sum, just to demonstrate that I'm not using sum to recurse. You can't, anyway, if you want a tail-recursive solution.

  2. This problem is like the last one, but more general. Define megasum to add up an arbitrarily nested list of integers. That is, (megasum '((8) 5 (2 () (9 1) 3))) should return 28.

    This solution is similar to the last one, but I'm not assuming that tail is a list, and more specifically, I only do the adding when I'm not dealing with a list. When I encounter a list, I just recurse; this catches cases where (car tail) is a list.

    SRFI 1Standard SchemeLists and Lists
    (define (megasum l)
      (let mega+ ((elem l) (sum 0))
        (cond
         ((null? elem) sum)
         ((list? elem) (fold mega+ sum elem))
         (else (+ elem sum)))))
    
    (define (megasum l)
      (let next ((sum 0) (tail l))
        (cond
         ((null? tail) sum)
         ((list? tail) 
          (next (next sum (car tail))
                (cdr tail)))
         (else (+ sum tail)))))
    
    (define megasum 
      (lambda (l)
        (letrec
            ((next 
              (lambda (sum tail)
                (cond
                 ((null? tail) sum)
                 ((list? tail) 
                  (next (next sum (car tail))
                        (cdr tail)))
                 (t (+ sum tail))))))
          (next 0 l))))
    
  3. Define max to be a function that finds the maximum of a list of integers. So (max '(5 14 -3)) should return 14. You can assume the list will have at least one term.

    My solution uses a pairmax helper function that simply returns the maximum between any two quantities.

    SRFI 1Standard SchemeLists and Lists
    (define (max l)
      (define (pairmax a b)
        (if (> a b) a b))
      (reduce pairmax #f l))
    
    (define (max l)
      (define (pairmax a b)
        (if (> a b) a b))
      (let next 
          ((best (car l)) (tail (cdr l)))
        (if (null? tail) best
            (next (pairmax best (car tail))
                  (cdr tail)))))
    
    (define max 
      (lambda (l)
        (letrec
            ((pairmax 
              (lambda (a b)
                (cond
                 ((> a b) a)
                 (t b))))
             (next 
              (lambda (best tail)
                (cond
                 ((null? tail) best)
                 (t (next (pairmax best (car tail))
                          (cdr tail)))))))
          (next (car l) (cdr l)))))
    

    You'll notice a pattern here, that there is a fairly mechanical way I'm translating from the original program to the Lists and Lists-compatible version. In fact, when tested with Guile, its macro expander actually expanded the named-let blocks on the left into something quite similar to the letrec blocks on the right.

    (Of course, in this problem, since Lists and Lists does not support internal define, the equivalent letrec is used instead.)

  4. Last problem. You're going to define a function called pocket. This function should take one argument. Now pay attention here: pocket does two different things, depending on the argument. If you give it nil as the argument, it should simply return 8. But if you give pocket any integer as an argument, it should return a new pocket function—a function just like pocket, but with that new integer hidden inside, replacing the 8.

    >>(pocket nil)
    8
    >>(pocket 12)
    [function]
    >>(define newpocket (pocket 12))
    [function]
    >>(newpocket nil)
    12
    >>(define thirdpocket (newpocket 3))
    [function]
    >>(thirdpocket nil)
    3
    >>(newpocket nil)
    12
    >>(pocket nil)
    8
    

    Note that when you create a new pocket function, previously-existing functions should keep working.

    My solution is pretty much the same as Lists and Lists' sample solution (just how many ways can you solve this one?!), just using a named let.

    Standard SchemeLists and Lists
    (define pocket
      (let construct ((num 8))
        (lambda (x)
          (if (null? x) num (construct x)))))
    
    (define pocket 
      (letrec
          ((construct 
            (lambda (num)
              (lambda (x)
                (cond
                 ((null? x) num)
                 ((construct x)))))))
        (construct 8)))
    

So, there you go. Feel free to comment with any corrections, improved answers, or whatever ideas you have. :-)

Job programming puzzles

Lately, I've been taking to job programming puzzles, to help my brain atrophy a bit less. :-P There are a couple of ones I've looked at so far: Justin.tv, and Weebly. I found both of these companies through the Hacker News job board. I look forward to doing more puzzles as I come across them. I'll probably store all my answers, and just submit them when my Green Card arrives and I can start applying for some of these jobs.

The Weebly one is easy. I solved that one in 15 minutes (and could have done it somewhat faster if not for a couple of false starts). In so saying, I didn't have to write any JavaScript code at all, I just used standard Unix tools, so perhaps that's cheating (as far as timing goes—I could have done using only client-side JavaScript code, but it would have taken me a little longer). :-P


The Justin.tv one is more challenging. I had some code from my OMGWTF 2007 submission that handled operator precedence (yes, my calculator was written to behave like a scientific calculator, and even provided buttons for parentheses so you could override the precedence), but I wanted to do it ‘the right way’, so I read up Wikipedia on parsing. I ended up using the shunting yard algorithm to do this (if you aren't familiar with this algorithm, I'd advise you to learn it from Dijkstra's paper, rather than from the Wikipedia article).

The extra-credit reduction option I implemented in a fairly conservative way, that does not reorder the values, nor change the evaluation order (even when such reordering would provide a correct final result). It does squash consecutive applications of the same operator into one function call (such that it would work as expected in Scheme), and it does so knowing that addition and multiplication are associative.

My implementation is written in Perl, by the way (and I use operator overloading on the S-expression class so that printing nested S-expressions requires very little code). It's written in a functional style, allowing easy translation to Ruby once I know the language better. And as an extension, it supports the exponentiation operator, **, which has higher precedence than * and /, and the output could even be fed to Scheme (with SRFI-1 support) if you had this function defined:

(define (** . args)
  (reduce-right expt 1 args))

Here is the test set I used (the first five are from the Justin.tv website, and the last four involve negative numbers, which are outside the spec, so change them appropriately if your implementation can't deal with negative numbers):

3
1 + 1
2 * 5 + 1
2 * ( 5 + 1 )
3 * x + ( 9 + y ) / 4
a + b + c + d
a + b + ( c + d )
a + ( b + c ) + d
a + ( b + c + d )
w - x - y - z
w - x - ( y - z )
w - ( x - y ) - z
w - ( x - y - z )
-1 + 0 - 1 * 2 * 3 - 4 - 5
-1 + 0 - 1 * 2 * 3 - 4 - 5 / 6 / 7 - 8 + 9
-1 + ( 0 - 1 * 2 * 3 - 4 - 5 / 6 - 7 / 8 ) + 9
-1 + ( 0 - 1 * 2 * 3 - 4 - 5 / 6 + 7 / 8 ) + 9

Results, without reduction:

3
(+ 1 1)
(+ (* 2 5) 1)
(* 2 (+ 5 1))
(+ (* 3 x) (/ (+ 9 y) 4))
(+ (+ (+ a b) c) d)
(+ (+ a b) (+ c d))
(+ (+ a (+ b c)) d)
(+ a (+ (+ b c) d))
(- (- (- w x) y) z)
(- (- w x) (- y z))
(- (- w (- x y)) z)
(- w (- (- x y) z))
(- (- (- (+ -1 0) (* (* 1 2) 3)) 4) 5)
(+ (- (- (- (- (+ -1 0) (* (* 1 2) 3)) 4) (/ (/ 5 6) 7)) 8) 9)
(+ (+ -1 (- (- (- (- 0 (* (* 1 2) 3)) 4) (/ 5 6)) (/ 7 8))) 9)
(+ (+ -1 (+ (- (- (- 0 (* (* 1 2) 3)) 4) (/ 5 6)) (/ 7 8))) 9)

Results, with reduction:

3
(+ 1 1)
(+ (* 2 5) 1)
(* 2 (+ 5 1))
(+ (* 3 x) (/ (+ 9 y) 4))
(+ a b c d)
(+ a b c d)
(+ a b c d)
(+ a b c d)
(- w x y z)
(- w x (- y z))
(- w (- x y) z)
(- w (- x y z))
(- (+ -1 0) (* 1 2 3) 4 5)
(+ (- (+ -1 0) (* 1 2 3) 4 (/ 5 6 7) 8) 9)
(+ -1 (- 0 (* 1 2 3) 4 (/ 5 6) (/ 7 8)) 9)
(+ -1 (- 0 (* 1 2 3) 4 (/ 5 6)) (/ 7 8) 9)