Errata
From APIDesign
(→Chapter 19) |
(→Chapter 11) |
||
(9 intermediate revisions not shown.) | |||
Line 4: | Line 4: | ||
Read [[The_Art_of_Building_Modern_Software#Current_or_Certain.3F|the reply]]... | Read [[The_Art_of_Building_Modern_Software#Current_or_Certain.3F|the reply]]... | ||
+ | |||
+ | == Chapter 4 == | ||
+ | |||
+ | === [[Errata 4|Page 43]] === | ||
+ | |||
+ | {{:Errata 4}} | ||
== [[Chapter 6]] == | == [[Chapter 6]] == | ||
Line 15: | Line 21: | ||
{{:Errata 8}} | {{:Errata 8}} | ||
+ | |||
+ | == [[Chapter 9]] == | ||
+ | |||
+ | {{:Errata 9}} | ||
== [[Chapter 10]] == | == [[Chapter 10]] == | ||
Line 20: | Line 30: | ||
{{:Errata 10}} | {{:Errata 10}} | ||
- | == Chapter 11 == | + | == [[Errata 11|Chapter 11]] == |
- | + | ||
- | + | {{:Errata 11}} | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
== Chapter 12 == | == Chapter 12 == | ||
Line 43: | Line 48: | ||
== Chapter 18 == | == Chapter 18 == | ||
- | |||
- | Page 351 | + | ==== Page 337 ==== |
+ | |||
+ | Typo in the sample. Instead of ''throw new IllegalStateException("Old visitor used on new exceptions")'' it should be ''throw new IllegalStateException("Old visitor used on new expressions")'' | ||
+ | |||
+ | ==== Page 350 ==== | ||
+ | |||
+ | If you are wondering why, in the create30 method, the implementation of Visitor.dispatchNumber(Number n) defines RealWrapper.getValue() which calls n.getValue() and not n.doubleValue(), then it is because the class ''Number'' is not {{JDK|java/lang|Number}} but rather own implementation defined at | ||
+ | <source lang="java" snippet="visitor.clientprovider.v1"/> | ||
+ | Sorry for not choosing different name. | ||
+ | |||
+ | ==== Page 351 ==== | ||
+ | |||
+ | In paragraph Syntactic Sugar ''this'' reference is leaking from constructor so it is unsafe reference publication. In terms of [[cluelessness]] this risk should be mentioned together with link to proper explanation. | ||
== Chapter 19 == | == Chapter 19 == | ||
+ | |||
Page 361: Referring to "sealed" packages without any explanation of this term (see [[wikipedia:JAR_(file_format)]]). | Page 361: Referring to "sealed" packages without any explanation of this term (see [[wikipedia:JAR_(file_format)]]). | ||
+ | |||
+ | == [[Errata Epilogue|Epilogue]] == | ||
+ | |||
+ | {{:Errata Epilogue}} |
Current revision
Contents |
Chapter 1
p. 13, para 2 - should "at its certain revision" be "at its current revision"? --David Biesack 20:25, 5 February 2009 (UTC)
Read the reply...
Chapter 4
Page 43
On page 43, in the comment inside code example:
import java.awt.*; import java.util.*; /** Could be compiled on JDK 1.2, before java.util.List was created */ public class VList extends List { Vector v; }
Yoshiki thinks, "JDK 1.2" should read "JDK 1.1". True. Looking at List one can see "since 1.2". As such the comment should say JDK 1.1. The online sources are fixed: http://source.apidesign.org/hg/apidesign/rev/b5f24c7c2a8e
Chapter 6
Page 89
The chapter 6 discusses protected abstract methods and says that removing such method is source compatible. In fact that was true until Java 5 appeared. However the newly introduced @Override annotation changed everything.
Code from Anagrams.java:
See the whole file.public abstract class Anagrams extends javax.swing.JFrame implements UI { protected abstract WordLibrary getWordLibrary(); protected abstract Scrambler getScrambler(); public void display() { initWord(); setVisible(true); } }
If you create a new version of public abstract class Anagrams dropping either getWordLibrary or getScrambler (or both), the @Override annotation in AnagramsWithConstructor will cause the compiler to complain:
Code from AnagramsWithConstructor.java:
See the whole file.public class AnagramsWithConstructor extends Anagrams { private final WordLibrary library; private final Scrambler scrambler; public AnagramsWithConstructor( WordLibrary library, Scrambler scrambler ) { this.library = library; this.scrambler = scrambler; } @Override protected WordLibrary getWordLibrary() { return library; } @Override protected Scrambler getScrambler() { return scrambler; } }
Source compatibility is gone. As an API designer of public class Anagrams you don't know whether your users (writing class AnagramsWithConstructor) will use @Override. As a result don't even try to remove protected abstract methods from an API. It was never good idea anyway and since Java 5 it is not backward compatible.
-- Rijk van Haaften, Oct 8, 2010
Page 90
In the example of defining inserting new super class into existing class hierarchy, the whole source code should have been shown. The newly created SimpleHelloClass should define no argument method. The original HelloClass shall extend it and keep definition of the more complicated sayHelloTo method with one string argument:
Code from SimpleHelloClass.java:
See the whole file.public abstract class SimpleHelloClass { public abstract String sayHello(); }
Code from HelloClass.java:
See the whole file.public abstract class HelloClass extends SimpleHelloClass { public abstract String sayHelloTo(String who); }
Cordeo 21:47, 7 October 2010 (UTC)
Chapter 7
Page 123: For the sake of consistency with other samples and to teach reader to be defensive, lookup and ic fields should be final.
Chapter 8
Page 132
Implementation of Playback interface should be named MyPlaybackPrints instead of MyCallbackPrints.
Page 134
Yoshiki suggests to use is not well understood instead of not part of conventional wisdom as that is much clear to international speaker in the paragraph that talks why client/provider API separation is much more visible in C and very blur in Java:
In the case of C, the amount of work to produce an SPI, such as a callback, is enough to prevent a beginner from even trying it. Your knowledge has to grow significantly to attain a state where you can or need to design an SPI. However, in Java any declared method that is not private, final, or static is an invitation for someone to provide a callback and thus create an accidental SPI. Often programmers and teachers don’t clearly understand this. It’s not part of conventional wisdom (e.g. not well understood). Although Java books introduce public, nonstatic, and nonfinal methods in their first chapters, or at least as soon as they start talking about applets, they don’t provide proper warnings about all their consequences. Though that might be fine for simple development, when you start to design APIs, all the bad habits learned at the start come back to haunt you in the form of mistakes.
However the message remains the same: Make sure you separate client and provider APIs and clarify meaning of types in your API.
Page 134
There should be append method mentioned (instead of write) in this sentence: "This is reasonable behavior for implementors because those who subclassed Writer have not implemented the new write method."
Page 140
While introducing code for separating API/SPI concerns, after saying "Say the original version of Writer looked like the following:", final Writer's code is shown with one of its methods being "create(java.io.Writer)", which implies java.io.Writer's pre-existence. I am guessing that that method is there for convenience, because otherwise all java.io.Writer's method bodies should have been copied over into an Impl implementation in order to be able to run the sample source code, but for clarity, that method should probably not appear in that paragraph (maybe just in the downloadable source code with comments in its header).
True, the "create(java.io.Writer)" method is not really necessary. On the other hand it provides real world example of the API use, matching it to some API familiar to the user. It demonstrates that the new Writer is good enough replacement for the standard java.io.Writer. It shows later that by evolving the SPI to understand CharSequences the delegation to java.io.Writer can be done much more easily.
--JaroslavTulach 18:45, 31 July 2009 (UTC)
Chapter 9
Page 154
Yoshiki wanted me to clarify meaning of that, the, this in the following paragraph. So here is the rephrased version (text is bold is changed compared to original used in TheAPIBook):
Measuring the Cost of Ownership isn’t your primary focus when you want to find out why you don’t have as many developers using your library as you would like. It might be reasonable to analyze the cost of ownership, if you used to have developers and are now losing them. However, if you’re just starting and you need to attract new ones, the cost of ownership is probably not the most important criterion to use. People may trust your library more if you have a good reputation with respect to BackwardCompatibility (which reduces the cost of ownership). However optimizing the Cost of Ownership may not be your primary concern when you need to optimize for Time To Market.
Chapter 10
Page 160
Introducing the String class in re-export sample is bit artificial and decreases readability. At least it should be renamed to something like LibraryString.
There suddenly appears the Query library in the text not being introduced anywhere. Don't get confused. The only important thing to know about this library is that it is returning the re-exported String on computeReply() method call.
Page 164
The text is unfortunately silently referring to the side note story (code completion). So when you read the text first and the NetBeans stories later you can get confused slightly.
Page 173
"Because they are protected, calling them from a subclass has no meaning, as they don’t provide any implementation in the defining class." should be "Because they are abstract, calling them from a subclass has no meaning, as they don’t provide any implementation in the defining class."
--Silentfish 09:29, 10 September 2009 (UTC)
Page 178
Type parameter is bit confusing. While most of the people are familiar with single uppercase letter (like T, E, V) and can easily recognize them as a type parameter author is using Configuration and switch to C just a few lines later.
Chapter 11
Page 193
Yoshiki observed that the following paragraph should use return values instead of return types:
An unsynchronized API is usually only handy for objects that are not shared. These are objects that your calling code creates and keeps private. It's fine not to synchronize anything and to delegate access control into the hands of the API's user. An example is the java.util Collections API, and it seems to work well there. The client code only needs to be aware of the need to keep objects private and not to leak them out via method return values or calls.
Just don't let your objects escape from your local thread state!
Page 195
It would be nice for the samples to have a bit wider context. They may be too hard to understand.
Page 203
Page 203 and 207: Class names R and H are bit misleading as a single letter identifiers are usually used as type parameter names.
Page 209
Page 209: The text is referring to the side note. You should read the side note first.
Page 214
Page 214: Example of controlFlow is bit harder to understand as it is using regular expression for two lines of log without further explanation. In fact it is just manifestation of such possibility (not required for the sample in order to work).
Chapter 12
Page 231: There is no real explanation of what immutability means in Java. At least there should be link to other document on this topic.
Chapter 15
Page 274: Sample is bit unclear. It is probably a method returning boolean, but the method signature is not part of the example. RuntimeCheck is not mentioned anywhere so it is a magic function call from the reader's point of view.
Page 283: Misleading name of the type parameter in Digestor sample - Data. Single character would be much better choice.
Chapter 16
Page 298: The file containing API changeset is apichanges.xml, not apidesign.xml.
Chapter 18
Page 337
Typo in the sample. Instead of throw new IllegalStateException("Old visitor used on new exceptions") it should be throw new IllegalStateException("Old visitor used on new expressions")
Page 350
If you are wondering why, in the create30 method, the implementation of Visitor.dispatchNumber(Number n) defines RealWrapper.getValue() which calls n.getValue() and not n.doubleValue(), then it is because the class Number is not Number but rather own implementation defined at
Code from Language.java:
See the whole file.public interface Expression { public abstract void visit(Visitor v); } public interface Plus extends Expression { public Expression getFirst(); public Expression getSecond(); } public interface Number extends Expression { public int getValue(); } public static abstract class Visitor { Visitor() {} public static Visitor create(Version10 v) { return create10(v); } public interface Version10 { public boolean visitUnknown(Expression e); public void visitPlus(Plus s); public void visitNumber(Number n); } public abstract void dispatchPlus(Plus p); public abstract void dispatchNumber(Number n); }
Sorry for not choosing different name.
Page 351
In paragraph Syntactic Sugar this reference is leaking from constructor so it is unsafe reference publication. In terms of cluelessness this risk should be mentioned together with link to proper explanation.
Chapter 19
Page 361: Referring to "sealed" packages without any explanation of this term (see wikipedia:JAR_(file_format)).
Epilogue
How do you recognize Good Advice? We already know what a good technology is, can we use the same concept to evaluate whether an advice is good or not? Let me answer that by a quote from TheAPIBook which Yoshiki asked about:
Page 363
Part 1 presents all of API design as a scientific discipline with a strong rational background, not as the art that it sometimes pretends to be. It defines terminology and initial prerequisites that can objectively help us measure if an API design is good. These rules try to be language neutral and applicable to any programming language, not just Java. The theory is unlikely to be complete. Other principles of API design exist elsewhere or are still waiting to be discovered.
However, that should not scare us, as Chapter 1 gives us a tool to evaluate the quality of various principles to find out whether a certain piece of advice helps us design better shared libraries and their APIs or not. It gives us the grand meta-principle: selective cluelessness. This cluelessness is a tool that can measure whether various goals really help. That’s because if they allow people to know less while achieving more and building better software systems more easily, then this advice is good. There is a need for this advice, especially in the future, when software systems will outsize the intellectual capacity of any of their designers.
Yoshiki: What do you mean by this advice?
"this advice" is a reference to advice mentioned in "to find out whether a certain piece of advice helps us design better shared libraries". To rephrase: any advice that helps users increase cluelessness is good and it will be even more valuable in the future when we start to build even bigger systems.