Holy cow, I wrote a book!
I may have scared a bunch of people with
that chart of German adjective endings,
but as several commenters noted,
native speakers don't refer to the charts;
they just say what comes naturally.
(Well, except for
who claims that native Russian speakers actually study these charts
in grade school.)
Helga Waage noted
that one quickly sees patterns in the charts that make them much
easier to digest.
And that's true.
But I taught myself the German adjective endings a completely different way.
If you're a student of German, you might find this helpful.
If you're not, then you probably just want to skip the rest of this entry.
As a side note,
you have to make sure you put the columns in the right order.
In many textbooks, the columns are ordered as
"masculine, feminine, neuter, plural",
but this fails to highlight the strong similarity between the masculine and
From a grammatical standpoint, German neuter nouns are
"90% masculine, 10% feminine";
therefore, it's more natural to put the neuter column between the masculine
and feminine columns.
I therefore prefer the order
"masculine, neuter, feminine, plural",
which as it so happens appears to be the order that Germans themselves use.
I'm going to do away with the terms "strong", "weak", and "mixed".
Instead, I'm going to reduce it to the question "How much work does
the adjective have to do?" which breaks down into two inflections.
In my mind, I don't have terms for these two inflections, but for the
purpose of this discussion I'll call them
"hardworking" and "lazy".
We start with the lazy inflection, which is used when
the definite article
or a word that has the same ending as the definite article
The lazy inflection is simple:
In the singular of the nominative and accusative cases (the "easy cases"),
the ending is "-e".
In the plural and in the genitive and dative cases (the "hard cases"),
the ending is "-en".
There is only one exception to this general rule, which I highlighted
in the table above.
But even that exception is natural,
because the masculine gender is the only one whose articles
change between the nominative and the accusative, from
"der" to "den" and "ein" to "einen",
so you're already used to sticking an extra "-en" in the masculine
(By the way, I call the nominative and accusative the "easy" cases
since most textbooks teach them them within the first few weeks,
which means that you've quickly become familiar with them and treat them as
On the other hand, the dative and genitive are not usually
introduced until second year, thereby making them "hard" due to
their relative unfamiliarity.)
The hardworking inflection is even easier than the lazy inflection.
You use the hardworking inflection when there is no
word that has the same ending as the definite article.
In this case, the adjective must step up and take the ending itself.
(I've included the definite article in the chart for reference.)
Hey, wait, I left two boxes blank.
What's going on here?
Well, because in those two cases,
even if there is nothing else to carry the ending of the definite article,
the noun itself gets modified by adding "-s".
For example, the genitive of the neuter noun "Wasser" (water) is "Wassers"
The word that carries the ending of the definite article is the noun itself!
That's why I leave the boxes blank:
The scenario never occurs in German.
It is those empty boxes, however, that always trip me up.
When it comes time to decide what ending to put on the adjective,
and I'm in one of those two boxes,
the word with the ending of the definite article hasn't
appeared yet so I think I'm in the "hardworking" case.
And then when I get around to saying the "-s" at the end of
"Wassers", I realize,
"Oh, crap, there's that indicator.
I should have used the lazy form."
But it's too late, I already said the adjective with the wrong ending.
I could go back and fix it, but that would interrupt the
flow of the conversation, so I usually decide to let it slide and take the
hit of sounding stupid.
(Or, more precisely, sounding more stupid.)
If you listen carefully, you may notice me pause for a fraction of
a second just as I reach the "-s"
and the realization dawns on me that I messed up
If you compare my charts to the official charts with strong,
weak and mixed inflections, you'll see that my "lazy" inflection
matches the weak inflection exactly,
and my "hardworking" inflection matches the "strong" inflection
except for those empty boxes.
(Because, under my rules, those empty boxes are lazy.)
The mixed inflection matches the "lazy" inflection except in three places,
which I count as "hardworking"
because the indefinite article "ein" does not take an ending
in exactly those three places.
Anyway, so there's how I remember my German adjective endings.
Mind you, I don't work through the details of these
rules each time I have to decide on an ending.
I just have to make the simple note of
whether the definite article ending has already appeared
(or in the case I always forget: will soon appear).
If not, then I put it on the adjective.
One of the big complaints about Explorer we've received
from corporations is how often it accesses the network.
If the computer you're accessing is in the next room,
then accessing it a large number of times isn't too much
of a problem since you get the response back rather quickly.
But if the computer you're talking to is halfway around the
world, then even if you can communicate at the theoretical
maximum possible speed (namely, the speed of light),
it'll take 66 milliseconds for your request to reach the
other computer and another 66 milliseconds for the reply to
In practice, the signal takes longer than that to make its
A latency of a half second is not unusual for global networks.
A latency of one to two seconds is typical for satellite networks.
Note that latency and bandwidth are independent metrics.
Bandwidth is how fast you can shovel data, measured
in data per unit time (e.g. bits per second);
latency is how long it takes the data to reach its destination,
measured in time (e.g. milliseconds).
Even though these global networks have very high bandwidth,
the high latency is what kills you.
(If you're a physicist, you're going to see the units "data per unit time"
and "time" and instinctively want to multiply them together to see
what the resulting "data" unit means.
Bandwidth times latency is known as the "pipe".
When doing data transfer, you want your transfer window to be
the size of your pipe.)
High latency means that you should try to issue as few I/O requests
as possible, although it's okay for each of those requests to be
rather large if your bandwidth is also high.
Significant work went into reducing
the number of I/O requests issued by Explorer during
common operations such as enumerating the contents of a folder.
Enumerating the contents of a folder in Explorer is more than
just getting the file names.
The file system shell folder
needs other file metadata such as the last-modification time
and the file size in order to build up its SHITEMID,
which is the unit of item identification in the shell namespace.
One of the other pieces of information that the shell needs is
the file's index, a 64-bit value that is different for each file on a volume.
Now, this information is not returned by the "slow"
As a result, the shell would have to perform three round-trip
operations to retrieve this extra information:
If you assume a 500ms network latency,
then these three additional operations add a second and a half
for each file in the directory.
If a directory has even just forty files, that's a whole minute
spent just obtaining the file indices.
(As we saw last time,
the FindNextFile does its own internal batching to
avoid this problem when doing traditional file enumeration.)
And that's where this "fast mode" came from.
The "fast mode" query is another type of bulk query to the
server which returns all the normal FindNextFile
information as well as the file indices.
As a result, the file index information is piggybacked on top
of the existing FindNextFile-like query.
That's what makes it fast.
In "fast mode", enumerating 200 files from a directory would take
just a few seconds (two "bulk queries" that return the
FindNextFile information and the file indices at one go,
plus some overhead for establishing and closing the connection).
In "slow mode",
getting the normal FindNextFile information takes
a few seconds, but getting the file indices would add another 1.5 seconds
for each file, for an additional 1.5 × 200
= 300 seconds, or five minutes.
I think most people would agree that
reducing the time it takes to obtain the SHITEMIDs for
all the files in a directory
from five minutes to a few seconds is a big improvement.
That's why the shell is so anxious to use this new "fast mode" query.
If your program is going to be run by multinational corporations,
you have to take high-latency networks into account.
And this means bulking up.
Some people have accused me of intentionally being misleading
with the characterization of this bug.
Any misleading on my part was unintentional.
I didn't have all the facts when I wrote up that first article,
and even now I still don't have all the facts.
For example, FindNextFile using bulk queries?
I didn't learn that until Tuesday night when I was investigating
an earlier comment—time I should have been spending planning
Wednesday night's dinner, mind you.
(Yes, I'm a slacker and don't plan my meals out a week at a time
like organized people do.)
Note that the exercise is still valuable as a thought experiment.
Suppose that FindNextFile didn't use bulk queries
and that the problem really did manifest itself only after the
101st round-trip query.
How would you fix it?
I should also point out that the bug in question is not my bug.
I just saw it in the bug database and thought it would be an interesting
springboard for discussion.
By now, I'm kind of sick of it and will probably not bother
checking back to see how things have settled out.
the names for some Microsoft products
had to be changed due to a name conflict.
I'm told that
the people who had to come up with the name for
the database product avoided
this pitfall in a clever way:
Instead of trying to avoid a name that was already taken,
they intentionally used a name that was already
By Microsoft itself.
They discovered that
Microsoft had a long-forgotten terminal emulator product
called Microsoft Access.
"Access" sounded like an appropriate name for a database product,
so they blew the dust off it and gave the name a new life.
Most westerners are familiar with the fact that the way
numbers are formatted differ between the United States
and much of Europe.
What people don't realize is that the grouping is not always
In India, the least significant group consists of three digits,
but subsequent groups are in pairs.
I've also seen reports that the first group consists of five digits,
followed by pairs:
Meanwhile, Chinese and Japanese traditionally group in fours.
What does this mean for you?
Don't assume that numbers group in threes,
and of course you can't assume that the grouping separator
is the comma and the decimal character is the period.
Just use the GetNumberFormat function and let
NLS do the work for you.
Next time, a little more about that NUMBERFMT structure.
What's the deal
the house in front of Microsoft's RedWest campus?
Here is my understanding.
It may be incomplete or even flat-out wrong.
The house belongs to a couple who was unwilling to sell their property
when Microsoft's real estate people were buying up the land
on which to build the RedWest campus.
(I'm told it was originally a chicken farm.)
Eventually, a deal was struck:
The couple would sell the property to Microsoft but retain
the right to live there until the end of their natural lives.
Furthermore, Microsoft would assume responsibility for maintaining
the lawn and landscaping.
When Microsoft needed to build an underground parking garage
beneath their property,
the house was put on a truck, carried across the street,
where it rested for the duration of the construction,
after which it was returned to its original location.
I imagine the couple was put up in a very nice hotel for
the duration of the construction.
(Heck, maybe they got a nice kitchen remodel out of the deal,
And while I'm spreading rumors about the Microsoft RedWest
campus, here's another one:
If you pay a visit to the campus,
you will find a nature trail that leads through
the wetlands that adjoin the campus.
I was told that the wetlands preservation area was part of the
environmental impact mitigation plan that was necessary to obtain
approval for the construction.
The students at
the nearby school will occasionally take field
(I'm going to cover lighter issues for a while just to take a break
from the network interoperability topic that has raged for over a week
(This is the first in a series of short posts on where Microsoft
products got their names.)
The original name for the malware protection service was "mpsvc"
the "Microsoft Protection Service", but it was discovered later
that filename was already used by malware!
As a result, the name of the service had to be changed by sticking
an "ms" in front, making it "msmpsvc.exe".
Therefore, technically, its name is the "Microsoft Microsoft Protection
(This is, of course, not to be confused with
"mpssvc.exe", which is, I guess, the
"Microsoft Protection Service Service".)
Fortunately, the Marketing folks can attempt to recover by
deciding that "msmpsvc" stands for
"Microsoft Malware Protection Service".
But you and I will know what it really stands for.
Mistakes were made.
Mistakes such as
having Windows NT put Notepad in a different
location from Windows 3.1.
(Though I'm sure they had their reasons.)
Mistakes such as having a TCS_VERTICAL
when there is already a CCS_VERT style.
Mistakes such as having listview state images be one-biased,
whereas treeview state images are zero-biased.
But what's done is done.
The mistakes are out there.
You can't go back and fix them—at least not until
time travel has been perfected—or you'll break code
that was relying on the mistakes.
(And believe me, there's a lot of code that relies on mistakes.)
You'll just have to do the best you can with the situation as it is.
Often, when I discuss a compatibility problem,
people will respond with
"That's your own damn fault. If you had done XYZ, then you wouldn't
have gotten into this mess."
Maybe that's true,
maybe it isn't,
but that doesn't make any progress towards solving
the problem and therefore isn't very constructive.
I sure hope these people never become lifeguards.
"Help me, I'm drowning!"
"Are you wearing a life preserver?"
"Well, if you had worn a life preserver, then you wouldn't be drowning.
It's your own damn fault."
When faced with a problem,
you first need to understand the problem,
then you set about exploring solutions to the problem.
Looking for someone to blame doesn't solve the problem.
I'm not saying that one should never assign blame,
just that doing so doesn't actually solve anybody's problem.
(If you want to blame somebody, do it at the bug post-mortem.
Then you can
study the conditions that led to the mistake,
assign blame, if you're looking for a scapegoat,
and take steps to prevent a future mistake
of the same sort from occurring.
As a lifeguard, you first rescue the drowning person,
and then you lecture them for not wearing a life preserver.)
Yes, there are plenty of scripting languages that are much
better than boring old batch.
Batch files were definitely a huge improvement over SUBMIT
back in 1981,
but they've been showing their age for quite some time.
The advanced age of boring old batch, on the other hand, means that you have
millions of batch files out there that you had better not break if you
know what's good for you.
(Sure, in retrospect, you might decide to call the batch language
a design mistake,
but remember that it had to run in 64KB
of memory on a 4.77MHz machine while still remaining compatible in
spirit with CP/M.)
Shipping a new command shell
doesn't solve everything either.
For one thing,
you have to decide if you are going to support classic batch files or not.
Maybe you decide that you won't and prefer to
force people to rewrite all their
batch files into your new language.
Good luck on that.
On the other hand, if you decide that you will support batch files after all,
presumably your new command shell will not execute old batch files
natively, but rather will defer to CMD.EXE.
And there's your problem:
You see, batch files have the ability to modify environment
variables and have the changes persist beyond
the end of the batch file.
C> copy con marco.cmd
1 file(s) copied.
C> echo %MARCO%
C> echo %MARCO%
If your new command shell defers to CMD.EXE,
these environment changes won't propagate back to your command
shell since the batch file modifies the environment variables
of CMD.EXE, not your shell.
Many organizations have a system of batch files that
rely on the ability to pass parameters
between scripts by stashing them into environment variables.
The DDK's own razzle
does this, for example, in order to establish a consistent build
environment and pass information to build.exe
about what kind of build you're making.
And I bet you have a batch file or two that sets your PROMPT
or PATH environment variable or changes your current
So good luck with your replacement command shell.
I hope you figure out how to run batch files.
Sometimes you're better off keeping your fool mouth shut.
The other day I got a piece of email requesting that I look at
a crashed system because the tester believed it was another
instance of bug 12345.
While that may very well have been the case,
bug 12345 was a kernel pool corruption bug in the object
something of which I know next to nothing.
Why was I being asked to look at the machine?
Because the bug was originally assigned to my team.
As a gesture of good will,
I reassigned the bug to a more appropriate team,
and that was my downfall,
because that put my fingerprint on the bug report.
The second occurence of the bug was inside another component entirely,
still completely unrelated to my team.
But the tester thinks that I am somehow responsible
for fixing the bug since my name is now in the bug report.
Perhaps I need an alter ego whose name I can use for
cases like this, where my involvement in a bug is not
as an interested party, but rather as somebody merely
offering to help redirect the bug to the correct developer.
But that merely defers the problem:
What should I do if somebody asks the alter ego to investigate the bug?
Another episode in the
sporadic series on the wisdom of seventh graders:
The topic this time is
"What do you want to be when you grow up?"
The students really enjoyed this topic because,
as one young man put it,
"I could write a book about myself!"
Here are what some students had to say.
Spelling mistakes are intact, but ellipses are editorial.
(I have provided tooltips to assist non-native English speakers.
Actually, even native English speakers may have trouble with
some of the spelling errors...)
(And I thought I didn't have to say this, but apparently I do:
These are just the funny-bad sentences.
There were of course plenty of well-written essays,
but they're not as funny.)
the previous series of essays on
humanity's greatest invention or discovery,
one of the responses was "marrying a princess".
I had to ask my friend for an explanation of that one.
"Well, one student decided to ignore the assigned topic and instead
wrote a fairy tale about a beautiful princess who gets married."