6
$\begingroup$

C++ initially had "readonly" and "writeonly" qualifiers, before "readonly" was renamed to "const", and "writeonly" removed. My question is: What are the problems with "writeonly" (or a "sink" qualifier)?


There are (non-object oriented) programming languages with "in", "out" and "inout" qualifier for functions arguments. In that context, the meaning of "out" is pretty clear. Writing "result_p = result_p+1" is not allowed if "out int& result_p", and the question whether "result_p += 1" is allowed doesn't arise, because these languages don't have "+=" and similar constructs.

Now "sink" in C++ would be a type qualifier, not just a function argument qualifier. The meaning of "sink" is clear on a semantic level. Information is only allowed to flow into a "sink" qualified object, but no information is allowed to leave a "sink" qualified object. So writing "result_p += 1" would be allowed if "sink int& result_p", but what about "result_p = result_p+1"? Its semantic is fine, but there seem to be no general way to check this based on simple syntax or typing rules. But so what, does anything bad happens if "result_p = result_p+1" is not allowed?

$\endgroup$
  • $\begingroup$ One serious problem are exceptions and error handling. No method called on a sink should throw an exception, or return an error code which gets checked. However, the typical methods one would want to call on a sink can potentially fail, like the assignment operator where memory allocation can fail. Postponing error handling is one possibility, but this encourages a dubious programming/error handling style. $\endgroup$ – Thomas Klimpel Jun 26 '14 at 21:50
  • $\begingroup$ What's the point of write-only variables? I would assume it's so the user can write to some field that a class uses, but we don't want the user to be able to use the field themselves. In that case, shouldn't we just use a setter method? $\endgroup$ – gardenhead Jun 26 '14 at 23:26
  • $\begingroup$ @StephenBly Say a function will append its results to a std::vector. The intention of a write-only/sink qualifier would be to indicate that the previous content of the vector does't have any direct influence on the behavior of the function, even if it may influences the content of the vector itself after the function call. $\endgroup$ – Thomas Klimpel Jun 27 '14 at 0:00
4
$\begingroup$

I can only hypothesize, so maybe this should only be a comment, but it's too long for the comment box.

In general Stroustrup tries extremely hard to avoid adding new keywords to the language, so if he discovered that there was another way to get whatever "expressivity" writeonly might provide he would remove the keyword.

My guess is that he actually couldn't find much use for writeonly. Stroustrup came from an Operating Systems background, and (according to [1]) a lot of the stuff about const and friend originally derived from analogies to O.S. access rights. (For const, think read/write/execute permissions on files in Unix, and for friend think of one program granting access permissions to another program.)

The analogy apparently only goes so far though. The usefulness of a writeonly parameter would seem to be that it allows you to return more than one value (but you can return a pair or a struct in C++, and you can "return" an error code by throwing an exception, and perhaps one return value plus an error code is the common case.) Declaring a non-parameter variable as writeonly makes no sense, because then you would need to do a cast in order to do anything with the value. A writeonly function is a constructor, and C++ already has those using a different syntax (that doesn't require a new keyword.) An append operation for vectors most certainly can not be writeonly, because it must increment the length of the vector (i.e., length = length+1.)

[1] Bjarne Stroustrup, The Design and Evolution of C++, Addison-Wesley, 1994.

$\endgroup$
  • $\begingroup$ You say "An append operation for vectors most certainly can not be writeonly, because it must increment the length of the vector (i.e., length = length+1.)". Why do you write "most certainly"? The status of the similar but simpler/clearer example "result_p += 1" has already been raised in the question, with a different conclusion. There could be an implicit assumption here, similar to assuming that a const-reference can only be initialized by from a const object. $\endgroup$ – Thomas Klimpel Jun 27 '14 at 7:39
  • $\begingroup$ I'm glad Stroustrup didn't invent a language where x+=1 has different type than x=x+1 $\endgroup$ – Wandering Logic Jun 27 '14 at 11:25
  • $\begingroup$ And I can't see any way in which writeonly lets me write more maintainable software no matter what the type of x+=1. $\endgroup$ – Wandering Logic Jun 27 '14 at 11:37
  • $\begingroup$ The documentation of a function will normally specify which of its arguments are purely output variables. I hope you agree this documention can make the software easier to understand. The purpose of writeonly (or sink) would be to let the compiler check whether this documentation actually tells the truth. (The important point is not the type of x+=1, but that the intended semantics of sink is understood. Modification of an existing object must be allowed, because already the assignment operator modifies an existing object in a way which can depend on its previous state.) $\endgroup$ – Thomas Klimpel Jun 27 '14 at 16:22
  • $\begingroup$ I'm sorry my answer isn't to your liking. If you want to argue about it more, perhaps it would be more appropriate to use Computer Science Chat. $\endgroup$ – Wandering Logic Jun 27 '14 at 19:05
3
$\begingroup$

If the question is interpreted in the historical way (as done by Wandering Logic), then the answer can indeed by found in "Bjarne Stroustrup, The Design and Evolution of C++" in section "3.8 Constants". The readonly and writeonly qualifiers were proposed in January 1981 by Stroustrup as a modification of the C language (not of the C with classes language), long before C++ even existed (but C with classes already existed and was mature). An internal Bell Labs C standards group requested that readonly be renamed to const, and agreed that it would be introduced into C then (which somehow didn't happen at the time). Stroustrup waited for this to happen, and in the meantime discovered that const could also be used to provide symbolic constants (the parameter keyword in fortran). The proposal for writeonly was not well worked out, didn't provide additional use cases beyond its main purpose in function interfaces, and wasn't accepted by the internal standard group. So writeonly wasn't removed by a conscious decision, but just didn't manage to convince enough people of its usefulness. Because Stroustrup still brings up writeonly when describing const, we can even guess that he's still proud of his initial idea.

What are the problems with writeonly (or a "sink" qualifier)?

  • For a language like C with ++ and += operators that return references to the modified object, the question whether this returned reference should be write only is difficult to resolve. The reference returned by the += operator should probably be a sink, but some uses of ++ need a non-sink returned reference.

  • An appropriate formal semantic of a sink qualifier is not obvious, and Stroustrup didn't work out a satisfying formal semantic either.

  • Even without exceptions, error handling becomes problematic and surprising. As a real world example, I remember me debugging through a "write only" "progress provider", which triggered a GUI update and thereby caused a cancel button to propagate its state to a "cancel provider". If the "progress provider" was replaced by a dummy implementation (when no progress was desired for certain use case), suddenly that "cancel provider" stopped working correctly. An this was even harmless compared to another "progress provider", which just took care of the cancel functionality himself by throwing an exception, thereby crashing the program in many multithreaded and distributed scenarios.
    These two examples show some of the real world issues that a sink qualifier should address. But this is a much more tricky problem compared to the problems solved by const, and it is not clear how a formal semantic resolving these issues can look like.

  • ??? (I forgot for the moment, maybe I will remember later)

But so what, does anything bad happens if "result_p = result_p+1" is not allowed?

The answer by Wandering Logic and his reaction to requests for clarification in the comments provide good examples for the bad things that would happen:

  • "An append operation for vectors most certainly can not be writeonly, because it must increment the length of the vector (i.e., length = length+1.)"
  • "I'm glad Stroustrup didn't invent a language where x+=1 has different type than x=x+1"

Having a half baked language feature would only lead to confusion and frustration, which could never be outweighed by the benefits of the feature. So if one would want such a sink feature, then one also needs a formal semantic which closely models the intended (informal) semantic. Some sort of preorder on the accessible references seems required, which determines how information is allowed to flow. But can this preorder always be generated implicitly, or does the programmer sometimes need to also specify details of this preorder? But this all seems to be quite complicated for the limited benefits provided by a sink modifier.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.