James Kuyper said:
Not quite, for two different reasons. Firstly, any set where it is
practical to count all of the elements is a countable set
Secondly, while even some fairly small countable sets can be impractical
to count (the number of grains of sand in a sand box, for instance), the
potential problem with some countable sets is much worse than simply a
matter of impracticality. For many countable sets, you can start
counting the elements, and never run into a problem that requires you to
stop counting them, but you'll also never finish counting them, no
matter how fast you count the, and no matter how long you continue
counting. That's the in-joke in the mathematician's definition of
"countable": infinite sets such as the whole numbers can be countable.
The phrase "countably infinite" would have been more precise.
An infinite set is countable if you can iterate of the set so that
there's no element that isn't reached after a finite number of
iterations. That doesn't mean that the set is finite. For example,
the positive integers are a countably infinite set; you can never
count them all, but if you start counting from 1, there is no value
that you won't reach in some finite time. The set is infinite,
but none of its memers are.
The set of mathematical real numbers is uncountably infinite.
You can start counting them in some order, but any order you choose
will omit some numbers.
Rational numbers are countably infinite. So are algebraic numbers.
So is the set of all numbers that can be expressed in mathematical
notation.
The set of valid C types is countably infinite, though the set of C
types that can be handled by any real-world implementation is finite
(you're going to run into capacity limits).
So providing distinct overloaded versions of free() for all pointer
types would be impossible. Providing overloaded versions for some
finite set of pointer types (say, those that can be expressed in
less than 1000 characters of C) would be utterly impractical.
It would be possible to create an implicit overloaded free() function
for each call that occurs in a given program (assuming a version of C
that supports overloading), or to make free an operator like sizeof,
or to use C++-style templates. The designers of the language didn't
follow any of those paths. The reasons are largely historical.
Basically, memory allocation was implemented in library code before
there was an opportunity to build it into the language. Once that
was done, there wasn't much point in going back and changing the
language itself.
[...]