In a comment to Steve Yegge's blog http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.html,
Vlad Patryshev said...
Tactically, you are very right. Strategically... I don't know. You mix two things together, strict typing in general, abuse of UML and class hierarchy, and overuse of strict typing where it is not necessary (I mean JavaScript).
Regarding class structures - it's probably hard to force people that love bureaucracy not to fill their code with Managers, Handlers, Helpers, and the like (none of these does any work, but they pass it around, like in real life). But I'm afraid this anti-bureaucratic rant has nothing to do with the issue of modeling in general.
I'll give you one example, an interview problem. Write a function f on 32-bit integers that, applied twice, it negates the integer. f(f(n)) = -n.
Try to solve it without any kind of model, by just applying randomly ad-hoc xors and shifts.
9:00 PM, February 11, 2008
Assuming Vlad means integers represented in two-complement, which is the case with 99% of the processors nowadays, such a function just doesn't exist. Here's the mathematical proof.
First, in ℤ, such functions indeed exist. For example:
(defun integer/f (n)
"
Assuming n is an INTEGER, (= (- n) (f (f n)))
0 --> 0
+1 --> -2 --> -1 --> +2 --> +1
+3 --> -4 --> -3 --> +4 --> +3
...
+(2k+1) --> -(2k+2) --> -(2k+1) --> +(2k+2) --> +(2k+1)
"
(declare (type integer n))
(if (zerop n)
0
(if (plusp n)
(if (oddp n)
(1- (- n))
(1- n))
(if(oddp n)
(1+ (- n))
(1+ n)))))
The same function works in one-complement representation, too
(assuming zerop
indicates both +0 and -0).
But things are different in ℤ/m, because of the special properties of the negation in these sets.
When m=2p with p>2:
Let i be the identity function: ∀ a ∈ ℤ/m, i(a)=a
Let n be the negation function in two-complement on ℤ/2p. n is defined as: n(x) = 1+(¬x), with ¬x being the bitwise not operation.
Here are some properties of n:
Properties 3 and 4 allow partitionning ℤ/2p∖{0, M} in two symetrical subsets, one representing the positive integers, and the other their opposite negative integers.
Now, assume there is a function f such as ∃ x ∈ ℤ/2p, f(f(x))=n(x).
Let's denote the composition of functions by mere juxtaposition: fg = f○g.
Let C be the function from ℤ/2p to 2ℤ/2p such as: C(x) = { f0(x), f1(x), f2(x), f3(x) }
Now, let (a,b) ∈ ℤ/2p2, such as a ∉ {0, M}, f2(a)=n(a) and b ∉ C(a) [H]
Since a ∉ {0, M} and f2(a)=n(a), | C(a) | = 4.
And:
However, since C(0) = { 0, f1(0) }, and C(M) = { M, f1(M) }, and ℤ/2p is divisible by 4 when p>2, there is at least two other elements of ℤ/2p, let's call them N and O, such as C(O) = { O, f1(O) } and C(N) = { N, f1(N) }.
We have f2(O) = O and f2(N) = N, which shows that ∃ x ∈ ℤ/2p, f(f(x)) ≠ -x.
Conclusion: When p>2, there is no function on ℤ/2p such as f2 = n.
At most, we can find functions such as f(f(x)) = -x for all elements x of ℤ/2p but for two of our choosing. Note that we can choose to break the formula for 0 and M, since -0 is not very interesting and -M in two-complement is pathologic anyways.(For other sets, ℤ/q if q ≡ 1 [4] or q ≡ 2 [4], then there are functions such as f2=n).
Finally, we can implement a function that does almost what was asked, only with a bug: we get to choose which two values for which f(f(x)) ≠ -x.
But of course, not using only XOR and SHIFT operations! Using only NAND and SHIFT, it would be possible (since NAND is all is needed to build all the boolean operators, but XOR is not powerful enough to do so, see Wikipedia articles on Logical connective or on Functional completeness).
Technically, we don't need full functional completeness for XOR (⊻), we'd only need to be able to implement logical not and increment. For logical not, there's no problem, a ⊻ 1 = ¬a, but for increment, we need to implement a semi-adder, where s = a ⊻ b and c = a ∧ b. But there is no way to get AND from XOR, because XOR is closed over {0, 1, a, b, ¬a, ¬b, a⊻b, ¬(a⊻b)} (any application of XOR on two elements of this set gives an element of this set).
Since two-complement negation on binary words of length w is
defined as (mod (1+ (lognot n)) (expt 2 w))
, we need more
than just XOR and SHIFT... Two impossibilities for one interview
question. Vicious! And asking to do that "without any kind of
model", tskss, tskss, I wouldn't like to work at such a company,
unless the question was designed exactly for that, to weed out people
doing what they're told without thinking...
(declaim (ftype (function (integer) (unsigned-byte 32))
32-bit
32-bit/2-complement-neg))
(defun 32-bit (x)
"Mask off 32-bits of X"
(logand #xffffffff x))
(defun 32-bit/plusp (n)
"Whether N represents a positive integer."
(declare (type (unsigned-byte 32) n))
(zerop (ldb (byte 1 31) n)))
(defun 32-bit/2-complement-neg (n)
"Return the negation of N in 2-complement."
(declare (type (unsigned-byte 32) n))
(32-bit (1+ (lognot n))))
(defun 32-bit/f (n)
"
Assuming n is a 32-bit 2-complement signed integer different
from 0 and -2³¹, (= (- n) (f (f n)))
"
(declare (type (unsigned-byte 32) n))
(32-bit
(case n ; (f (f n))
((#x00000000) #x80000001) ; --> 0x80000000
((#x80000000) #x7FFFFFFF) ; --> 0x00000000
((#x7FFFFFFF) #x00000000) ; --> 0x80000001
((#x80000001) #x80000000) ; --> 0x7fffffff
;; For the above exceptions, any permutation is valid;
;; we choose here to break it for 0 and M, with
;; f(f(0))=M and f(f(M))=0,
;; to keep f(f(2³¹-1))= -(2³¹-1) and f(f(-(2³¹-1)))= 2³¹-1
(otherwise
(if (32-bit/plusp n)
(if (oddp n)
(lognot n)
(1- n))
(if (oddp n)
(+ (lognot n) 2)
(1+ n)))))))
C/USER[83]> (load"ffn=-n.lisp")
;; Loading file ffn=-n.lisp ...
;; Loaded file ffn=-n.lisp
T
C/USER[84]> (test-f)
i -i (f (f i)) (f i) (- (f (f i)))
00000000 00000000 /= 80000000 80000001 80000000
00000001 FFFFFFFF FFFFFFFF FFFFFFFE 00000001
00000002 FFFFFFFE FFFFFFFE 00000001 00000002
00000003 FFFFFFFD FFFFFFFD FFFFFFFC 00000003
00000004 FFFFFFFC FFFFFFFC 00000003 00000004
00000005 FFFFFFFB FFFFFFFB FFFFFFFA 00000005
00000006 FFFFFFFA FFFFFFFA 00000005 00000006
00000007 FFFFFFF9 FFFFFFF9 FFFFFFF8 00000007
00000008 FFFFFFF8 FFFFFFF8 00000007 00000008
00000009 FFFFFFF7 FFFFFFF7 FFFFFFF6 00000009
0000000A FFFFFFF6 FFFFFFF6 00000009 0000000A
0000000B FFFFFFF5 FFFFFFF5 FFFFFFF4 0000000B
0000000C FFFFFFF4 FFFFFFF4 0000000B 0000000C
0000000D FFFFFFF3 FFFFFFF3 FFFFFFF2 0000000D
0000000E FFFFFFF2 FFFFFFF2 0000000D 0000000E
0000000F FFFFFFF1 FFFFFFF1 FFFFFFF0 0000000F
00000010 FFFFFFF0 FFFFFFF0 0000000F 00000010
00000011 FFFFFFEF FFFFFFEF FFFFFFEE 00000011
00000012 FFFFFFEE FFFFFFEE 00000011 00000012
00000013 FFFFFFED FFFFFFED FFFFFFEC 00000013
FFFFFFFF 00000001 00000001 00000002 FFFFFFFF
FFFFFFFE 00000002 00000002 FFFFFFFF FFFFFFFE
FFFFFFFD 00000003 00000003 00000004 FFFFFFFD
FFFFFFFC 00000004 00000004 FFFFFFFD FFFFFFFC
FFFFFFFB 00000005 00000005 00000006 FFFFFFFB
FFFFFFFA 00000006 00000006 FFFFFFFB FFFFFFFA
FFFFFFF9 00000007 00000007 00000008 FFFFFFF9
FFFFFFF8 00000008 00000008 FFFFFFF9 FFFFFFF8
FFFFFFF7 00000009 00000009 0000000A FFFFFFF7
FFFFFFF6 0000000A 0000000A FFFFFFF7 FFFFFFF6
FFFFFFF5 0000000B 0000000B 0000000C FFFFFFF5
FFFFFFF4 0000000C 0000000C FFFFFFF5 FFFFFFF4
FFFFFFF3 0000000D 0000000D 0000000E FFFFFFF3
FFFFFFF2 0000000E 0000000E FFFFFFF3 FFFFFFF2
FFFFFFF1 0000000F 0000000F 00000010 FFFFFFF1
FFFFFFF0 00000010 00000010 FFFFFFF1 FFFFFFF0
FFFFFFEF 00000011 00000011 00000012 FFFFFFEF
FFFFFFEE 00000012 00000012 FFFFFFEF FFFFFFEE
FFFFFFED 00000013 00000013 00000014 FFFFFFED
FFFFFFEC 00000014 00000014 FFFFFFED FFFFFFEC
7FFFFFEC 80000014 80000014 7FFFFFEB 7FFFFFEC
7FFFFFED 80000013 80000013 80000012 7FFFFFED
7FFFFFEE 80000012 80000012 7FFFFFED 7FFFFFEE
7FFFFFEF 80000011 80000011 80000010 7FFFFFEF
7FFFFFF0 80000010 80000010 7FFFFFEF 7FFFFFF0
7FFFFFF1 8000000F 8000000F 8000000E 7FFFFFF1
7FFFFFF2 8000000E 8000000E 7FFFFFF1 7FFFFFF2
7FFFFFF3 8000000D 8000000D 8000000C 7FFFFFF3
7FFFFFF4 8000000C 8000000C 7FFFFFF3 7FFFFFF4
7FFFFFF5 8000000B 8000000B 8000000A 7FFFFFF5
7FFFFFF6 8000000A 8000000A 7FFFFFF5 7FFFFFF6
7FFFFFF7 80000009 80000009 80000008 7FFFFFF7
7FFFFFF8 80000008 80000008 7FFFFFF7 7FFFFFF8
7FFFFFF9 80000007 80000007 80000006 7FFFFFF9
7FFFFFFA 80000006 80000006 7FFFFFF9 7FFFFFFA
7FFFFFFB 80000005 80000005 80000004 7FFFFFFB
7FFFFFFC 80000004 80000004 7FFFFFFB 7FFFFFFC
7FFFFFFD 80000003 80000003 80000002 7FFFFFFD
7FFFFFFE 80000002 80000002 7FFFFFFD 7FFFFFFE
7FFFFFFF 80000001 80000001 00000000 7FFFFFFF
80000013 7FFFFFED 7FFFFFED 7FFFFFEE 80000013
80000012 7FFFFFEE 7FFFFFEE 80000013 80000012
80000011 7FFFFFEF 7FFFFFEF 7FFFFFF0 80000011
80000010 7FFFFFF0 7FFFFFF0 80000011 80000010
8000000F 7FFFFFF1 7FFFFFF1 7FFFFFF2 8000000F
8000000E 7FFFFFF2 7FFFFFF2 8000000F 8000000E
8000000D 7FFFFFF3 7FFFFFF3 7FFFFFF4 8000000D
8000000C 7FFFFFF4 7FFFFFF4 8000000D 8000000C
8000000B 7FFFFFF5 7FFFFFF5 7FFFFFF6 8000000B
8000000A 7FFFFFF6 7FFFFFF6 8000000B 8000000A
80000009 7FFFFFF7 7FFFFFF7 7FFFFFF8 80000009
80000008 7FFFFFF8 7FFFFFF8 80000009 80000008
80000007 7FFFFFF9 7FFFFFF9 7FFFFFFA 80000007
80000006 7FFFFFFA 7FFFFFFA 80000007 80000006
80000005 7FFFFFFB 7FFFFFFB 7FFFFFFC 80000005
80000004 7FFFFFFC 7FFFFFFC 80000005 80000004
80000003 7FFFFFFD 7FFFFFFD 7FFFFFFE 80000003
80000002 7FFFFFFE 7FFFFFFE 80000003 80000002
80000001 7FFFFFFF 7FFFFFFF 80000000 80000001
80000000 80000000 /= 00000000 7FFFFFFF 00000000
NIL
C/USER[85]>