Re-re-reading it, you'd expect substr(...)=expr to return what the substr was set to. In this case, it returns the value of the substrafter the operation was complete. Your 4-argument, err, argument does seem to be the most persuasive.
Bug? Feature? Undefined behavior? I think a case could be made for the validity of either mode of operation.