16.04.10

More SpiderMonkey changes: ancient, esoteric, very rarely used syntax for creating getters and setters is being removed

tl;dr

We’ve removed support for a handful of obsolete getter/setter syntaxes in SpiderMonkey and Mozilla. This does not include { get property() { return "value"; }, set property(v) { } }, which is widely used and which is part of the latest standard. If you don’t get any syntax errors with your code, you don’t need to worry about this. If you do, skip to the end for details on how to adjust your code to cope. But really, you should read it all for the sheer joy of learning about all sorts of awful syntax you didn’t even know existed before it went away. [Or at least empathize with us liberated SpiderMonkey hackers. :-D])

Properties in JavaScript and ECMAScript 3

The fundamental data structure in JavaScript is the object: a container mapping names to values through properties. You can add, remove, or change the value associated with any property, so long as the property may be modified. All user-defined properties are infinitely modifiable in any of these ways; only a few properties defined by ECMAScript (the standard on which JavaScript is based) are not fully modifiable.

var obj1 = {};
obj.property = 17; // add
var obj2 = { property: 42 }; // add from birth
obj2.property = 17; // change it
delete obj2.property; // remove it

Properties which store values are useful, but what if you want properties which can do things when you interact with them? What if you want to have properties which map strings to lazily-computed values? Or what if you want setting a property to have side effects (as, for example, setting an array’s length to 0 removes all elements in it)?

Properties with getters and setters in JavaScript

If you want properties which have functionality beyond just holding a value, you need getters and setters, stored within accessor properties. (Properties which hold values are called data properties.) JavaScript has long included extensions to ECMAScript to create accessor properties, both syntactic:

var o1 =
  {
    get property() { print("gotten!"); return "get"; },
    set property(v) { print("sotten!  " + v); }
  };
var v1 = o1.property; // prints "gotten!", v1 === "get"
o1.property = "new"; // prints "sotten!  new"

…and programmatic:

var o2 = {};
o2.__defineGetter__("property", function() { print("gotten!"); return "get"; });
o2.__defineSetter__("property", function(v) { print("sotten!  " + v); });
var v2 = o2.property; // prints "gotten!", v2 === "get"
o2.property = "new"; // prints "sotten!  new"

Getters and setters are now part of ES5. The syntax demonstrated above is valid ES5; a different API, Object.defineProperty, provides more flexible support for specifying getters and setters dynamically. Developers using the old-school APIs should begin updating to use the new API as browsers make new releases supporting it. Firefox in particular will include support for Object.defineProperty in its next major release, likely to occur in the latter half of the year.

Examining antediluvian accessor syntax

Unbeknownst to the vast majority of web developers, extension developers, and even Mozilla developers, in the past JavaScript has included other getter and setter syntaxes.

Named ES5-like getters and setters

If you look up the function that acts as the getter given ES5-standard getter syntax, what’s the name of that function?

var o = { get property() { return "get"; } };
print(Object.getOwnPropertyDescriptor(o, "property").get.name);

There are a couple plausible answers here: “anonymous“, “property” (the property name), or “” (the empty string) might be reasonable. JavaScript and ES5 arbitrarily create the getter or setter as a function whose name is the empty string. What if you wanted to name that function? (Bear with me for a moment and pretend this is a compelling need, and that adding a named getter or setter programmatically is absolutely unacceptable.)

Solely by accident of implementation, in the past SpiderMonkey has parsed the following syntax to assign names to getter and setter functions:

var o = { get property getter() { return "get"; } };
// Prints "Name: getter" in past versions of SpiderMonkey (or would if
// Object.getOwnPropertyDescriptor existed; __lookupGetter__ is a
// simple workaround); previous line is syntax error elsewhere
print("Name: " + Object.getOwnPropertyDescriptor(o, "property").get.name);

SpiderMonkey internally implemented the parsing of literal getters and setters by parsing them as though the start of a function expression had just been parsed:

// Faked-up parser state when parsing normal getters/setters
var o = { get property () { } };
                       ↑
function () { }
         ↑

Function expressions may be named or unnamed, but this wasn’t originally considered, so in the above example getter is treated as the name of the function created to correspond to the getter:

// Faked-up parser state when parsing named-getter-function syntax
var o = { get property getter() { } };
                       ↑
function getter() { }
         ↑

No other JS engine accepts this unintentional accessor-method name token.

Getters and setters in object literals

Possibly the best-known additional syntax is for specifying getters and setters in object literals. This syntax was the original Netscape invention for getters and setters; in practice it was superseded by the newer, more function-looking syntax. SpiderMonkey is again the only engine to implement it.

function g() { print("gotten!"); return "get"; }
var o1 =
  {
    property getter: g,
    property setter: function(v) { print("sotten!  " + v); }
  };
var v1 = o1.property; // prints "gotten!", v1 === "get"
o1.property = "new"; // prints "sotten!"

This accessor property syntax has one large advantage over the more-common syntax previously demonstrated (and even over the unintentional named-accessor mistake shown in the previous section). Where you see property in the object literal above, you could instead see a numeric literal, or a string literal — just as you might see either in any object literal without getters or setters, e.g. { 1: "value", "o": "hai" }. Historically, in get property() { ... }, property was required to be an identifier, thus excluding numbers and non-identifier accessor properties from representation. The syntax here had the further advantage of allowing serialization to “source” (more accurately, a reasonable but not always equivalent facsimile) of objects containing non-identifier-named accessor properties, through another Netscape extension in JavaScript.

This syntax also has a few disadvantages. Since the getter and setter contextual keywords follow the property name, the eye must scan past the property name to determine whether a portion of a literal represents a data property or an accessor property. This special-case check also complicates parsing, because now the parser has to check for something beyond just a colon at such locations. (To be sure, this problem exists with get foo() { }, but it’s restricted to the single leading token get, not to all leading tokens.) Since the value assigned to the getter is parsed as an arbitrary expression, there’s no guarantee the value must be a function — that must be checked at runtime.

Assigning getters and setters to properties

This accessor syntax provides the same functionality as Object.defineProperty(obj, propname, { get: fun, enumerable: true, configurable: true }) (mutatis mutandis for setters), except as part of the language syntax rather than as part of its standard library. Again, no other engine has implemented this syntax.

var o = {};
o.property getter = function() { print("gotten!"); return "get" };
o.property setter = function() { print("sotten!"); };
var v = o.property; // prints "gotten!", v === "get"
o.property = "new"; // prints "sotten!"

This syntax is also obscure: outside SpiderMonkey source and test files, only a single file in the Mozilla source code uses it. Strangely, a trawl through AMO shows half a dozen extensions have managed to discover this syntax, despite its near-complete disuse in Mozilla itself.

Assigning getters and setters to names rather than properties

Syntactically, this is just a different flavor of the previous example:

varname getter = function() { return "get"; };
var q = varname; // "get"

Semantically, however, it’s a rather different beast. The problem is that not all names are alike in SpiderMonkey. While ECMAScript specifies all name accesses in terms of objects (pure-JS objects in ES3, tighter spec-internal artifacts in ES5), most if not all JS engines out there optimize name access based on the type of the name. Local and enclosing variable access may be some number of pointer jumps, comparisons, and an offset, rather than some sort of hash table lookup in a more general case. Global variable access can in many circumstances skip lookups in enclosing scopes, going to the global object directly. (Last and certainly least, variable access inside with almost necessarily must be essentially unoptimized and dog-slow. Friends don’t let friends use with!) These sorts of optimizations rely on names always being plain old values, not accessors (except in the global case, where the type of optimizations implemented are qualitatively quite different). Slowing down local or enclosing variable accesses just to support this very rare case would be insane.

SpiderMonkey actually hasn’t supported this syntax for awhile. I only mention it because SpiderMonkey includes code specifically to exclude it. If this syntax is seen and varname can be resolved to a var, it’s a compile-time syntax error. Otherwise, if varname resolves to a var at runtime (possible in the presence of with or eval), it’s a runtime TypeError. Last, if it doesn’t, it “works” — and you are most likely Jesse, combining syntax and features in obscure and evil ways solely to make SpiderMonkey developers’ lives hard. 😉 In sufficiently old versions of Firefox where these restrictions weren’t in place, it’s entirely conceivable this syntax may have resulted in security vulnerabilities (one large factor in its removal from SpiderMonkey).

Prefixed function expressions

Perhaps the most bizarre getter/setter syntax is a modification of the syntax for function expressions and statements. As with all the others, this syntax has only been implemented by SpiderMonkey.

getter function foo() { return "foo getter"; };
var v = foo; // "foo getter"
var q = setter function bar(v) { };

When the prefixed function is a statement in the global scope, the syntax is equivalent to Object.defineProperty(globalObject, "foo", { get: function foo() { /* ... */ }, enumerable: true, configurable: true }) (mutatis mutandis for setter). If it’s a statement in a function scope or an expression that’s not a statement, the prefix serves no purpose that I can discern, except that it affects Function.prototype.toString()‘s behavior by including the prefix in the returned string.

None of these old getter/setter syntaxes provide value

Now that ES5 has codified The One True Syntax and The One True Programmatic API, these older syntaxes bring little to the table.

  • The mistaken ES5-like named accessor get property funname() { } syntax doesn’t satisfy a compelling need.
  • property getter: in object literals provides one compelling feature: the ability to have non-identifier-named properties. As ES5’s get property() { } syntax includes these further extensions beyond what engines have already implemented, this advantage no longer exists:
    var o =
      {
        get name() { return "names valid"; },
        set break() { this.x = "keywords too"; },
        set 1() { this.y = "numeric literals also accepted"; },
        get "custom string"() { return "arbitrary string literals too!"; }
      };
    

    (property getter: has a final advantage with respect to an ancient Netscape extension, but given that extension’s dubious future I will omit the details. Suffice it to say the use case is highly esoteric, and reasonably graceful degradation is possible without property getter:.)

  • getter = and getter function are fully subsumed by Object.defineProperty.
  • varname getter = was already gone.

In sum: these syntaxes make some things slightly easier, but they don’t provide anything you can’t do with ES5’s standardized accessor support.

These syntaxes were the source of numerous bugs

In addition to not being particularly useful, these syntaxes imposed notable costs on development. Supporting so many different getter and setter syntaxes isn’t easy, and the relevant code paths are quite complicated, attempting to decide when which syntax is correct and when not (particularly as far as object serialization is concerned). This has resulted in a multitude of accessor bugs usually found by Jesse‘s fuzz-testing and almost never by real-world scripts: bugs which, in C or C++, can often lead to memory-unsafety and, in the extreme, arbitrary code execution. By my count SpiderMonkey has sixteen separate tests (corresponding to the same number of bugs) dedicated to edge cases and corner behaviors with these syntaxes: syntaxes no one uses, syntaxes superseded by newer and better ones, and syntaxes which no other JS engine currently supports, nor ever will support.

These syntaxes continue to impose costs on development. Not all related bugs have been fixed, and changes to nearby code do have to take account of this syntax. We have had at least one long-standing (but believed “mostly harmless”, in that a sanity-check fails but surrounding defensive code completely contains the problem) bug involving this syntax, which due to its relative harmlessness has gone unfixed for nearly three years (and, almost as bad, undiscovered for two of them). Recent implementation work on ES5’s strict mode support required adjustments to the area of parsing object literals (for ES5’s strict mode rejection of duplicate property names), adjustments required to work around support for these syntaxes.

In short, TANSTAAFL. We’ve paid a large cost to keep these syntaxes around, and we continue to pay to keep them around — sometimes directly, sometimes indirectly, but unavoidably if support is worthwhile.

Support for all non-ES5 accessor syntaxes has been removed from SpiderMonkey

But for the many reasons previously given, support for these obsolete syntaxes is not worthwhile, so we have removed them from SpiderMonkey. get property funname() { } was an error from the start that no one will miss. SpiderMonkey has recently implemented support for ES5 numeric- and string-literal accessor property names (support for keyword names already exists), so the remaining important use case for property getter: has been eliminated. The getter = and getter function syntaxes never provided extra value, so they too have been removed without qualms.

To give an idea of the complexity eliminated by removing these syntaxes, the patch to remove them added 116 lines of code but removed 313 lines of code. Outside of code changes (that is, adjusting or removing tests which used these features), it added 133 lines but removed 1213 lines. It’s always great deleting code like this. 🙂

Updating existing code to adapt to these removals

One nice feature of removing syntax is that the failure mode when that syntax is encountered is blindingly obvious: the script will fail to parse. Parse errors show up in the JavaScript console, so it’s easy to tell when this is the problem; SpiderMonkey’s excellent error messages should point directly at the offending location.

If by chance you do actually use any of these syntaxes, the necessary fixes are simple. Suppose the existence of these helper functions:

function accessorDescriptor(field, fun)
{
  var desc = { enumerable: true, configurable: true };
  desc[field] = fun;
  return desc;
}

function defineGetter(obj, prop, get)
{
  if (Object.defineProperty)
    return Object.defineProperty(obj, prop, accessorDescriptor("get", get));
  if (Object.prototype.__defineGetter__)
    return obj.__defineGetter__(prop, get);

  throw new Error("browser does not support getters");
}

function defineSetter(obj, prop, set)
{
  if (Object.defineProperty)
    return Object.defineProperty(obj, prop, accessorDescriptor("set", set));
  if (Object.prototype.__defineSetter__)
    return obj.__defineSetter__(prop, set);

  throw new Error("browser does not support setters");
}

Here’s how you can update each old syntax to work again:

get property funname() { }
var o = defineGetter({}, "property", function funname() { });
property setter: fun
var o = defineSetter({}, "property", fun);
obj.prop getter = fun
defineGetter(obj, "prop", fun);
setter function prop() { } (when at global scope; otherwise just remove the setter prefix)
defineSetter(obj, "prop", fun);

You can experiment with a version of Firefox with support for these obsolete syntaxes removed by downloading a nightly from nightly.mozilla.org. (Don’t forget to use the profile manager if you want to keep the settings you use with your primary Firefox installation pristine.)

A brief word on __defineGetter__ and __defineSetter__

As you may have noticed, all examples here use Object.defineProperty in preference to either __defineGetter__ or __defineSetter__, using the latter two only as fallback when the former is absent. While many browsers support these methods, not all do. Object.defineProperty is the future, and it is the standard; Microsoft has even gone on the record to say that they will not implement __defineGetter__ or __defineSetter__ in IE given the existence of the standardized method (props to them for that choice, by the way). For greatest forward compatibility with all browsers, you should use Object.defineProperty if it exists, and only fall back to __define{G,S}etter__ if it does not.

In a distant future we would like to remove support for __defineGetter__ and __defineSetter__, after ES5 adoption has taken off, so as not to distract from the standardized support. The less new web developers have to know about legacy extensions superseded by standardized alternatives, the better. This action is at least several years in the future, likely longer; being able to make the change will require preparation and adjustment in anticipation of that time. Given upcoming releases of browsers supporting ES5 functionality, there’s no better time than the present to start gradually, and gracefully, adopting standardized methods over legacy alternatives.

07.04.10

Strange Fruit

(I first heard the song several months back, but the 95th anniversary of Billie Holiday‘s birthday today presented a convenient excuse to prerecord a post for now.)

Disturbing, depressing, haunting:

While it's certainly worthwhile to see Holiday herself singing Strange Fruit, I think I prefer the audio from the studio recording

Via the excellent Night Lights Jazz Program, at around 26:35 (make sure to check out their archives of weekly broadcasts dating back to 2004, some great stuff in the back-episodes I’ve enjoyed). The song later went on to be called the song of the century by Time magazine. According to the broadcast, when Billie Holiday performed Strange Fruit at the Café Society nightclub, it was as her last number of the night; its owner, Barney Josephson, couldn’t imagine her following it with anything else (quite understandably, I think). I’d never heard it before now, and while I can’t quite say I’m glad to have heard it, it was worth hearing. Anyway, something to think about.

(Apologies for disrupting your day if you find you can’t get the song or its topic out of your mind. For some reason, at least for me personally, it feels like historic treatment of racism in the South is rather more clinical and sparse than, say, treatment of the Holocaust during World War II, which is probably why I find the song and lyrics so disturbing — they’re fresh and novel. Emphasis is certainly important concerning history of this nature, but relentless repetition [if nowhere else, I think I got that with respect to Nazi Germany in my high school German classes] desensitizes one to emotional impact. It’s unfortunate we don’t treat topics such as these more carefully — neither excessively nor sparingly, and with the right amount of gravity and eloquence.)

06.04.10

More changes coming to SpiderMonkey: the magical __count__ property is being removed

Tags: , , , , , — Jeff @ 17:17

Meet __count__

SpiderMonkey for some time has included a little-known, little-publicized, and little-used property named __count__ on all objects. This property stored the count of the number of enumerable properties directly on the object. For example,

assertEqual({ 1: 1 }.__count__, 1);
assertEqual([].__count__, 0);
assertEqual([1].__count__, 1);
assertEqual([1, /* hole */, 2, 3].__count__, 3);

It’s sort of a convenient way to check property counts, avoiding a verbose for (var p in o) loop. For example, you could use it to determine how many mappings you had in a hash.

Unfortunately, __count__ has a number of problems.

What’s wrong with __count__

First, and most notably for web developers, __count__ is non-standard. To the best of my knowledge, no other JavaScript engine supports it. Developers must write scripts under the assumption it doesn’t exist, so it provides no brevity bonus. (I recognize extensions and Mozilla-based applications are a special case. For the further reasons below, it’s still worth removing even if some code could assume its existence.)

Second, the special __count__ property contributes to the problem that you can’t actually use an object as a string-value hash. The reason is that you have to be careful that your string-valued keys don’t conflict with special properties, because special properties can’t be overwritten with a custom property. This breaks the nicest feature of using objects for hashes: you can’t just use normal [] property access to set and retrieve mappings. If someone inserts a mapping of, say, "__count__""special", the association with "special" won’t be preserved; obj.__count__ = 5 is actually a no-op. (NB: Even ignoring __count__ other special properties prevent this from working, but we’re slowly working toward getting rid of them. [Some much more slowly than others, I hasten to note! You don’t need to worry about __proto__ being removed any time in the near future, although you should use Object.getPrototypeOf(obj) with a compatibility shim to determine obj‘s prototype in new code.]) A further wrinkle is that __count__ is implemented in such a way that an object literal with "__count__" as a named property functions differently from an object to which the property is later added by assignment:

var o = { __count__: 17 };
assertEqual(o.__count__, 17);

// ...but...
var o2 = {};
o2.__count__ = 17;
assertEqual(o2.__count__, 17); // fails: __count__ is 0

Third, in supporting __count__ we’ve incurred special-case deoptimization code in SpiderMonkey’s script-to-bytecode compiler. This extra complication, for a feature not often used, does nothing for code readability, complexity, or quality.

Fourth, __count__ doesn’t work the way you might think it works: it’s not uniformly fast for all objects. Property access generally has a syntactic assumption of constant-time speediness. This assumption isn’t valid in languages with getters and setters, but since it’s usually the case, it’s not a horribly inaccurate one. Thus, one might expect that evaluating obj.__count__ is an uncomplicated O(1) operation which doesn’t allocate memory and just looks up the size of an idealized hash table. It might be possible to make that true, but in fact it never has been true: generally, computing __count__ is O(n) in the number of properties on the object. Further, because __count__ reuses the same enumeration mechanism as for loops, it usually requires a memory allocation, which can be slow. __count__ has no asymptotic advantage over manual enumeration of the object’s properties.

In sum, __count__ has problems that mean it doesn’t give you much more than a for (var p in o) loop would. If that loop were placed in a function, it would be almost identical in code size to use of the property — and it would have the advantage of being completely cross-browser.

__count__ is being removed

We have removed support for __count__ from SpiderMonkey. As a consequence __count__ will also be removed from the next version of Firefox based on trunk Mozilla code. (And, of course, future versions of other Mozilla-based products like SeaMonkey will pick the change up when they produce releases based on trunk Mozilla code.) For the above reasons __count__ doesn’t make much sense to keep around, and it imposes real development costs. You should have no difficulty updating your code to implement alternative functionality to __count__. Here’s one example of how you might do this:

function count(o)
{
  var n = 0;
  for (var p in o)
    n += Object.prototype.hasOwnProperty.call(o, p);
  return n;
}

assertEqual(count({ 1: 1 }), 1);
assertEqual(count([]), 0);
assertEqual(count([1]), 1);
assertEqual(count([1, /* hole */, 2, 3]), 3);

If you use __count__ and need to test changes to remove that use, you can experiment with a version of Firefox with support for __count__ removed by downloading a nightly from nightly.mozilla.org. (Don’t forget to use the profile manager if you want to keep the settings you use with your primary Firefox installation pristine.)

04.04.10

25.03.10

Bluemont, VA to Waynesboro, VA: Shenandoah NP is overrated

September 4

(0.0; 1185.4 total, 988.6 to go; -15.0 from pace, -134.6 overall)

I intend to get up and hike today, but laziness and a ready Internet connection distract me. I spend most of the day reading email and feeds as well as working on a web tech blog post about a feature I implemented shortly before starting this hike: the DOM Text.wholeText and Text.replaceWholeText APIs. It was an interesting little bit of hacking I did in an attempt to pick up as many easy Acid3 points as possible for Firefox 3 with as little effort as possible. I have more to say on this topic, but at the request of a few people I have split it into an extended, separate post so that my thru-hike ramblings don’t distract from it. Beyond writing the web-tech post and catching up on things, one other minor anecdote sticks out from today: at one point Lydia, the daughter, has a screaming fit. Red Wing tells me how he responded: he told her that she should be quiet because her stuffed rabbit was trying to sleep — and it worked. Heh. 🙂

The Honeymooners walk in later in the day to again catch up to me (not unexpectedly, as I knew the Four State Challenge would not be an efficient way to make good miles in the long run), and I round out the day again by taking advantage of the same $25 hostel deal available last night. Also, since I ended up staying this extra day at the hostel, I’m now slightly rushed to meet up with family at the south end of Shenandoah National Park, at around 1325 miles down the trail. I’m currently at 1185, with the plan being to meet them at the end on September 10, so I’ve eaten up my margin for error today: The Hike Must Go On again in earnest tomorrow.

September 5

(18.3; 1203.7 total, 970.3 to go; +3.3 from pace, -131.3 overall)

Yesterday was a recovery day, so today it’s back to business, as I work to remain mostly even with the Honeymooners and to catch back up to Smoothie. Of course, that still doesn’t stop me from dallying in the morning, and after I post the web-tech article alluded to yesterday, I finally roll out of the hostel at around noon, well after the Honeymooners leave.

Not much sticks out in today’s hiking. I don’t see the Honeymooners again, which is a little odd since I’d assumed they would plan to hike further than I intended to hike, having left several hours before I did. The first bit of the day is just getting out of the Roller Coaster (a 13.5 mile stretch of trail with ten viewless ascents and descents necessitated by a narrow trail corridor; see also my previous entry), and there’s not a lot to see. By the time I get through to Rod Hollow Shelter at its end it’s just about 17:00. I consider stopping for the day, but I haven’t even gone ten miles at this point, and I still have daylight and energy left in me; onward another 8.4 miles I go to the next shelter.

I have to keep up the pace to get there before it gets too ridiculously dark, but it’s a nice bit of hiking. Later on I pass through Sky Meadows State Park as dusk hits; I feel a sprinkle every so often, providing further incentive to keep moving to avoid real rain if it happens. I get to the shelter as darkness hits, and it’s an unusual one — probably the most unusual since Hexacuba Shelter in Vermont. Dick’s Dome Shelter is on private land, was constructed by a PATC member out of (as best as I recall) fairly artificial materials, and — strangest of all — is shaped like a d20 (icosahedron, for the culturally challenged) with three adjacent faces omitted to serve as an opening. It’s small (claimed to sleep four), and luckily I’m the only person in it for the night. I fill up on water from a small stream passed en route to the shelter, and I hang my food bag from a bear cable placed between trees a little distance from the shelter — it’s great not to have to search around for a plausible tree branch in the darkness. Rain falls at a moderate rate — no longer sprinkles, but not in particular earnest — as I head to sleep. 18 miles for the day is a reasonable distance given my late start, but I have 122.2 miles to hike in the next five days to meet family at the south end of Shenandoah National Park, and an 18-mile day just doesn’t cut it if I want to hike those days without feeling rushed.

September 6

(18.0; 1221.7 total, 952.3 to go; +3.0 from pace, -128.3 overall)

I wake up in the morning to the same rain from last night, and it shows no signs of stopping. (I eventually learn that this rain is the continuation of Hurricane Hanna, explaining the rain’s persistence over the next several days.) At least it’s not turning into a downpour, but this won’t be much fun to hike through. Off I head into the rain; it’s not stopping, and I can’t stop either.

Rain continues up to the first shelter stop of the day at Manassas Gap Shelter, where I take an opportunity to duck inside and out of the rain for a bit. The shelter has a note prominently posted in it talking about a semi-residential rattlesnake, noting that anyone who sees it (I do not) should mention it in the register. I fill up my water bottle with rainwater pouring off a corner of the shelter roof (I still purify, of course) before returning to the rain. I continue hiking through the rain to the Jim and Molly Denton Shelter, where I again stop out of the rain for a bit. I save its register from being soaked beyond its current state; someone’s left it on one of the porch benches, fully exposed to rain. Past that the trail passes by a fenced-in National Zoological Park Research Center, which the Companion says occasionally provides views of exotic animals; I see none in this weather.

A few more miles of walking and drizzle take me to Tom Floyd Wayside, the first shelter in the Shenandoah National Park section of the trail as delimited by the Companion. (Technically, I have a little more hiking before I’m inside the park proper.) The site has a nice cable for hanging food, and as usual these days I have the shelter to myself. It’s somewhat odd, this being a Saturday night when usually others are out camping, but I suppose the near proximity of Shenandoah makes the difference: if you’re going out for a weekend trip, you’re probably not going to go just next to a national park but rather into it. Among the shelter’s decorations: a charming poster warning of the possible dangers of accidentally inhaling fecal dust from mice or rats infected with disease.

Today’s hiking would have been shorter and more pleasant if I didn’t have the looming deadline to get out of Shenandoah to meet family. Given the remaining distance, however, I couldn’t make any further curtailments; 104.8 miles in the remaining four days is already pushing pretty hard, and the rainy weather makes that even worse. Why didn’t I learn the lesson the last time I had a hard deadline to make that deadlines are bad?

September 7

(23.6; 1245.3 total, 928.7 to go; +8.6 from pace, -119.7 overall)

Today’s hiking is much more pleasant than yesterday’s soggy mess as I enter Shenandoah National Park.

Mid-day view of Skyline Drive in Shenandoah NP
Mid-day view of Skyline Drive in Shenandoah NP

Shenandoah National Park consists, roughly speaking, of a hundred-mile road called Skyline Drive that follows the ridges of the Appalachians in the area, surrounded by a fair amount of forest, cut through with hiking trails, horse riding paths, and other nature-y things of that nature. Sounds vaguely nice, right? Well, yes and no. First, it’s a national park, which means, relative to its attractions, it receives an outsize number of visitors. I don’t mind people when I’m hiking, but I’d prefer there not be too many people, and national parks can push it, even on hiking trails. Second, it’s a national park whose chief attraction is a road. Many, possibly most, visitors drive down Skyline Drive looking at scenery, maybe stopping at overlooks, and consider that their park experience. Fine, you go do that if you want and miss out on all the interesting bits, but leave me out of it. Unfortunately, for this park, hiking on the A.T., there’s no choice: the trail roughly parallels Skyline Drive for roughly 100 miles of trail, crossing back and forth over it 28 times according to the Companion. Thus, you’re never very far from something approximating civilization. Great national park experience, eh?

The only good thing about being near a road so much is that you’re also near Shenandoah’s “waysides”, convenience stores along the road at which it’s possible to resupply. (The stores also sell bottles of wine, which seems like an incredibly stupid idea given clueless tourists’ penchant for careless littering.) This is almost convenient, except that the waysides are all run by a single entity, Aramark, so you get markedly higher pricing than you’d get at any other resupply point in the area. Some of the difference is due to the waysides’ remoteness, to be sure, but some is certainly the result of Aramark’s government-licensed monopoly on services in the park.

More mid-day views from Shenandoah
More mid-day views from Shenandoah

Shenandoah’s a bit different from most of the Trail, for backpackers, in that you have to get a permit to backpack through it. The permit’s basically a formalism: if you enter Shenandoah via the A.T. you pass by a small sign-in station. There you pick up a carbon-copy form, fill it out with your rough itinerary of camping locations and dates, deposit one copy at the station, and visibly fasten the remainder on the outside of your backpack with a small wire. There’s no fee for doing this (people who drive into the park have to pay for that privilege), which is pleasantly surprising. I pick mine up at the station, which is just a mile into today’s hiking.

Much of today’s hiking consists of me marveling at so many people as I cross and recross Skyline Drive. Parking lots filled with cars and the occasional people disembarking from them present a marked contrast to anything I’ve seen this close to the trail since probably Bear Mountain in New York. The highlight of the day happens around noon when I get a definite sighting of a black bear. I’d seen what might have been one in New Jersey, but I get a good, long view of this one. He’s eastward of the trail maybe fifteen or twenty yards over — and ten or fifteen yards up. See a bear like this, and you’ll realize why the prospect of climbing a tree to get away from a bear is such an utterly ridiculous idea. The bear’s up there, just nibbling away on leaves or acorns or whatever it is they like to eat, certainly aware of the people around him but not sufficiently rushed to stop eating immediately. After a minute or so some people I’d just passed catch up, and they stop to watch the bear as well. Shortly after the bear leisurely and gracefully climbs down the tree. He turns, looks at us briefly, then ambles off into the trees and brush in the opposite direction. Good stuff — now if only I’d remembered to pull out the camera before he was walking away…. Shenandoah is the big spot on the Trail for seeing bears — if you see one, you’re probably going to see it here. I see a few more bears through my hiking hear, and I hear what are probably about an equal number crashing through the bushes and trees running away from me. This one was really one of the more fearless bears I saw both in Shenandoah and on the entire hike.

My goal for the first bit of the day is to get to Elkwallow Wayside, 16 miles south, so I can resupply. The Companion notes this is the last opportunity for northbounders to get blackberry shakes, so I’m planning on getting one to see what it’s like. Once there I resupply and discover the aforementioned prices. Where usually Knorr noodles (the mainstay of my dinners) go for $1.25-1.50 or so, here, as best as I recall, they’re around $2.30. Other items are similarly marked up; had I known beforehand I would have made an effort to avoid resupplying here, since resupply here was more a matter of convenience than anything else. The attached burger/milkshake fast-food counter is similarly overpriced, with the milkshake going for around $4.00 as I recall (and it’s unremarkable to boot), and the entire meal coming to around $11 including tax. Oh well, at least it’s only the once.

After lazing around for a bit eating and relaxing, watching people pass by, it’s time to start hiking again, newly burdened with food to last through the rest of SNP. It’s only 7.4 miles to go, and I hit a good pace and the miles go by effortlessly. I walk up to Pass Mountain Hut (as shelters are named in SNP) with some day to spare.

I share the shelter with three other people. One is a middle-aged man who says he’s doing a long-distance northbound hike, starting from some location I can’t quite remember, maybe the south end of Virginia. The other two men are in their thirties or forties and, as best as I can recall, are hiking together. One of them, upon hearing at some point that I’m going into the software industry after I finish my thru-hike, vigorously attempts to dissuade me from such, based upon his experiences at IBM (in sales or something like that, I hasten to note), wherein he discovered just how far he was willing to betray his principles. (The furthest such case involved eating food from the foot of a quadriplegic client, or something approximating that scenario. I am not making this up!) I’m not sure if I ever stated that I was going to work for Mozilla. I’m not sure it would have made a difference even if I had, given the extent of his bitter-and-jadedness.

The shelter register here provides good entertainment in the form of stories from other insane thru-hikers. Several northbounders, when they passed through, arbitrarily decided to complete a Twenty-Four Hour Challenge. Their full day of hiking ended at this shelter, after a sixty-plus mile day including a few-hour detour into nearby Luray for food and entertainment resulting in an entertaining picture of, of all things, clogging, which they left in the register. Another potential challenge, maybe? This one doesn’t require any particular time or location to attempt, so it’s easier to work into the hike any time it’s convenient. We’ll see…

The other fun thing about Shenandoah is that they have somewhat unusual food-storage requirements at campsites: large, dozen-foot poles stuck in the ground with hooks at the top, from which you’re to hang bags of smellables using an attached pole. (If you’re stealth-camping and not staying at an established campsite you hang your smellables in the usual way, with rope over tree branches.) It takes some dexterity to get my pack up, mostly because it’s still mostly filled with food. It’s not necessary to send the full pack up, but — particularly in a national park — the shelter mice population will be considerable. Even emptying a pack out isn’t proof against mice chewing their way in after smells of foods since removed. Opening up all zippers and pockets as far as possible helps, but it’s no guarantee like removing it from their reach completely.

September 8

(26.8; 1272.1 total, 901.9 to go; +11.8 from pace, -107.9 overall)

Today it’s up and out pretty early since I have so much distance to cover: nearly 27 miles to where I plan to stay for the night, Bearfence Mountain Hut. As a result I scare a couple bears down from trees as I walk back along the trail to the shelter to get back to the A.T. itself. These bears are both a good ten or fifteen yards up, and they’re down on the ground in two or three seconds bolting the other way, yet again demonstrating that climbing trees to escape bears is pointless and that the bears are more afraid of you than you are of them.

Continuing on, I meet my first truly unwelcome wildlife in Shenandoah: a deer on the trail who won’t move. (The trail’s too narrow to safely walk around it given its hind legs.) As I approach the deer is clearly aware of my presence, but it makes no effort to move. I keep walking until I’m perhaps a dozen feet from it, and it still hasn’t moved! This is ridiculous. I yell at it a little, and it remains unfazed (and unmoved). I take a step or two toward it while attempting to appear as aggressive as I can; it backs up (WIN), but then it takes a step or two toward me (FAIL), and I just as quickly take a couple steps back. This deer is clearly used to Not Taking Nothing From Nobody Nohow. Eventually it takes a step or two halfway into the bushes next to the trail, and I decide that if I move as far to the left on the trail as possible I’ll be comfortably far from the deer’s hind legs, so I pass the “wild” deer on the momentarily-congested trail.

A deer munching on leaves at close range, entirely unafraid of my presence
Mm, doesn't that venison look tasty?

This isn’t the only deer I see in SNP that’s overcomfortable with people. The situation eventually gets so bad that I start counting the number of deer I see each day I’m hiking through, and I don’t think I had a day where the number was in single digits. Sometimes the deer run; mostly they stand and watch lazily. The deer know I can’t do anything to them, and indeed they hope for the opposite: that I’ll give them food. There are signs everywhere telling visitors not to feed the deer (I took a moment to admire one while at Elkwallow Wayside yesterday), but effectively prohibiting deer-feeding is about as likely as being able to effectively administer Prohibition. Through this food, the deer have lost much of their natural respect (with some amount of fear) for humans. Now to be sure, education is a worthy goal, and the fewer people who actually do feed the deer, the better — but it’s not realistic to ever think education alone will cure the deer of their fearlessness.

What SNP really needs, and what would address this problem, is the introduction of limited hunting. Shenandoah is a national park, so hunting in it is prohibited. This doesn’t have to be the case! A very little bit of hunting, carefully overseen by the park, would very quickly make the deer realize that humans are not risk-free potential sources of food, that humans can mean danger, and that it’s best to maintain a healthy distance from them. I don’t suggest open season — but if portions of the park were periodically opened to hunting for very short periods of time (so as to minimize disruption to the activities of other visitors), the deer would learn quickly enough how to behave in a way that minimizes dangerously close interactions between deer and humans. Limited hunting for such purposes is not an unusual concept; when I lived in Michigan we had a similar problem at some state parks (except even worse, because those parks had far more trail and road coverage than SNP does), and the problem got so bad that the state actually hired sharpshooters to come in to thin the herds and reduce excessive interaction. (Why they hired sharpshooters rather than opening it up for local hunters, who would have done the same work for free, is beyond me.) Unfortunately, getting traction on the problem will be a horrendous matter of politics, so I don’t expect such sensible measures to be taken any time soon.

Morning hiking proceeds slowly as usual. At one point the trail passes by the Pinnacles Picnic Ground, with picnic tables, water, restrooms, and so on, and I stop for a bite to eat. While there I meet a man who, upon hearing what I’m doing, says he thru-hiked the Appalachian Trail back in the 1970s when the A.T. was thru-hiked much less often; his year saw maybe a dozen or so thru-hikes (or perhaps completions, memory hazy), total. (For comparison, there were 419 reported thru-hikes going north to south or south to north in 2008 when I completed my hike, a further 39 hikes which took some other route covering the entire trail [say, starting halfway walking north, then returning to finish hiking south], and 96 full-trail hikes completed in multiple segments.) I continue hiking toward Skyland, a lodge roughly 11 miles into my hiking for the day, arriving sometime after 13:00.

Skyland is a small lodge/resort/restaurant/tap room in SNP that dates to the 1800s; it precedes the park itself, and its owner, George Freeman Pollack, was a strong advocate for creating a national park in the area by taking the necessary land from its owners using eminent domain. From what I understand he took this position not because he thought the country needed a national park, or SNP in particular, but because he figured it would be a good way to drum up extra business at his resort. It’s ironic, then, that through his success in seeing SNP created he himself was among those who had his resort and land taken from him. It’s a dirty little story I doubt you’d see mentioned in many of the displays there, a strong warning to those considering harnessing leviathan for private gain.

In other circumstances I would be taking this opportunity to visit the tap room at Skyland, the better to fully enjoy the unique experience of a good, backcountry, restaurant. But that’s out of the question now if I have to get to the south end of the park in two days. 🙁 (Have I mentioned how incredibly bad deadlines are?) Instead I buy a (vending-machine) bottle of root beer, glance at a nearby newspaper (Hurricane Hanna and the nationalization of Fannie Mae and Freddie Mac dominate headlines), and search for a phone to call family and update them on current progress. I have almost 70 miles to go, another 16 still for today, to meet family where I’d intended to meet them. We discuss for a little, but there really isn’t a good place to meet up other than the end. There are a number of random overlooks at which we might be able to meet, but that’s kind of a dicey plan. There’s one major road crossing that’s feasible, except that it’s so much further from the end that getting there in two days would be absurdly easy. In the end I decide there’s really nothing to it but to hike through to where we were going to meet originally — serves me right for setting a deadline.

Call completed, it’s back out to hiking again. It’s getting close to 15:00, so I need to make miles quickly to avoid night hiking. Thankfully, as usual my afternoon-hiking legs kick in, and I churn out the next 16 miles of trail almost without stopping, to arrive at Bearfence Mountain Hut as darkness hits around 20:30. I have the shelter to myself, it being a Monday night, and there’s a very convenient water source. After that it’s off to sleep to the sound of more-present-than-typical shelter mice (zippers and pockets opened) — two more big-mile days until family…

September 9

(25.8; 1297.9 total, 876.1 to go; +12.8 from pace, -97.1 overall)

It’s up and out for a long day today, either thirty-plus miles to Blackrock Hut or something less than that with stealth camping. It’s drizzly and rainy for much of the day, making hiking more drudgery than otherwise. Still, it could be worse — I pass Smoothie, hiking in the opposite direction, hoping to find a camera he thinks he dropped somewhere back on the trail. (I find out in shelter register reading tomorrow that he successfully retrieved it, getting a ride back to where he was on the trail and thus leapfrogging me.) Hiking continues into the afternoon; I see several turtles on the trail:

A handspan-sized turtle with a brown shell mottled with yellow
A turtle (possibly an eastern box turtle) on the trail

The trail drags today; eventually I find myself at a road crossing with a ranger station (and, more importantly, a water spigot) 0.2 miles away, and I head there to consider my options. It’s getting pretty late in the afternoon, and I’m not much above halfway for the day if I wanted to go to Blackrock Hut. For the moment I decide to punt on a decision and make and eat dinner. I hope maybe that’ll help me decide what do to. While eating I have perhaps my most disgusting deer interaction of the trip, as a deer walks up to within a dozen paces of me and proceeds to pace back and forth, looking at my Knorr rice dinner with obvious interest, clearly begging for food. This deer knows what he can get from stupid tourists, but I’m not one.

The extra energy from dinner (I really ought to use this tactic more often), however, helps me decide what to do: hike another seven miles or so to an area of trail nestled carefully between a campground and a wayside (safely further than the required 0.25 miles distance from either) and stealth-camp there, or hike further if there’s no obvious camping space. By now it’s late enough that I know I’ll be night-hiking. With the extra energy I have now, that just makes it all the more fun — after all, if you don’t night-hike, how will you ever get to wonder if that crashing noise from up in a tree just off the trail is a bear fleeing your presence or not? (This actually happens to me tonight; highly recommended. Remember: the bears fear you more than you fear them.) My pace isn’t fast, particularly due to encroaching darkness, but that no longer matters mentally, so it’s all okay.

My aim brings me to a field with somewhat high grasses and a fair number of trees. The trees provide good branches to hang smellables, which makes it basically adequate for me — hanging food in a bad location is a bigger chore than suffering a little while sleeping. This is definitely an area where I’d have been out of luck with the tent; I’m glad to have the bivy sack.

September 10

(28.0; 1325.9 total, 848.1 to go; +13.0 from pace, -84.1 overall)

Sleep last night wasn’t very comfortable, nor was it very dry. This bivy sack may keep out water when properly set up, but if the hood at top is mis-deployed it’s hopeless. I find if I roll over slightly I’m in a half-puddle of water, fun times. I get up, put on not-dried socks and wet boots, and start hiking with a minimum of delay. Hiking is slow this morning (what’s new?) as I head toward the first shelter of the day at Blackrock Hut, eating a Pop-Tart breakfast (“breakfast”? so it goes) as I walk. This trail is interesting because it was the site of a controlled burn in the spring, according both to signs and scorched, er, “blackery”. There’s not a whole lot of green through here, certainly none of it as trees, and I’m sure some northbounders had to skip trail in this area to avoid the fires when they were originally started. I reach Blackrock Hut having covered seven or so miles in way too long, and by the time I leave it’s past noon, and I have twenty miles to go to meet family at an unspecified time at a location that hopefully isn’t too hard to figure out (it’s a large road crossing, but beyond that I have no idea).

I continue hiking, being careful about what I eat because I have little of it — a handful or so of large Snickers bars is about it. This doesn’t help hiking speed much, but the problem is likely more mental than physical. I’m helped out a bit when, in talking to some passing day hikers (Trail fans, one a section hiker as I recall; they talk a bit about the Mayor with me), they give me an extra Clif bar to eat. After eating that and getting a little mental boost from talking and explaining where I have to be at end of the day, hiking pace picks up again to its normal top speed, and the miles start flying again. At this pace I should finish hiking just before dark.

The miles pass as I hike out of SNP. As I approach the first shelter just outside the park I see wild turkeys off the side of the trail; they’re making me hungry. The shelter’s far enough off-trail, and I’m in enough of a groove, and my time is just limited enough, that I keep moving past the shelter and don’t bother stopping. (An idle idea: could you carry a road bike in along the Appalachian Trail, past the gates, to avoid paying an entry fee?) I reach the southern self-registration backpacker kiosk, where northbounders would have registered. There’s a note waiting from Dad, maybe 15-30 minutes ago, saying they were waiting with the car at the road perhaps 0.8 miles away. A bit more walking and I’m there! The very first task is to quickly run to the promised nearby convenience store that closes at 20:00 in the hopes of getting some proper ice cream, but the store’s empty (and clearly has been for some time, sigh; another thing fixed in more recent Companions).

That done, and greetings complete (I’m told quite accurately that I reek), it’s on the road to drive to the resort where we’re staying (with a grocery store stop along the way, to get that half gallon of ice cream I’d been hoping to eat — and it’s not a proper half gallon either 🙁). It’s about an hour away (perils of trying to meet a hiker who doesn’t have a planned schedule), but once we arrive it’s dinnertime — barbecued ribs tonight, as I recall. For kicks I pull out the wrappers from all the various food items I ate today and count calories; the total is upwards of 3000 calories, maybe just under 4000 — and all of it except maybe the Clif bar was junk food. 🙂 Fun times…

September 11

(0.0; 1325.9 total, 848.1 to go; -15.0 from pace, -99.1 overall)

Today’s pretty lackadaisical, and mostly it’s just a chance to relax. We don’t make an effort to do very much. Shopping for supplies for the next section of hike is the biggest task I remember (although it seems like we still spent a fair amount of time running errands even if we didn’t do much). As usual the candy haul (thirty-odd bars) gets me some looks. This next section of trail’s fairly remote, arguably the most so since the Hundred Mile Wilderness. While there are towns off-trail, they’re all a fair distance along the roads, so the most convenient destination for someone not interested in dealing with the unpredictable delay hitchhiking entails is 134 miles south at Daleville. My food supply, therefore, is probably the third-largest I end up carrying during the entire trip. (The two long stretches in Maine are the only larger hauls.) Once back at the resort we take the opportunity to swim in the resort pool; for me it’s the first swimming since Massachusetts. But mostly, today’s just a day to relax, without deadline or plan to fulfill.

I don’t know it at the time, of course, but I have 44 days of hiking to go to reach Springer…

« NewerOlder »