"Don't worry, Bender. There's no such thing as two."
RefactorMe: This page and ZeroOneInfinityRule are about the same thing. And take care about the off topic.
Regarding YouAreGonnaNeedIt.
I frequently write a more general routine than I need at the moment, because it doesn't cost much more to make it more general. I'm guided by something IsaacAsimov wrote in "The Gods Themselves": "Two is an impossible number, and can't exist"... which means there are only three numbers: zero, one, and infinity. If you're writing a routine, and there's some possible generalization, there are only three possibilities: either you have zero cases (and why are you writing the routine), you have exactly one case (and if that's the case, you usually know it), or you have an indefinite number of cases you may have to deal with.
You have one master configuration file. But if you've got multiple users, you may want a per-user configuration file as well. Now you're going to write code to read *two* files. So it's no harder to write it to read an arbitrary number of configurations.
You're writing a SMTP server. You have it listen to port 25, and you have it listen to port 2525 when you have the debug flag set, for testing. That's two cases... add an option to listen to any arbitrary port. You don't need it now, but once you're dealing with two ports, you're dealing with an impossible number... generalize. You're gonna need it.
You're writing a mail proxy. You've added code to plug in a virus filter in front of your final delivery stage. Generalize it, allow for multiple filters. Once you've implemented two output stages, you might as well have an indefinite number... it's not any harder. -- PeterdaSilva
OK, how do I code arithmetic operations for the complex numbers? Or what should I put as a base for the Lisp-like lists instead of dotted pairs? -- NikitaBelenki
I'd describe those as records, not arrays. They happen to have a high degree of symmetry, but "1" and "i" have semantic meaning, as do "car" and "cdr". They're not fungible, operations on lists don't treat car and cdr identically. You cdr down a list for example; when examining each element, you can't arbitrarily treat i and 1 as interchangeable like you can filters or keystrokes. Similarly, if you're building a database table containing "Name" and "Social Security Number", you've got two fields in each record, but that's not a violation of this rule. -- PeterdaSilva
It is important to note that this rule is primarily applicable with respect to arrays, or things that should have been refactored into arrays (or vectors, whatever). In cases where each entry has a different role, then 2, or a specific N, occurs quite often. Consider non-commutative mathematical operators, where you have object and subject. While the operator takes 2 parameters, it is really 1 and 1 - 1 subject, 1 object. Likewise, consider TCP connections from the client perspective - 1 server, 1 client (but 2 computers involved in the connection). The TCP connections example is also good for demonstrating the reverse case: the server should not be designed for a specific number of clients, but for N clients, and leave the specification of N up to the user (or configuration administrator) at run-time, if at all, since the limit N is defined by the performance abilities of the server.
-- MartinZarate
Doesn't this also apply to database normalization? A company I worked for was designing a database where menus were linked with options, and the lead developer wanted a Menus table with Option0 through Option11. I argued with him for weeks that we should put the options into a MenuOptions? table, where the primary key is the menu key plus the option key, and the only other field is the destination. But, the only evidence I could come up with at the time was that I learned in my database administration class at DeVry that many-to-many relationships and repeating fields are bad. His argument was that we were designing a voice response system anyway and phones only have twelve buttons, so YouArentGonnaNeedIt. And it was my first paying job since high school, so guess what we went with. -- NickBensema
Actually, having columns Option0 through Option11 does not violate any NormalForm. And in your case it might be the better solution. Not only because of YouArentGonnaNeedIt, but it might be better for the performance as well. -- GregorRayman
Though it might have been slightly better to name the columns after the buttons they related to - Is "#" Option10 or Option11?
In my first job out of college, I worked on a mainframe system that tracked mental health "episodes." As all the bad things that happen to a person in a day were considered one "episode", our system used an array of 31 elements - one for each day of the month. Well, of course, requirements change: Now "episode" is each individual "attack" or symptom; so one can have more than 31 in a month. Needless to say, this made a mess of the ISAM file structure, and forced all kinds of complexity into every program that did processing on the file: Each person had zero to N records of up to 31 "episodes" each. Ick. Very ick. -- JeffGrigg
Also, didn't early caveman counting systems consist of One, Two, Many? And if I recall correctly, zero didn't gain widespread popularity until we ran into the Aztecs...
Nevertheless, it does provides a humorous addition to the endless cute names for your favorite senior DBA.
The novel WatershipDown explained that for rabbits, SixIsAnImpossibleNumber?. Young rabbits are counted as One, Two, Three, Four, Fiver (for all rabbits after the fourth).
Experiments have shown that humans have inbuilt neurological mechanisms in the visual cortex for counting up to three or four. This ability is known as "subitizing". To count more than four objects, we use higher brain functions. Experiments have also shown that some animals can subitize, but (apart from great apes perhaps) cannot count higher numbers.
Sounds like God (who, as we all know, is a Lisp programmer) tried to optimize by using prog4 instead of progn...
If I remember correct, the number of things we can distinguish WITHOUT COUNTING is normally between 6 and 9 (not 3 or four).
The use of positional numbers and zero as a place holder completes a series of discoveries leading to the current (perfect?) number system. This was thought to be discovered in India and then carried west where they became known to the Europeans as Arabic numbers. Recent dating, however, suggests that zero could have been discovered independently three times. See The UniversalHistoryOfNumbers? ISBN 0471375683 .
Also see "Zero: A Biography of a Dangerous Idea". Does a great job of explaining how the Roman Catholic church inhibited mathematical and scientific progress through its rejection of the idea of zero.
The argument of this page is based on how the universe works, not how the human mind works. Software models the universe, not (unless the bit of the universe you're modelling is a human) the human mind. In fact, now that you've brought it up, I suspect the ability of the human mind to keep track of SevenPlusOrMinusTwo things at a time is one reason people implement little arrays and then have to change them later... they're modelling the mind, not the universe. For the universe, every number past one is hrair. -- PeterdaSilva
Actually the argument of this page is based on how the human mind thinks about how the universe works. Software models the human thinking about the universe. -- nb
Charles Bair used to say "Two is an odd number", meaning that when something occurs in just two ways or when just two things are supported, there's something wrong.
This page is a somewhat roundabout restatement of the old ZeroOneInfinityRule.
Thanks for the reference.
When modeling a bicycle, you would have a list of wheels instead of 2. When modeling a marriage, you would have a list of partners and not just two? When modelling testicles, you would use a list and not two?
Unicycles, tricycles, Yanomami, and Lance Armstrong.
Unicycles and tricycles are not bicycles. Yanomami can't legally marry more than one person at a time. And you would certainly want a predefined slot for one testicle so you could say what happened to it. The actual number is not important, it's the "configured" number that is important.
Yes, but why deliberately cause the limitation? I mean, why artificially limit your bicycle-modelling system to only work on bicycles and not other, functionally identical vehicles that may possess other numbers of wheels? And remember that two isn't an impossible number when the two different objects are fulfilling different roles. A left hand cannot do the same things as a right hand, so if a person has two hands, they don't really have two - they have 1 left hand and 1 right hand. If your model of a bicycle is specific enough that you really need to know that you have exactly two wheels, than odds are it's because you're dealing specifically with the front wheel and the back wheel - in which they're conceptually separate. Only once you get a functionally homogeneous collection do you have the situation where TwoIsAnImpossibleNumber - if you're doing the same operations on every element of the collection, then you should generalize to allow any number of elements.
Men with three testicles: http://www.bbc.co.uk/wales/bllcks/facts/three.shtml
The Goodies (of which there were 3) would ride around on a vehicle called a trandem
AdolfHitler was widely reported to have only one testicle. Aaaargh! Now I've just brought GodwinsLaw into a friggin technical debate.
That said, two is appropriate for the number of wheels on a bicycle, which by definition has two wheels. Ignoring training wheels, of course... there are also many of other things with known cardinality of two (or up to two); I have never met a ConsNode? with more than two descendents, for instance. (I've met many with fewer; but that is modelled well with nil).
Without trying to be too silly, allowing for a definition of "bicycle" that reads "in-line multi-wheeled straddled pedal-propelled vehicle" (or something equally absurdly precise), the fact that they have two wheels is an engineering convenience rather than a restriction of physics. Given an adequate suspension system that flexes either the frame itself or "floats" the axles, one could easily have an "N-cycle" - at which point, full generality is achieved. -- gh
Search the web for "Tag-a-longs" or "trailercycles" and you will find that there exist "in-line multi-wheeled straddled pedal-propelled" vehicles with more than 2 inline wheels. -- RussellKent?
I may model a bicycle for convenience, however it will inherit from vehicle, which can have unlimited number of wheels or seats. A bicycle by definition has two wheels, and is not configurable. I think they mean instances where a relationship can be recursive or sequential, don't implement a fixed number. A better example would be a stack of boxes. They always have on the boxes, "Do not stack more than 2 high". Don't implement this restriction into the boxes, because what if you want to implement a box that's safe to stack three high??? Implement this restriction into the "safety check". -- LeeLouviere
The number of wheels on a truck. The number of carriages in a train.
ZeroOneInfinityRule is something deeper than just an example of RefactorMercilessly. It reflects something fundamental about modelling. Refactoring mercilessly is one way to avoid screwing up this rule. In fact, you could turn it around and say the rule is a support for refactoring...
There is an obvious analogy link between this and the BifurcationFallacy. The Bifurcation Fallacy assumes that two is not only a possible number but (in a certain set of circumstances) the only possible number.
It is interesting that people searching for signs of extra-terrestrial life assume that TwoIsAnImpossibleNumber. They often say "if we find one radio signal from an alien civilization, it would be reasonable to suppose that the Universe is teeming with life." (can't remember who or the exact quote, but it was on a Horizon program about the Seti project).
Okay, great, two means nothing when you're enumerating behaviors. But what about when you're enumerating kinds or causes of behavior? For example, what about when you have two people?
The point isn't that you can't have two people, of course you can. But if you are modeling one person, then decide that you need to extend the model to two people, it is probably silly to stop there. If you are going to generalize, generalize to N people, not two. I guess another way to put it would be this: the difference between 0 people and 1 person is fundamental; while the difference between two and three, or two and 17823, is not. Failing to understand this leads to bad design, when down the road you realize "Oh, we don't only need two people, here we need three.
One response is YouArentGonnaNeedIt, and I think the point here is that you do need it right now. It's a question of how it's implemented. If you can implement it just as easily for N units as for 2 units, it's better to implement it for N units, all other things being equal.
Of course, if you can get more for no cost, take it. But often the implementation of an arbitrary number of things can be significantly more difficult. The case with multiple column in a table instead of a second table mentioned above is a perfect example for generalization, which _can_ be premature and _can_ cost more. You can always generalize later, when you will need it. -- GregorRayman
I see two different things being discussed here. First up is the case of generalizing for the sake of robustness, second up is the case of generalizing for future-proofing, or just-in-case, or whatever. For example, if you have an array of Monkeys, you might decide to determine the size of this array by some predefined magic number MAX_NUM_MONKEYS. Of course this is madness; if not you, then one of your users WILL one day want MAX_NUM_MONKEYS+1. It costs no more effort to generalize this for N Monkeys - and YouAreGonnaNeedIt. On the other hand, thinking 'well maybe one day I'll want to store chimps as well as monkeys, in fact primates in general' is a case of YouArentGonnaNeedIt. Provided you RefactorMercilessly, when the day comes that you need to generalize for all primates, it shouldn't be a problem. -- JayBell
It's worth noting that a) in many environments (although not common today), generalizing to support any number of monkeys actually has significant cost and may not even be possible, and b) that C programmers relying on a specific number of monkeys are/were a major cause of security flaws in applications of all types, due to MonkeyBufferOverflow?.
I find that sometimes, when generalizing past two, there can be another 'natural' limit that needs consideration before MAXINT, e.g. generalizing from a request of less than 32 say, up to a range including 256. -- Paddy3118
Performance might be another issue, depending on the language you choose. I used an Array of 18 clubs to model the German bundesliga with 18*17*2 matches, and 9 matches per (logical) day and so on. I needed a constant value to initialize the array and because C++ needs to know the size of an array. I had a single point where I could change the number of clubs, to allow a new build for 19 clubs - so refactoring was simple. I could have used another collection instead of array, but arrays where damn fast. My conclusion isn't to say, that 2 is not a number, but 18 is :) - but rules have to be violated from time to time.
This is a case of ZeroOneInfinity, for a small value of infinity.
I just experienced a counterexample. During the initial development (I hesitate to call it design, because we were doing AlmostExtremeProgramming in its worst fashion), we came across a case where we thought we needed to support nested compound data schemas (in relational database terms, think of tables that support tables as a column data type). The specific case we needed was a compound within a compound, one deep. The general solution was, of course, to let compounds contain compounds across the board. A SpikeSolution to implement the general way proved to be clumsy and unworkable. We considered allowing just a single level, but TwoIsAnImpossibleNumber, and we feared that allowing this would mean that we'd have to implement the general solution six months later, so we decided not to implement this at all: since there was only one place in the software where it would help, and that place could be designed a little differently to avoid the need for it.
Recently, we ran into a situation that absolutely does require one level of compound data within compound data, similar to the case we had before. We can't design around it this time; that schema is required by external software. The general solution is still unworkable, but had we swallowed our pride originally and accepted that TwoIsNotAnImpossibleNumber, we'd be much happier.
Well, it still sounds like two is an impossible number... "The specific case we needed was a compound within a compound, one deep." That's one. Zero would be not supporting compounds in compounds at all (your original decision), and 'n' was the general solution that you found to be unworkable. How much of the unworkable solution would have been included in some form in order to allow a compound in a compound in a compound?
I've noticed that there has been some amount of confusion about what makes up the number one. But all of them so far have made more sense when you consider what 'zero' means in that context. It sure doesn't mean no levels when you need a level to hold whatever. It does mean zero relationships between levels. Like all things, it depends on what exactly you're talking about.
What about if you're modeling a soccer game? Would it really be worth your while to support more than 2 teams per game? Considering all the things that would have to change to reflect this (player AI, etc), in the real world does anybody have the time to code this? -- Michael Schurman
Again, consider what 0 and n actually mean in that case. One team (or one player in a non-team sport) implies the lack of a game: there are 0 relationships. The typical case is 1, with one interaction between teams. 'n' would be supporting many concurrent relationships, and greatly changes how strategy & tactics would work, if not scoring.
And note, outside of a single game, it is absolutely necessary to manage 'n' teams instead of 2 teams: consider a league. A simple two player game gets away with it by either making both sides identical (or trivial reflections), or by allowing a selection of 'n' options/combinations/teams for each player to choose from.
Moreover, even in a single game that is nominally between two teams, as is very common, there are game variants that allow more than two teams, as in various 3-player chess games that are not at all unpopular. To insist that "number of teams in a game = 2" means that a lot of redesign and reimplementation will be necessary if anyone ever needs to support 3 or more sides to the game. This is therefore yet another example of why arbitrary limitations should not be imposed, in the ideal. (Although admittedly YAGNI may apply if it's difficult to expand beyond 2. That's not the point here, though.) -- DougMerritt
From what I learned in analysis class in high school many years ago; sometimes infinity == 2. -- BruceIde
And from what I learned in physics class in college a couple years ago; sometimes infinity == 3. -- JonathanTang
And from what I never learned, sometimes squared 2 == 3. -- AdamBerger
See SeventeenTimesAndOnlySeventeenTimes
The idea of impossibility of two is total BS. Nikita rightly pointed to two interesting examples, complex numbers and pairs in general, from which the notions of rational numbers, functions, etc. arise. In fact, the number two is crucial in mathematics; consider Peano axiomatization of natural numbers in terms of binary operations '+' and '*'. Also consider theory of order based upon binary relations. And, finally, consider logic based upon two-state variables, and all computer science based upon that logic. Isn't it counter-intuitive that it's programmers that try to discredit "two", while measuring their boxes' memory (also bandwidth, etc.) in powers of that allegedly non-existent number? -- Igor
In that case it's interesting that the closest thing to two in Peano arithmetic is "the successor of the successor of zero", and that any statements about the addition or multiplication of arbitrary natural numbers are based on the principle of proving something that is true for N which implies that the something is also true for the successor of N. In a sense, Peano arithmetic is defined in terms of Zero, One, and the ZeroOneInfinity rule.
"TwoIsAnImpossibleNumber" isn't meant to be taken literally: it's just a consequence the ExtremeProgramming crowd's preference for using bullet-point slogans to represent their positions.
Complex numbers are (as is already stated above) a record, not a collection. And if you want to see them as a vector, then what about 3D? Mostly the same operations, but with three numbers instead of two. Thus, 2 is nothing special here. And the pairs usually model a single (thus ONE) relation/object/whatever. And the binary logic goes 0 or 1, not 2. We may have 2 conditions, but they are used to count up to 1, so we are still in the ZeroOneInfinity space!
-- KostasArvanitis?
When dealing with complex and hyper-complex numbers, you cannot just tack on more numerical components... you must also choose the precise multiplication matrix you wish to utilize (e.g. if you have 1+2i+3j, you need definitions for ij, ji, and j^2.) In this sort of situation, you cannot just generalize over an arbitrary number of possibilities without generalizing over types and describing complex-types in part with that multiplication matrix. I'd say that this applies to binary and boolean, too... and is the main reason you cannot generalize beyond the two possibilities. If you move from true:()->*|false:()->* (boolean type) to true:()->*|false:()->*|unknown:()->* (open boolean), you must handle all the functions you wish to apply to this type (and, or, not, if, etc.). If you move from binary 0 or 1 to 0 or 1 or 2, you need to handle bit-and, bit-or, bit-xor, summing on bit-arrays, etc.
Only if ALL the functions can be generalized naturally should you consider the possibility that the ZeroOneInfinity rule might apply.
The phrase "two is an impossible number" is, in my opinion, a misleading way of representing the concept actually described here. Two is certainly a necessary, and very real, number, just as pi, i, and e are necessary and very real (tongue firmly in cheek with regards to i). You can't, for example, accurately describe the hypotenuse of a right triangle whose sides are one unit long each. If you do, it'll be unnecessarily long, and more work than simply taking sqrt(2).
The concept here, as far as I can tell, is saying that as long as you're treating two as a specific, necessary constant, the same way you'd treat pi or the color green, you're fine. However, the idea is that if you have one thing, and then add something essentially similar, and you've written a system to accommodate this, it's usually pretty easy to have that system you've just written accommodate any number of additions in the same manner.
That said, the only exception to the actual concept I can point out, is that the concept of n relies on two. What I mean, is that if you have a system in which numbers greater than one do not exist (10 binary is conceptually similar to 2 arabic in this instance, and does not exist), and you have an array, you can certainly add anything you want to the array. When it comes time to /extract/ things from the array, however, since there's literally no way to index anything in the array (as they are all too similar for numbers greater than one to exist, or you wouldn't be able to group them in an array to begin with), you have absolutely no idea what you're going to extract, without popping off from the end or shifting from the beginning repeatedly.
What that means, to me, is that "one plus one is an impossible number" (I feel that's more accurate than saying two) is a fairly sound design principle, especially if what you're mainly trying to do is increase flexibility in a cost and time-efficient manner. It's not a good idea any time you're retrieving information, though.
Good for defining, bad for retrieving.
I think it's defined as :
Finite numbers are allowed to restrict the object, but not its data. Create a shape object with indefinite sides, then implement triangle on top of it. However, there's no need to implement exactly a triangle and no other shape. A triangle would have its sides stored in such a way that can support unlimited sides, but methods specific to creating triangles would only ever implement 3 sides. A triangle by definition has three sides, thus it is ONE object, and not two. TwoIsAnImpossibleNumber is about implementation, not restrictions that define objects that use said implementation. Your program may only support one triangle, or infinite triangles, but don't make a program that can only support two triangles.
English alphabet supports 26 letters, but make a generic alphabet that supports unlimited characters. That way you don't have to implement rules common to all alphabets later and your code is OnceAndOnlyOnce, and saves refactoring.
You can always split something into two aspects... but then again, you can always split it into three and get more detail... four is also good.. but five... oh five!!... I've heard legends of what six can do though.
Does this mean a BinaryTree is a bad thing? -- JonGrover
A BinaryTree with one level of nodes is an atom. Two levels of nodes is meaningless. Infinite levels of nodes is now a useful tool.
A BinaryTree isn't about handling only 2 things or a finite N things. It's about breaking a problem into smaller groups. If a binary tree was a bad thing, then so is recursion, then so it a foreach loop. Again, I might implement a tree that supports 1 to infinite branches, or I might implement a binary tree. I would never implement a binary tree and a trinary tree. Recursion is greater than Two, so don't create a binary tree that only allows 3 branchings. . -- LeeLouviere
The base case here is a "Unary Tree", better known as a LinkedList. (Nobody ever says "Zero-ary Tree", since that's a scalar, and something completely different.) Note that we tend not to use ternary (or higher) trees in practice, making this a good example of TwoIsAnImpossibleNumber: When we use higher degrees, we turn them into Binary Trees anyway. We don't directly use a 2-3-4 tree; we encode it in a binary tree as an RedBlackTree. We don't directly use a 2-3 tree; we encode it in a binary tree as an ArneAnderssonTree?. -- ScottMcMurray
And because TwoIsAnImpossibleNumber, we don't stop there. We don't directly use a 2-3-4-5-6-.... tree either: we use a left-child-right-sibling tree :)