Smalltalk Best Practice Patterns
Rate it:
Open Preview
Read between December 3 - December 10, 2016
13%
Flag icon
Constructor Method
Jaaved Ali Khan
o: smalltalk does not distinguish between methods - there are no special methods in smalltalk. In Java there is a special method for construction. In python classmethods can be used to create alternate constructors. This 'constructor method' pattern is still applicable to languages like Python and Java.
13%
Flag icon
The alternative is to make sure that there is a method to represent each valid way to create an instance. Does this result in a proliferation of instance creation methods? Almost never. Most classes only have a single way to create an instance. Almost all of the exceptions only have a handful of variations. For the rare case where there really are hundreds or thousands of possible correct combinations of parameters, use Constructor Methods for the common cases and provide Accessor Methods for the remainder.
14%
Flag icon
If the method takes parameters, you will need a Constructor Parameter Method (p. 25). Give your method an Intention Revealing Selector (p. 49) that describes the roles of the parameters, not their type. A Constructor Method that is used extensively may deserve a Shortcut Constructor Method (p. 26).
Jaaved Ali Khan
info about the role of the parameter is more important than there type. Type info can infered from the context.
14%
Flag icon
^self Note the Interesting Return Value in setX:y:. It is there because the return value of the method will be used as the return value of the caller.
16%
Flag icon
• Convert from one object to another rather than overwhelm any one object’s protocol.
16%
Flag icon
I avoid the protocol explosion problem by only representing conversions with a message to the object to be converted when: • The source and destination of conversion share the same protocol. • There is only one reasonable way to implement the conversion. • Provide a method in the object to be converted that converts to the new object. Name the method by prepending “as” to the class of the object returned. Here are some examples. Notice that the object returned has the same protocol as the receiver (Sets act like Collections, Floats act like Numbers). Collection>>asSet Number>>asFloat
16%
Flag icon
• Make a Constructor Method that takes the object to be converted as an argument. For example, Date class>>fromString: is a Converter Constructor Method. It takes the String to be converted as an argument and returns a Date. Put Converter Constructor Methods in a protocol called “instance creation.”
17%
Flag icon
There are actually two decisions here. The first is deciding what to return from a method that tests a property. The second is what you should name the method.
17%
Flag icon
That leaves clients needing to know how Switch stores its status:
17%
Flag icon
It is far easier to maintain a relationship based solely on messages. Rather than status returning a Symbol, it is better for Switch to provide a single method that returns a Boolean; true if the Switch is on and false if the Switch is off.
Jaaved Ali Khan
**: name of the message should describe what gets returned instead of the return value.
17%
Flag icon
However, this leads to confusion. Does “on” mean “is it on?” or “make it on?”
17%
Flag icon
• Provide a method that returns a Boolean. Name it by prefacing the property name with a form of “be”—is, was, will, etc. Here are some examples from Smalltalk: isNil isControlWanted isEmpty
Jaaved Ali Khan
*
17%
Flag icon
Comparing Method • How do you order objects with respect to each other?
18%
Flag icon
Reversing Method A Composed Method (p. 21) may not read right because messages are going to too many receivers. You may have a Cascade (p. 183) that doesn’t look quite right because several different objects need to receive messages.
18%
Flag icon
Here we have messages going to three different objects. We want to read this as a three part operation, but because the operations are on three different objects it is hard to put the pieces together. We can solve the problem by making sure that all messages go through a single object. However, creating new selectors just for the fun of it is a bad idea. Each selector in the system must justify its existence by solving a real problem; encoding an important decision.
18%
Flag icon
Adding a new method with a new selector to make code read more smoothly is a good use of the selector namespace. • Code a method on the parameter. Derive its name from the original message. Take the original receiver as a parameter to the new method. Implement the method by sending the original message to the original receiver. By defining Stream>>print:, we can smooth out the above method: Stream>>print: anObject           anObject printOn: self Point>>printOn: aStream           aStream                     print: x;                     nextPutAll: ‘ @ ‘;                     print: y
18%
Flag icon
However, I often find that the desire to use it is followed closely by the absolute need to use it. As soon as you have all the messages going to a single object, that object can easily vary without affecting any of the parameters.
19%
Flag icon
You have a method that does not simplify well with Composed Method (p. 21).
19%
Flag icon
Far from improving communications, applying Composed Method to such a method only obscures the situation. Since all the parts of such a method generally need all the temporary variables and parameters, any piece of the method you break off requires six or eight parameters.
19%
Flag icon
The solution is to create an object to represent an invocation of the method and use the shared namespace of instance variables in the object to enable further simplification using Composed Method. However, these objects have a very different flavor than most objects. Most objects are nouns, these are verbs. Most objects are easily explainable to clients, these are not because they have no analog in the real world. However, Method Objects are worth their strange nature. Because they represent such an important part of the behavior of the system, they often end up at the center of the ...more
19%
Flag icon
This is the last pattern I added to this book. I wasn’t going to include it because I use it so seldom. Then it convinced an important client to give me a big contract. I realized that when you need it, you REALLY need it.
19%
Flag icon
Class: TaskSender           superclass: Object           instance variables: obligation task job notProcessed processed copied executed
Jaaved Ali Khan
method object with verb phrase name: TaskSender not a noun.
20%
Flag icon
Execute Around Method • How do you represent pairs of actions that have to be taken together?
20%
Flag icon
• Code a method that takes a Block as an argument. Name the method by appending “During: aBlock” to the name of the first method that needs to be invoked. In the body of the Execute Around Method, invoke the first method, evaluate the block, then invoke the second method.
Jaaved Ali Khan
If there methodA, methodB and methodC. and methodB is variable, methodA and methodC are required to be executed everytime before methodB. Then create an execute around method with name as "DuringMethodA" and pass the methodB - or the code of the methodB as block- and execute it. Use exception handeling to make sure that the mehtodC gets executed everytime. But in python I thing with block does exactly this.
21%
Flag icon
The two audiences for strings generated by objects, you and your client, are often in conflict. You want all the internal, structural details of your object laid out in one place so you don’t have to go searching layers and layers of objects to find what you want. Your client assumes the object is working correctly and just wants to see externally relevant aspects of the object in the string.
Jaaved Ali Khan
Indirectly this give the reason why in python __repr__ and __str__ methods are needed.
21%
Flag icon
VisualWorks has taken the valuable step of separating these two uses of object-to-string conversion. If you want a client-consumable string, you send “displayString.” If you want a programmer-consumable string, you send “printString.” For Smalltalks with a single message for printing, you need to choose which audience you will address.
Jaaved Ali Khan
analogy: Python __repr__ __str__ Smalltalk printString displayString
22%
Flag icon
Communicate important information that is not obvious from the code in a comment at the beginning of the method.
22%
Flag icon
• To-do—I often write comments while I am prototyping to remind myself of some thought I don’t want to lose.
23%
Flag icon
This section talks about the tactical ways you can use the message stream. It gives you a toolbox of techniques for solving problems by manipulating the communication between objects.
Jaaved Ali Khan
Purpose of this section
23%
Flag icon
Messages provide a disciplined way to handle theme-and-variation programming. Because the variations live in different objects, they have much less opportunity to interfere with each other than just putting the variations in different parts of the same routine. The client, the object invoking the variations, is also isolated from what variation is currently active.
24%
Flag icon
Decomposing Message You are using a Message (p. 43) to break a computation into parts. • How do you invoke parts of a computation?
24%
Flag icon
A Choosing Message gets work done. It is the equivalent of a case statement in procedural languages. Depending on the circumstance, different code is invoked.
Jaaved Ali Khan
polymorphism
25%
Flag icon
ParagraphEditor>>highlight: aRectangle           self reverse: aRectangle What’s going on? Communication.
Jaaved Ali Khan
calling a method with a better intention revealing name or intention revealing message.
25%
Flag icon
I could mechanically replace all the invocations of highlight with invocations of reverse. The code would run the same. However, all the invoking code reveals the implementation—“I highlight by reversing a Rectangle.”
25%
Flag icon
The other advantage of code written to reveal intention and conceal implementation is that it is much easier to refine by inheritance.
25%
Flag icon
Here are some examples of Intention Revealing Messages and their implementation: Collection>>isEmpty           ^self size = 0 Number>>reciprocal           ^1 / self Object>>= anObject           ^self == anObject
Jaaved Ali Khan
example: intention revealing messages. method call signature or names in Python or Java
26%
Flag icon
The second option is to name a method after what it is supposed to accomplish and leave “how” to the various method bodies. This is hard work, especially when you only have a single implementation. Your mind is filled with how you are about to accomplish the task, so it’s natural that the name follow “how.” The effort of moving the names of method from “how” to “what” is worth it, both long term and short term. The resulting code will be easier to read and more flexible. • Name methods after what they accomplish.
Jaaved Ali Khan
Method name should describe what not how. How is implementation detail which should be defined by actual code not by name.
26%
Flag icon
Here’s a simple exercise that will help you generalize names of messages with a single implementation. Imagine a second, very different implementation. Then, ask yourself if you’d give that method the same name. If so, you’ve probably abstracted the name as much as you know how to at the moment.
Jaaved Ali Khan
heuristic:
26%
Flag icon
Dispatched Interpretation
30%
Flag icon
Jaaved Ali Khan
1) Super 2) Extending Super and 3) Modifying Super patterns are implemented as special methods in Python and Java. Just follow those methods while using these patterns.
33%
Flag icon
We’ll ignore the arithmetic nature of Vectors and focus on how it delegates. Sometimes, clients want to treat a Vector as a Collection of Numbers. When someone iterates over a Vector, it delegates to its “elements” instance variable: Vector>>do: aBlock           elements do: aBlock This is an example of Simple Delegation. You can imagine implementing at:, at:put:, size, etc. the same way.
Jaaved Ali Khan
delegating the messages or method call to the methods of objects referenced by intance variables.
34%
Flag icon
• Pass along the delegating object (i.e. “self”) in an additional parameter called “for:”
34%
Flag icon
Pluggable Behavior • How do you parameterize the behavior of an object?
34%
Flag icon
Classes are an opportunity. Each one will be useful to instantiate and/or specialize. However, each class you create places a burden on you, as the writer, to communicate its purpose and implementation to future readers. A system with hundreds or thousands of classes will intimidate a reader. Managing a namespace across many classes is expensive. You would like to invoke the costs of a new class only when there is a reasonable payoff. A large family of classes with only a single method each is unlikely to be valuable.
Jaaved Ali Khan
Pros and cons of creating a class.
37%
Flag icon
Collecting Parameter You have written an Intention Revealing Selector (p. 49). • How do you return a collection that is the collaborative result of several methods?
38%
Flag icon
Most state-related decisions have more to do with modeling and less with coding, so the patterns here don’t tell anything like the whole story.
38%
Flag icon
This section talks about two kinds of state: instance variables and temporary variables. Of the two, temporary variables are covered much more thoroughly because they are a complete artifact of coding, living only as long as a method is computing.
38%
Flag icon
The problem is that temporary variables really are all about coding. They are a tactical solution to a tactical problem. Thus, they fit very well in the scope of this book.
Jaaved Ali Khan
Temporary variables are all about coding.
39%
Flag icon
The decision to create an instance variable usually comes from a much different mind-set and in a different context than the decision to create a temp.
39%
Flag icon
The stored program computer changed all this. Now, the manipulations and the state were on par. They were both virtual parts of the same machine, stored as charges that could easily be changed.