If that were exactly true, how would you explain chess?
Chess is a game. It is abstract and defined by rules.
No dice.
Everything is a game; that's why John Nash became famous. See
game theory. In a very real, mathematically provable sense, all interactions between rational beings can be modeled as games (with "win" or "lose" similarly arbitrarily selectable); even the definition of
game in game theory is "interactions between rational beings". There is no "play" or "pretend" implied or assumed here.
Choice is the key. See
combinatorial explosion.
Simply put, if you have Conway's Game of Life with four rules, an
m by
n world, the information it contains is just 2
mn (plus the information needed to store the rules, which I believe is either 256 or 512 bits for any possible rule set involving only the nearest neighbor cells), no matter how long the world would evolve.
Consider a simple game on a
m by
n board, where each player gets to move their piece one step in any of the four cardinal directions. Ignoring the minute difference whether we allow or deny them occupying the same position, the board has 2
2mn possible states. However, because of having the ability to choose, the
sequence of position over
K turns is much larger. Even if you add a hundred rules, the size of the phase space of all possible sequences – the amount of information required to describe such a game – is infinitely larger. If there is no stop conditon, it is infinite. The only reason chess has a limited phase space, is because it has rules/stop conditions regarding cyclicity (
impasse, I think? I'm too stupid to be much good at chess myself).
Consider what I wrote above about C pointers. They basically have no rules the C compiler enforces. If you want a pointer of qualified type
TYPE to point to address
ADDRESS given as either a pointer or a numerical address (compatible to
intptr_t or
uintptr_t type), then you do
(TYPE *)(ADDRESS).
I have claimed based on limited personal observation that the majority of bugs related to C pointers stem from not seeing anything wrong or suspect in such expressions.
So, we
derive rules, based on observations of such expressions. Mine can perhaps be summarised as
- Make sure the target address is valid, that it points to what I think it does.
- Make sure the target address is sufficiently aligned for the hardware requirements.
- Make sure the entire address range implied by the pointer is valid. A four (say, uint32_t) or eight-byte (say, uint64_t) access even at a sufficiently aligned address in a byte buffer may not be valid, if the content in the buffer does not cover the entire accessed element.
- Record your assumptions, and if reasoning was required, the basis of that reasoning in a comment. It serves as an orthogonal support for the maintenance of the code (describing important features not described by the code itself), as well as a tool for organizing ones thoughts (rubber duck): it saves total effort.
- Record the basis of expressions that are the result of effective simplification from an originally complicated form. The originally complicated form may express assumptions and logic that are not expressed in the effective simplified form.
As a mathematical example, consider the sum of n consecutive integers starting at k. This simplifies to k n + (n2 - n)/2. This simplified form does not imply the sum; therefore if the sum is the mathematical/logical thing needed to express or evaluate, just having the simplified form loses significant amount of information needed for a developer to see whether the code implements the logic the author intended it to or not. Including the original reason (sum of n consecutive integers starting at k) as a comment, lets further developers verify the implementation, and possibly even replace this local optimization with a higher-level algorithmic one (one that eliminates the need for any calculation of this sort, typically).
I understand if your beef is with the definition of what is a "rule", "law", "rule of thumb", et cetera; but fact is, reality trumps theory and words every single time.
Words are only tools, not primary things – think of Magritte's The Treachery of Images (
Ceci n'est pas une pipe) – and it is at the very core of what I am suggesting here; and the "rules" we are talking about here are not the kind of rules that restrict choice, these are the sort of rules that help people estimate the effects of any given choice.
Hell, I even tried to allude to this directly in my long example code snippet, in the fact that even it was in a long-ass paragraph describing why one would deliberately set a pointer NULL after freeing or handing it off to another entity taking responsibility for it, I deliberately omitted it and even added a comment why, near the very end!
I'm familiar with this, because every single
rational physicist who sees "laws of physics" knows they're not, in any sense of the "law"; except in that one rarely used or understood sense which means "if you choose to behave this way – or apply this model to phenomena you see – you should succeed and prosper". Or whatever the correct idiom/saying in English is. Me no English good today.