by Colin Adams (modified: 2007 Apr 13)
Why aren't literal strings in Eiffel read-only? Indeed, why isn't class STRING read-only? I think (as do others) that Java gets in right in this respect, with it's separation of String and StringBuffer.
All sorts of hard-to-debug problems can arise because there is no read-only variant of STRING. We had one of these occur in the Gobo XML library - the XML parser was corrupted because one of the event filters was editing one of the strings emitted by the parser.
Our work-around for this problem was the following class:
description: "STRINGs with copy-on-write semantics"
library: "Gobo Eiffel String Library"
copyright: "Copyright (c) 2005, Colin Adams and others"
license: "MIT License"
date: "$Date: 2007-01-26 18:55:25 +0000 (Fri, 26 Jan 2007) $"
revision: "$Revision: 5877 $"
feature -- Access
-- Version of item that is safe for editing
same_as_item: Result /= Void and then Result = item
feature -- Element change
append_character (c: CHARACTER_8)
-- Append `c' at end.
new_count: item.count = old item.count + 1
appended: item.item (item.count) = c
append_string (s: STRING_8)
-- Append a copy of `s' at end.
s_not_void: s /= Void
fill_with (c: CHARACTER_8)
-- Replace every character with `c'.
same_count: old item.count = item.count
filled: item.occurrences (c) = item.count
insert_character (c: CHARACTER_8; i: INTEGER_32)
-- Insert `c' at index `i', shifting characters between
-- ranks `i' and `count' rightwards.
valid_insertion_index: 1 <= i and i <= item.count + 1
one_more_character: item.count = old item.count + 1
inserted: item.item (i) = c
put (c: CHARACTER_8; i: INTEGER_32)
-- Replace character at index `i' by `c'
valid_index: item.valid_index (i)
stable_count: item.count = old item.count
replaced: item.item (i) = c
item_not_void: item /= Void
end -- class ST_COPY_ON_WRITE_STRING
Hm. Now I look at it, it seems that the contract for append_string could be strengthened in the postconditions.
The _8 suffixes are only present because I used the EiffelStudio interface view.
This class can be used in a lot of situations to avoid problems. The basic idea is to avoid duplicating strings needlessly.
But it would be much better if we could follow the Java line here.
I think it ought to be possible to do this without breaking (much) existing code, by making use of the convert keyword. Rather than having STRING_GENERAL inherit from READ_ONLY_STRING_GENERAL, we have parallel hierarchies, and say that the read-only versions can convert to the existing versions (the creation procedures involved would of course copy the characters of the string).
Then we could change string literals to be of type READ_ONLY_STRING (or rather, one of its aliases), and everything should work just fine.