A column of zero-padded account codes comes back as numbers with the zeros gone. What did the reader do, and what would have prevented it?
answer
- digits are not a type
- notation is not value
- lost at parse, not at print
- re-padding needs a fixed width
- would you ever add two of them
basics
~20 sEvery field in that column looked like digits, so the reader chose a numeric representation and parsed the characters into values. Leading zeros carry no numeric value, so they were discarded during the read. Stating the column as text prevents it.
solid answer
~50 sThe reader inspected the column, saw nothing but digits, and picked a numeric representation for it. Parsing then converts the characters into a number, and a number has no memory of how it was written: leading zeros, any plus sign, and any separators inside the field are simply not part of the value. The loss happens at the read, not at display time, so no later formatting step can reliably undo it — re-padding only works when every code is the same known width, and identifier schemes frequently are not. The fix is to tell the reader that column is text when you call it, or to give it a per-column conversion hook, so the characters are carried through as characters. The wider lesson: an identifier is not a quantity, and any column you will never do arithmetic on is a column the reader should not be allowed to guess about.
go deeper
Recall that a column of digits is not automatically numeric, and that leading zeros vanish when characters are parsed into a number. Know that you can state the column as text at the read.
Explain that the loss is at parse time and therefore usually unrecoverable, and be able to say when re-padding works and when it does not. Mention the related loss for identifiers longer than the numeric width holds exactly.
Demonstrate that you plan the identifier columns before the first read of a new feed, and can say what you would check to prove none of them was silently converted.
The angle is where this belongs: if identifiers arrive in a shape with no types in it, every consumer repeats the same declaration and one of them eventually forgets. That is an argument about what the producer emits, not about readers.
## Why this happens at all A file that stores every value as characters hands the reader a column of fields like `00471`, `00038`, `01900`. Nothing in the file says these are codes. The reader inspects some of them, sees digits and only digits, and concludes the column is numeric — which is the most useful conclusion it could draw if the column really were quantities. Having chosen, it parses. **Parsing is the point of loss.** Converting `00471` into a number produces the value four hundred and seventy-one; the two leading zeros are notation, not value, and a number does not carry its notation around. When you later look at the column you see `471`, and the characters that made it an identifier are gone from the table entirely. ## Why you cannot repair it afterwards The instinct is to format the column back: pad every value out to a fixed width with zeros. That works only when you know the width and the width is the same for every code. - If the scheme is fixed-width, re-padding recovers the original strings, and you got lucky. - If code lengths vary — some five characters, some seven — the number no longer tells you how many zeros to restore, and there is no way back from the table alone. - If a code could contain a separator, a plus sign or spacing that was significant, the same argument applies with no fixed-width escape hatch. Two neighbouring losses come from the same cause. An identifier long enough to exceed the exact range of the chosen numeric width comes back subtly altered rather than truncated at the front, which is worse because it looks fine. And an identifier that happens to contain a decimal point or an exponent marker can be read as a fractional quantity, which reprints in a form the producing system will not recognise. ## The general rule underneath **Digits are not a type.** A postal code, an account number, a product code, a national identifier, a phone number and a year-plus-sequence reference are all written with digits and none of them is a quantity. The test is not what the characters look like; it is whether you would ever add two of them together. If you would not, the column is text and should be read as text. This is the clearest case of a general property of an inferred type: **the guess is optimised for the common case and has no idea what your data means.** The reader is not wrong about the characters. It is wrong about the domain, and it has no access to the domain. ## The two fixes, and how they differ 1. **State the type at the read.** Tell the reader that column is text. It then carries the characters through untouched. This is one statement, costs nothing at read time, and is the answer in almost every case. 2. **Hand the reader a per-column conversion hook.** Some readers let you supply your own conversion for a named column. Say the hook's shape before you say its cost: if the reader hands it one field at a time, you pay a host-language call per field and the conversion, not the parse, becomes the expensive part of the read; if the same surface hands it the whole column at once, or accepts a stated type instead of a function, it runs at the reader's own speed. Use the hook when the column genuinely needs transforming, not merely to keep it as text. ## What good looks like in practice - Identify the identifier columns before the first read, not after the first wrong join. They are usually obvious from the column names. - State their types at the read, alongside whatever else you state. - Notice that this is cheap insurance in both directions: if a column you declared as text later needs to be numeric, you convert it deliberately and see the failures; if a column you let the reader guess about was destroyed, you may not find out for months. And be aware of the variation across designs, because the same file does not behave the same everywhere. Where the reader is built to guess, this bites by default. Where the reader leaves every column as text unless told otherwise, it never bites and the opposite complaint is heard — that you must state the numeric columns yourself. Where the file declares its own types, whatever the producer wrote is what you get, and the question moves to the producer. Knowing which of the three you are dealing with is the actual skill.
- Why is an identifier longer than the numeric width worse than one with leading zeros?Leading zeros are visibly missing, so somebody notices. An identifier beyond the range the representation holds exactly comes back as a nearby value of the same length — it still looks like an identifier, it joins against nothing, and every check that only looks at the shape of the column passes.
- Is converting the column back to text after the read equivalent to stating the type at the read?No. Converting afterwards operates on the parsed values, so it reproduces whatever survived the parse, not the original characters. Only stating the type at the read keeps the reader from parsing them in the first place.
Typing a phone number into a calculator. The calculator is not broken and it did not lie to you; it simply treats what you typed as a quantity, and a quantity has no leading zeros, no spacing and no country prefix. What comes back is a number that is no longer a phone number.
saying these in an interview costs you the question
- Says the zeros are only hidden and can always be formatted back
- Treats any column of digits as a numeric column
- Blames the file or the producer rather than the read
- Thinks the loss happens when the value is displayed
- Suggests converting the column back to text after the read as a complete fix
- Assumes a long identifier survives a numeric representation exactly