jinx@CHAMARTIN.AI.MIT.EDU ("Guillermo J. Rozas") (05/26/89)
There are good reasons not to specify (in the Standard) the value returned by mutators. Individual dialects/implementations can specify the value(s) returned if they wish. Besides the already mentioned ontological reasons for not returning a "canonical unspecified object" (there is no uninteresting positive integer), there are other reasons that have not been posted recently: Semantic reasons: Some people believe that the "right" thing for mutators is to return no values. Assuming that we adopt some multiple values mechanism in the future, this may be the "natural" thing to do. Specifying the value in the meantime will only make people depend on it, and will make it hard to make this change. Leaving the value unspecified, any "portable" program that depends on the value is "in error", and thus we don't have to support it. Correct programs won't depend on the value, and thus the change from one value to no values won't affect portable programs at all. Some dialects have consistent values to return for mutating operations, but there is no agreement among the various dialects. For example, some dialects specify that the return value is the new value being stored (since it has to be computed anyway). Some specify that the return value is the previous contents (so that mutators can be used as atomic "swapping" operations). Specifying the value in the standard will force these dialects into non compliance or into introducing a parallel set of operations which differ only in the returned value. Leaving the return value unspecified allows dialects/implementations to experiment with minor language design changes. Implementation reasons: For implementations of many dialects, in which the value returned is in fact not specified, specifying the return value (even if it is specified to be an arbitrary, otherwise useless, value) would cause compilers to generate more/worse code in many cases. The compiler must issue code to return the "canonical unspecified value" whenever it can't prove that the value won't be used. In my experience this happens in a large fraction (if not most) of the cases when side effecting operations are used. Since the return value should not be used anyway, why not leave what is returned to the compiler's convenience? Why go to extra work to return some canonical object which is not meant to be used? The only guarantee that the compiler must make is that the return value has to be a valid object (so that your garbage collector won't become confused if the value is "saved"). For debugging reasons, the "right" value to be returned would be some context object specifying which procedure/expression was producing this object, what the environment of the procedure (parameters and free variables) was like at the time of the construction of this context object, and what the continuation was at this time as well. Thus if such an object was ever found while debugging, the "culprit" could be pinpointed easily. Clearly this is too expensive to do, and I doubt that returning a canonical object would provide nearly as much information (think of the case where the result is consed into a data structure, and is only found to be "unspecified" ten years later when the structure is accessed).