Symphonious

Living in a state of accord.

Ant Dependencies Running Twice

Most people believe that ant will only ever execute a target once per execution of ant. So if we have targets A, B, C and D, where A depends on B and C and C and D both depend on D.

<target name="A" dependencies="B, C"/>
<target name="B" dependencies="D"/>
<target name="C" dependencies="D"/>
<target name="D"/>

 

When we run ‘ant A’, we expect each task to execute once, D first, then B  and C, ending with A. Since there is no dependency between B and C, they may execute in any order, so we might also get D, C, B, A. All pretty straight forward.

Similarly, if we run ‘ant B’ we expect (and get) D then B and ‘ant C’ gives D then C. Most people expect that if you run ‘ant B C’, the execution path would be D, B, C but that’s not what happens. Instead we get D, B, D, C. Each target passed to the command line creates a new dependency chain and runs all targets in that chain.

The other case that catches people out is when using antcall. The antcall task actually sets up essentially a new execution of ant (by default inheriting any properties that have already been set). It never inherits the dependency chain or list of targets that have already been executed. So if our targets were:

<target name="A">
<antcall target="B"/>
<antcall target="C"/>
</target>
<target name="B" dependencies="D"/>
<target name="C" dependencies="D"/>
<target name="D"/>

Then the execution order for ‘ant A’ would be A,D,B,D,C.

The cost of running targets twice is reduced because most ant tasks do nothing if their inputs haven’t changed (so javac only compiles files once), but for a large project there can still be a significant cost in checking over all the files to determine if anything needs to be done. So whenever possible, use actual dependencies to build up a chain of targets instead of antcall or specifying multiple targets on the command line.

 

 

Doctypes, Compatibility Modes, Charsets and Fonts

This information is all covered in much more detail elsewhere on the web but for my own future reference, here’s a primer on doctypes, compatibility modes, charsets and fonts which was required to explain why certain Chinese characters weren’t showing up in IE8. Of course the best answer is that you need to have the East Asian Font pack installed and then it just works (usually) but this tends to be useful background and saves “server side” folks from a number of gotchas.

Doctypes and Compatibility Modes

  • IE 7 and above has an insane array of compatibility modes which are out to get you. The most common gotcha is that it will use compatibility mode (emulating IE7) if the website is in the “intranet zone”. There’s an option to disable this somewhere in the preferences dialogs.  You wind up in the intranet zone if you’re accessing a site via any domain name that doesn’t look like a real one (e.g. http://dog/ is in the intranet zone).
  • If you can avoid falling into compatibility mode, any pages including the DOCTYPE as <!DOCTYPE html> or <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> will render in standards compliant mode (where the world is as sane as it gets in web development). Go with the shorter version unless you have a reason not to.
  • http://hsivonen.iki.fi/doctype/ is the gold standard for information about browser modes.

Character Sets and Fonts

  • If you’re tracking down problems with foreign languages there are two major categories of problems – encoding corruption (where characters come out garbled or as ?) and missing glyphs in fonts (where characters come out as little boxes).
  • Corruption is fixed by specifying the same character encoding everywhere. It is a security issue if any webpage is missing a meta tag defining the character set (smallest variant is <meta charset="UTF-8">). It must be the first tag in the <head> of the document.
  • Little square boxes mean that either the font currently in use doesn’t have a glyph for that particular character and the font fallback routine was unable to find any font on the system which supports that character. 
  • Browsers have a default stylesheet which is automatically applied to every page which commonly sets a specific font-family and font-size for text input elements, so adding the style body { font-family: 'Arial Unicode MS' } may get some Asian characters working in the main content but not in text boxes unless you also add input { font-family: inherit; }.

The security issue mentioned above is that any page which doesn’t define a character set but includes any form of user supplied content is vulnerable to a cross site scripting injection attack – even if the user supplied content is escaped properly, because the content may include a character that causes the browser to incorrectly switch to UCS-7 or other weird character sets and drastically change the meaning of the content on the page (hence the user content is no longer correctly escaped). There have been steps taken by modern browsers to remove this risk (including removing support for UCS-7 I believe) but its good practice to specify your charset explicitly anyway.

Media Release or Bug Report?

Ah Apple maps, ever the source of a good sensationalist headline. This time the Victorian police have warned people not to use Apple Maps to get to Mildura. This is definitely a bug with Apple maps, no question it should be and has been fixed.  What’s interesting though is that the Victorian police thought it would be easier to attempt to notify every iOS 6 user about the problem via the media and get them to use an alternate mapping application than it would be to call Apple and get them to fix the source data.

Users complaining publicly instead of being constructive and reporting the problem to the manufacturer certainly isn’t new, but in the age of web services its more self-defeating than ever.  Apple can fix the problem in one place and its fixed for every user, surely the Victorian police have a better way of getting in touch with Apple than through the media?

And lets not even start asking why anyone would blindly follow GPS directions into the Australia bush despite the fact that they are looking at a satellite photo that clearly shows there isn’t a town there.

The power of user feedback and cloud hosted data was very clear with my recent experience of using Apple maps – on the way to my destination was some road works which diverted the road and replaced a round about with a set of lights. Despite the fact that the roadworks were actually still in progress, Apple maps gave exactly correct instructions for the new layout. Meanwhile my TomTom GPS will still think there’s a round about there for up to another year and then require me to pay nearly $100 to get the updated maps. It wasn’t too long ago that I’d be looking up a book of maps to get my outdated driving instructions (and then have to memorise it or stop regularly to have another look).

Makes you realise what an incredible time we live in.

Brawling on a Plane

From Straights Times:

A flier aboard Sunday’s Swiss airline flight – a 57-year-old Chinese man [...] felt disturbed during his meal when the passenger in front of him reclined his chair.[...]

“The older of the two felt disturbed during his dinner. When the younger did not respond to his protests, he hit him on the head with the flat of his hand. It was a real slap,” said the guide, Ms Valerie Sprenger.

A fight then broke out between the two men, who rolled in the plane’s aisle. A crew member and a well-muscled passenger restrained the aggressor, bound his hands and placed him at the back of the plane, where he shouted for an hour, the newspaper said.

I can sympathise. In fact I’d have probably tied up the douchebag who put his seat back during meal service.

Demystifying Doubles: Consistent Inaccuracy

Of all the data types, double is probably one of the most misunderstood. A huge amount of folk lore has been built up around it to help protect developers from falling into its many pitfalls.  Lately I’ve done a lot of work replacing usage of BigDecimal with double and learnt a lot about where those pitfalls are and how the folk lore can be misleading.

The great challenge with double is that it has a degree of inaccuracy because of the way the number is actually stored.  For example, the number 2983792734924.2293 actually winds up being stored as 2983792734924.2295, a tiny difference but with far reaching consequences. All of the folk lore around doubles is designed to deal with this potential for inaccuracy.

One piece of folk lore is that you should never do a strict comparison of double values (e.g. with == or !=).  Due to the inaccuracy of doubles you should always compare them with a level of tolerance:

abs(doubleA - doubleB) < tolerance

It’s important to realise however, that this inaccuracy isn’t random, it’s perfectly consistent and predictable.  The number 2983792734924.2293 always comes out as 2983792734924.2295.  The same applies if you parse it from a string: parseDouble(“2983792734924.2293″) always comes out as 2983792734924.2295.  As a result the following are consistently true:

2983792734924.2293 == 2983792734924.2293
parseDouble("2983792734924.2293") == 2983792734924.2293
parseDouble("2983792734924.2293") == parseDouble("2983792734924.2293")

Introducing tolerance to the comparison can lead to subtle bugs. For example, if we were updating our model with user input we might have something like:

// In our model:
public void setAmount(double amount) {
  this.amount = amount;
  fireChangeEvent();
}
// In our UI code:
model.setAmount(parseDouble(widget.getText()));

So far so good, but what if we want to avoid firing the change event if the value hadn’t really changed?  We might change the model code to:

public void setAmount(double amount) {
  if (abs(amount - this.amount) > 0.01) {
    this.amount = amount;
    fireChangeEvent();
  }
}

 It follows the double folk lore, but also introduces a bug. Let’s say the user first enters the amount ’1′.  Then they change the amount to ’1.001′.  The second amount is within the tolerance so it’s not considered an actual change. The user is now looking at a text field that says 1.0001, but the model thinks the value is still 1.   You can make the tolerance smaller but that just means the user has to enter more zeros to trigger the problem.

The right answer is to take advantage of the fact that inaccuracy with doubles is consistent and do the comparison using strict comparison:

public void setAmount(double amount) {
  if (about != this.amount) {
    this.amount = amount;
    fireChangeEvent();
  }
}

So when doesn’t this work? When the two values are calculated in different ways. So:

(1491896367462.1147 * 29.837927349242293) / 2.3982983923
= 18561116318075.207
1491896367462.1147 * (29.837927349242293 / 2.3982983923)
= 18561116318075.203

The only difference between the two equations is the order of evaluation – they should give the same answer, but because doubles have a degree of inaccuracy the intermediate result is rounded to something that will fit in a double, so the order of evaluation matters because it affects what rounding is done to the intermediate result. Repeating the exact same calculation will always give the exact same result, but if there’s any chance that the values were calculated in different ways, comparisons must be done with tolerance.

So the folk lore about needing to compare doubles with some tolerance is perfectly valid, good advice, but be aware that it introduces its own inaccuracy which may cause problems. You should consider what the impact of falsely deciding that the values are different vs falsely deciding that the values are the same; which side should you err on?

Sometimes you really do want a strict comparison, even between doubles.