• Aucun résultat trouvé

Other Coding Guidelines

Dans le document The Art and Science of Smalltalk (Page 161-164)

Having looked at Smalltalk naming conventions, how to access variables and constants and how to structure methods in Smalltalk, we'll consider a collection of other coding guidelines. All of these come under the category of common sense. This means that whilst they are generally useful, there will always be specific circumstances in which you'll want to do something different.

Variables with Discrete States

Always use false and true if you are dealing with a boolean state, and not 0 and 1, or nil and some non-nil object. Tests for these values are optimised by the compiler (which by the way means that their definitions are one of the few pieces of code you can't alter). It also makes your code say directly what you want, especially if you name your variables appropriately (isCooked, wasRaw, etc.)

If you have a need for a variable which takes a fixed number of values, try to use a symbol (not a string—symbols are more efficient since they are unique and can be compared with ==) rather than say a number to encode this value. For example use #large, ftmedium and ttsmall, to describe something's size rather than 3 , 2 and 1 to encode it. In the following three expressions, consider how much easier it is to Understand what the second is doing than the first. The third expression is easier still and becomes available if you write a method called isLarge which encapsulates the size = # large test and returns either true or false .

MyObject size = 3 ifTrue; ["do something"1.

MyObject size = ftlarge ifTrue: ["do something"].

MyObject isLarge ifTrue; ["do something"].

Using Dictionaries

Dictionaries are one of the most useful building blocks in the standard class library. It's easy to conceive of using them as a simple data structure to hold pairs of objects, organised as 'name', and 'object'. But remember that dictionaries can hold any kind of object. This makes much more complex and powerful uses possible. For example, a dictionary may be used as a kind of control structure by putting blocks in as the values, and some other objects as the keys. This allows a kind of 'case' statement to be constructed if you wish. The first expression

Coding in Smalltalk

below shows a dictionary being initialised in this way (which need only happen once), and the second expression shows the way in which it might be used:

MyDict at: #Small put: ["do a small thing"];

ati ^Medium put: ["do a medium thing"];

at: #Large put: ["do a large thing"].

(MyDict at: case) value.

Managing Unique Objects

Sometimes you might think you'll only ever need one object of a particular type in a program. For example, you might need an object whose job it is to manage some kind of unique resource—the filesystem, a central look-up table, or perhaps an external interface. In these circumstances it is very tempting to make this object a class. In other words, it seems logical to create a special class and write class methods which do the work of this object, especially if the object really needs a unique name which is well known throughout the system (just like a classname).

This way of creating such an object is not the best however. A much better approach is to create the class, and create a single instance of it to do the work. The main reason for this is that you can never really be sure that you (or someone else) won't one day want to make more than one instance of this apparently unique object. It also means that your unique object inherits only the functionality of instances, and not the inappropriate functionality of classes. Remember that inheriting only the appropriate functionality is one of the guidelines you should use when designing classes.

In practice, the standard way to deal with this situation is to create the class and give it a class variable called Default. Then create a class method called initialize which initialises this variable to hold the required single instance of the class. Finally, create a class method called default, which returns the value of the class variable Default. Then, when the rest of your code wants to use this object it can refer to it using the expression MyClassHame default. Now if you or anyone else wants to create more instances of the class you are free to do so. You may or may not then want to create additional class variables to hold these instances. To find examples of classes which use this way of structuring code use the Browse—>implementors of...

command from the launcher to browse the implementors of default.

Unwinding Actions

Sometimes it is important to undo actions you have taken, especially if an exception occurs. The classic example is closing a file which has been opened, but in. Smalltalk, terminating processes which have been started is equally as important. The class BlockClosure provides a way of doing this in the form of a method called valueMowOrOnUnwindDo: . If you send this message to a block with another block as the parameter, the system will execute the first block, and then the second, even if the first block results in an exception. This is very useful for keeping things tidy during development—making sure you don't end up with hundreds of open files, windows, or processes running.

Another way to avoid these problems is to encapsulate the opening of a file, or the spawning of a process, in your own method. Make sure you keep a reference to the file or process (say in an instance variable), and each time you invoke the method, check whether a file is open or a process running, and close it or kill it before opening another.

Modifying System Classes

Smalltalk's provision of the entire set of source-code for its implementation explicitly gives you permission to modify the system classes. This is a very powerful facility, and like all such facilities it should be treated with respect. It is absolutely not the case however that you should never modify a system class.

If you want to add simple functionality, such as new features in the development tools, you should go right ahead. This kind of modification by programmers is what has made the development environment as powerful as it is, so if you think you can improve it further, don't hesitate. If you don't like something, change it.

If you're planning on making modifications to some of the more fundamental classes such as Object or Behavior, you might want to be more circumspect. There are two dangers—you might break the system, and you might put in changes which are incompatible with someone else's changes.

Look at whether you can achieve the effect you want without modifying the system classes. Look also at how the change you want to make might interact with other changes. Finally, consider how serious you are about changing the way Smalltalk behaves in fundamental ways. If after taking these considerations into account you still want to modify the system classes, then go cautiously ahead.

Coding in Smalltalk

One of the most powerful features of Smalltalk is the ability to extend the language if you wish. You can (and people do) add persistent storage mechanisms, create distributed object systems, change the way the UI works, even change the way inheritance works, all by modifying the system classes. The designers of Smalltalk intended this to be possible. Just remember the kind of responsibility you're exercising.

Other Things to be Careful With

If you browse the class hierarchy, especially in Object, Behavior and Class, you will find all sorts of useful methods. There are one or two of these that you should be careful about using though. Chief amongst them are perform: and become:. Both of these are very powerful methods—we've already looked at how perform: permits and enables the writing of 'pluggable' classes. The become: method swaps the state of the object receiving the message with the object sent as a parameter. Both of these methods have their place, but if you find yourself wanting to use them you should stop and ask 'Do I have a good reason for doing this?* If the answer is 'Yes', then go ahead. If the answer is 'No', you should think carefully before using them. The perform: method can be slow and makes your code essentially untraceable. The become: method never does quite what you expect, and is also costly of resources.

Dans le document The Art and Science of Smalltalk (Page 161-164)