Skip to content

Commit fd18a6b

Browse files
committed
Extend the section about proper types
Fixes #24.
1 parent cb7f0ac commit fd18a6b

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

rules/0100-Writing-a-kata.md

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Follow your language's naming conventions
6262
-----------------------------------------
6363

6464
Every language has its quirks. Some of them get discussed in the later sections.
65-
However, there's one thing that should get mentioned at this point:
65+
However, there's one thing that should get mentioned at this point:
6666
**make sure to use your language's proposed naming convention, if there exists
6767
one.**
6868

@@ -140,9 +140,23 @@ format your code. You don't want to have something like the aforementioned
140140
[GFM]: https://help.github.com/articles/github-flavored-markdown/
141141
[ragged]: https://en.wikipedia.org/wiki/Typographic_alignment
142142

143+
143144
Use the proper types whenever possible
144145
--------------------------------------
145146

147+
Types are everywhere. Even if you use dynamic typed languages, you've at
148+
least encountered some quirks of your language, like `"12345" + 1` in
149+
JavaScript, or "xy isn't a ab" in Python or Ruby.
150+
151+
There are basically two things that can go wrong with types: you can
152+
ask the user for the wrong return type, or __you__ accidentally use
153+
the wrong type in your reference solution.
154+
155+
The second one is a lot harder to notice, so lets keep this for later.
156+
Instead let us look at one often used wrong return type first: the string.
157+
158+
### The problem with strings
159+
146160
Have a look at the following function:
147161

148162
```java
@@ -185,6 +199,78 @@ the argument a string, or the return value. But use those strings with care. If
185199
possible, use the proper type and avoid string, unless it leads to convoluted code.
186200

187201

202+
### The wrong return type
203+
204+
Even if you don't use strings, you can end up with the wrong type. Let us
205+
motivate this with an example.
206+
207+
The Fibonacci sequence is defined as follows
208+
209+
$$
210+
f_n = \begin{cases}
211+
1 & n = 1\\
212+
1 & n = 2\\
213+
f_{n-1} + f_{n-2} & \text{otherwise} \\
214+
\end{cases}
215+
$$
216+
217+
Now, lets say you want a user to write a function that returns arbitrary
218+
Fibonacci numbers up to `N = 100`:
219+
220+
``` c
221+
int32_t fibonacci(int8_t N);
222+
```
223+
224+
You might already note where I'm going with this, if not, read on.
225+
Lets have a look at $f_{45}$, $f_{46}$ and $f_{47}$:
226+
$1134903170, 1836311903, 2971215073$. And if you're familiar with the bounds
227+
of signed 32bit integer numbers, you should already see the problem.
228+
229+
The number $2971215073$ cannot get represented with 32 bits (if signed integers
230+
are used), since $\log_2 (2971215073) > 31$. If you were to ask the user for
231+
$f_{50}$ (or even $N = 100$), you (and they!) end up with a wrong answer:
232+
233+
``` c
234+
printf("f 47: %d\n", fibonacci(47));
235+
// prints -1323752223
236+
```
237+
238+
This indicates that `int32_t` isn't enough for your kata. Even `uint64_t` isn't,
239+
since $\log_2 (f_{100}) > 64$,
240+
so you have to switch to your languages `BigInteger` variant, e.g. `BigInt`,
241+
`bignum`, `Integer`.
242+
243+
By the way, this particular error could have been prevented by a test that
244+
checks that every returned number is positive. Also, if you use a dynamic
245+
typed language, make sure to check the return type in one of the first tests:
246+
247+
``` ruby
248+
Test.expect (fib(0) is Bignum, "Your function doesn't return a BigNum")
249+
```
250+
251+
### Wrong internal types
252+
253+
This is usually a mess. Your return type is correct, and you check for the
254+
correct type, but your users complain about invalid results. This indicates
255+
that you accidentally used the wrong type somewhere in your own computation,
256+
for example `int16_t` in a helper function. This is __really__ hard to spot,
257+
so you should add some static test values. More on that in the later sections.
258+
259+
### Integral vs floating point arithmetic
260+
There's a later section on floating point numbers, but this section is also
261+
fitting for the delicate problem. As you (hopefully) know, floating point
262+
arithmetic isn't exact. The usual double value has 54 bits for its significant,
263+
which is better than `int32_t`, but worse than `int64_t`. So if you ask for an
264+
__exact__ solution, you should ask for an integral type and also check
265+
that the user returns an integral type (in dynamic typed languages).
266+
267+
Note that JavaScript doesn't really differ between integral and floating point
268+
numbers. You can force numbers to behave as `int32` (or `uint32`), but you
269+
cannot help the user with an appropriate error message in this case.
270+
271+
Also, JavaScript doesn't have a large integer class/type, so you need to
272+
improvise a little bit.
273+
188274
Use the preloaded section only for helpers or constraints
189275
---------------------------------------------------------
190276
The preloaded code is both usable by you and the user. It's the perfect place to

0 commit comments

Comments
 (0)