3 ms·
> Richard P. Gabriel critiqued this notion of "patterns should be abstracted and instantiated" I think patterns should always be "abstracted and instantiated".
by malisper 12y ago
> Richard P. Gabriel critiqued this notion of "patterns should be abstracted and instantiated"
I think patterns should always be "abstracted and instantiated". I always found his example of actual code in support of his argument a bit weird. From the book:
Does the following code fragment:
(mismatch sequence list :from-end t
:start1 20 :start2 40
:end1 120 :end2 140 :test #’baz)
seem easier to understand than this pattern of use:
(let ((subseq1 (reverse (subseq sequence 20 120)))
(subseq2 (reverse (subseq list 40 140))))
(flet ((the-same (x y) (baz x y)))
(loop for index upfrom 0
as item1 in subseq1
as item2 in subseq2
finally (return t) do
(unless (the-same item1 item2)
(return index)))))
Gabriel then goes on to argue that the advantages of the first one (that it is more efficient and more compact) go away once faster computers and good editors are thrown into the mix. I completely disagree with this. Just try to figure out what test is being used in the second example. The first example clearly says:
:test #'baz
That tells me that the test is baz. In the second example, there is no such indication. You have to actually parse the entire piece code to figure out where the test is. This makes a huge difference not only in reading code, but also in debugging code. There are many more things that could go wrong in the second piece of code than in the first. If there was a bug in both examples, it would be much easier to find it in the first example since there is so much less of it. This is just like Hoare's saying, "There are two ways to write code: write code so simple there are obviously no bugs in it, or write code so complex that there are no obvious bugs in it". In the first example there are obviously no bugs since the code is so simple. In the second, it is much harder to tell since there are so many more things going on than in the first.
- mbrock 12y agoI wouldn't claim conclusively that the second version is better, but I see Gabriel's point. Yes, the first version is elegant, and it is easier to spot the predicate—but I also can't tell you exactly how the predicate is used, because I don't know the definition of MISMATCH. For example, should a positive result from BAZ mean that the items are the same? There's no way to tell. You could argue that this is because of poor keyword argument naming, but that's part of the point: in the second version, there's no need for such considerations, because the use is explicit. (Consider yourself lucky that the function uses keyword arguments to begin with!) Nor do I agree that the first example is obviously bug-free. How would I know? The definition of the actual logic is in some other file. Yes, that's true for the library functions used in the second example, but those are standardized. Other examples of ambiguities: Are START1 etc counted from the end of the list or from the beginning? What happens if there are several mismatches? What's the time complexity? Etc. Of course these would be part of the documentation, in an ideal world. I should point out that Gabriel isn't arguing that patterns should not be abstracted (or "compressed"), only that there are tradeoffs.