The Last Superstition: Reasoning With Aquinas

Chapter 3: Aquinas’s logical reasoning

Eventually, Feser settles down to tell us a bit about Aquinas. In particular, his method of reasoning:

What Aquinas is doing can be understood by comparison with the sort of reasoning familiar from geometry and mathematics in general. Take the Pythagorean theorem, for example. Once you understand the axiomatic method, the definition of triangularity, and so forth, and then reason through a particular proof of the theorem, you can see that the theorem must be true, and necessarily so. It is not a “hypothesis” “postulated” to “explain” certain “evidence,” and it is not merely “probable.” [p.81]

Metaphysical arguments of the sort Aquinas is interested in combine elements of both these other forms of reasoning: they take obvious, though empirical, starting points, and try to show that from these starting points, together with certain conceptual premises, certain metaphysical conclusions follow necessarily. [p.83]

In other words, Aquinas is trying to prove God the way you’d prove a mathematical theorem, through logic and reason, and most emphatically not through observation. You could sum this up as “it stands to reason”.

There are a few problems with this approach: while mathematics is undeniably useful, it also describes a lot of things that don’t actually exist. For instance, Wikipedia defines a Hilbert space as a generalization of Euclidean space, one that can have thousands, or even an infinite number of dimensions, instead of our paltry three or four or twenty-some.

More trivially, mathematics tells us that if you put six quadrillion apples into a basket, and add another eight quadrillion apples, you’ll have fourteen quadrillion apples in your basket. This is obviously false because there aren’t that many apples on the planet, and no basket that can hold them all. In this case, the math describes a world with fourteen quadrillion apples, which is not the world we live in.

The point of this isn’t that mathematics is broken, but rather that it’s important to make sure that you’ve picked the sort of mathematics that describes the world you’re living in, and specifically the problem you’re studying. Don’t go beyond its area of applicability: Euclidean geometry might work on the scale of a town, but not that of a continent, where you have to take the earth’s curvature into account, lest you get wrong answers.

Furthermore, the longer a demonstration goes on, the greater the odds that it’ll contain some error in reasoning, perhaps a subtle one. When Andrew Wiles presented his proof of Fermat’s last theorem, several reviewers went over it looking for errors (and found some). That’s why, when you’re drawing conclusions about the real world, it’s important to have a reality check from time to time to make sure you haven’t gone off the rails. But Feser sees no need for this.


In a criticism of “scientism”, Feser says that science makes certain metaphysical assumptions:

Of its very nature, scientific investigation takes for granted such assumptions as that: there is a physical world existing independently of our minds; this world is characterized by various objective patterns and regularities; our senses are at least partially reliable sources of information about this world; there are objective laws of logic and mathematics that apply to the objective world outside our minds; our cognitive powers – of concept-formation, reasoning from premises to a conclusion, and so forth – afford us a grasp of these laws and can reliably take us from evidence derived from the senses to conclusions about the physical world; the language we use can adequately express truths about these laws and about the external world; and so on and on. [p. 84]

Maybe a scientist or philosopher of science will correct me, but this doesn’t seem quite right:

there is a physical world existing independently of our minds
I think this is a working assumption, one that could be proved wrong.

this world is characterized by various objective patterns and regularities
I’d call this a discovery, not an assumption. Things could conceivably have been otherwise; Greg Egan explores this possibility in his novel Schild’s Ladder in which there is a region of space where there don’t seem to be any consistent laws of physics; every experiment gives inconsistent results. My point is that if such a zone existed, we’d know it. So it seems reasonable to assume regularity, at least until there’s reason to think otherwise.

our senses are at least partially reliable sources of information about this world
there are objective laws of logic and mathematics that apply to the objective world outside our minds
our cognitive powers – of concept-formation, reasoning from premises to a conclusion, and so forth – afford us a grasp of these laws and can reliably take us from evidence derived from the senses to conclusions about the physical world
These all seem to be conclusions, or at worst working assumptions.

the language we use can adequately express truths about these laws and about the external world
But natural languages like English and Greek are often not up to the task of describing reality. That’s why the language of science is math, and why Newton and Leibnitz had to invent calculus. And of course every discipline invents its own jargon, to describe the objects and ideas specific to that discipline, as well as mathematical techniques for those areas.

It’s true that some of these may be basic assumptions, or at least working assumptions. In fact, Feser could just as easily have listed “God is not messing around with my experiment” as a working assumption. But most of them seem at least potentially falsifiable, like in the movie The Matrix, where Neo, the main character, did find out that he was a brain in a vat. I also like this article that uses supernova SN1987A to show that the speed of light was the same 300,000 years ago as it is today, using trigonometry, astronomical observations, and the decay rate of cobalt to cross-check each other.

This cross-checking and verification are things that make science so robust and reliable, and they’re things that I don’t see in Feser’s presentation. And given that he seems to be basing his reasoning on what a medieval monk thought was obvious, I think there’s good reason to be skeptical of his conclusions.

Series: The Last Superstition

A Couple of Shell Quickies

Since I got asked several sh-related questions, I might as well get a post out of them.

One person asks:

I’m writing a portable shell script to download a file from the web, and then compare it to a locally-stored version of the same file, using diff.

My first version of the script used mktemp to download the web-file to temporary file, run the diff command, and then delete the temporary file afterwards. e.g.

TEMPFILE=$(mktemp)
wget -q $ONLINEFILEURL -O $TEMPFILE
diff $TEMPFILE $LOCALFILE
rm $TEMPFILE

However I later discovered that the BSD version of mktemp has an incompatible syntax to the GNU version of mktemp. So then I got rid of the usage of temporary files completely, by using input-redirection, e.g.

diff <(wget -q $ONLINEFILEURL -O -) $LOCALFILE

However while this works fine under bash and ksh, it fails under ash and sh with

Syntax error: "(" unexpected

to which I replied:

The first obvious problem here is that “(wget -q $ONLINEFILEURL -O -)” isn’t a filename, it’s a subprocess. So the shell sees “<” and expects a filename, but finds “(” instead.

It looks as though the way to get diff to read from stdin is the standard way: specify “-” as the filename, and give it input on stdin. Since you’re feeding it the output from a process, you want to use a pipe:

wget -q $ONLINEFILEURL -O - | diff - $LOCALFILE

I also suggested that he could try to figure out which version of mkfile he was using:

# Wrapper function for GNU mktemp
gnu_mktemp() {
	mktemp /tmp/tmpfile.XXXXXX "$@"
}

# Wrapper function for BSD mktemp
bsd_mktemp() {
	mktemp -t /tmp/tmpfile.XXXXXX "$@"
}

# Try to figure out which wrapper to use
if mktemp -V | grep version >/dev/null 2>&1; then
	MKTEMP=gnu_mktemp
else
	MKTEMP=bsd_mktemp
fi

mytmpfile=`$MKTEMP`

And, of course, if race conditions and security aren’t a big concern, there’s always

mytmpfile=/tmp/myprogramname.$$

Another person wanted to write a bash script that would do one thing when run by him or root, and another thing if run by anyone else (basically, die with an error message about insufficient privileges and/or grooviness).

He asked whether the following two expressions were equivalent:

  • if [[ ( `whoami` != "root" ) || ( `whoami` != "coolguy" ) ]]
  • if [[ ! ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]

They’re not, but maybe not for obvious reasons, because propositional logic is a harsh mistress.

In the first expression,

if [[ ( `whoami` != "root" ) || ( `whoami` != "coolguy" ) ]]

let’s say that the user is joeblow. In this case, “`whoami` != "root"” is true, and so the shell can short-circuit the rest of the “||“, because the entire expression is true.

If the user is root, then the first part, “( `whoami` != "root" )” is false. However, the second part, “( `whoami` != "coolguy" )” is true (because rootcoolguy), and so the entire expression is “false || true”, which is true.

The second expression,

if [[ ! ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]

is closer to what he wanted, but doesn’t work because of operator precedence: “!” binds more tightly than “||“, so the expression is equivalen tto “(whoami ≠ root) || (whoami = coolguy)”.

In this case, if the user is joeblow, the first clause, “whoami ≠ root“, is true, and so the entire expression is true.

Worse yet, if the user is root, then neither the first nor second clause is true, so the entire clause is false.

What he really wanted was something like:

if [[ ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]; then
	# Do nothing
	:
else
	# Do something
	echo "Go away"
	exit 1
fi

Except, of course, that since the if-clause is empty, it can be cut out entirely. Then all we need to do is to negate the condition and only keep the code in the else-clause:

if [[ ! ((`whoami` = "root" ) || ( `whoami` = "coolguy" )) ]]

Note the extra pair of parentheses, to make sure that the “!” applies to the whole thing.

(Update, May 18: Fixed HTML entities.)