Bug 15507 – Throwable.message() should be pure @safe

Status
RESOLVED
Resolution
INVALID
Severity
blocker
Priority
P1
Component
druntime
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-01-03T15:30:00Z
Last change time
2016-01-21T01:02:25Z
Assigned to
nobody
Creator
code

Comments

Comment #0 by code — 2016-01-03T15:30:14Z
As per https://github.com/D-Programming-Language/phobos/pull/3751#issuecomment-168475896: The newly added message() method is neither @safe nor pure, both of which it should probably be as a replacement for the msg member. We need to figure out this part of the design before first releasing it.
Comment #1 by public — 2016-01-04T12:49:51Z
`@safe` indeed makes sense. `pure` - not so sure. Does marking base method as pure imply weak or strong purity for overriding? I.e. would this be legal? class SomeE : Exception { char[] buffer; override const(char)[] message () pure { // on demand message generation into this.buffer } } and this? class SomeE : Exception { static char[] buffer; override const(char)[] message () pure { / on demand message generation into SomeE.buffer } }
Comment #2 by issues.dlang — 2016-01-04T22:56:56Z
All that pure means is that the function can't access mutable variables that aren't passed to it. And the notion of strong vs weak purity is meaningless aside from when optimizations can be made or the compiler can implicitly change the mutability of the return type. And inheritance has no effect on how pure functions work (just on whether the function is pure or not when overriding). The this pointer/reference is one of the arguments to the function, so anything that can be accessed via it will work, whereas something like writeln wouldn't. And since the this pointer/reference is mutable, no optimizations of any kind can be made based on purity. There is no "strong" purity, since not all of the arguments are immutable. As for your example, the one where the buffer is a member variable will work perfectly fine. However, the one where the buffer is a static variable will not work, because it's not passed in as a function argument (even an invisible one) nor is it reachable via a function argument (unless the class also had a member variable which referred to the static variable).
Comment #3 by public — 2016-01-05T14:17:44Z
Right. Well, this means my original concern remains. Overly restrictive method attributes in base classes has caused me more trouble than lack of any attributes there. I have no idea how to make stuff like `pure` or `nothrow` to work with overriding when it comes to some very base abstract methods.
Comment #4 by issues.dlang — 2016-01-05T17:56:33Z
(In reply to Dicebot from comment #3) > Right. Well, this means my original concern remains. Overly restrictive > method attributes in base classes has caused me more trouble than lack of > any attributes there. I have no idea how to make stuff like `pure` or > `nothrow` to work with overriding when it comes to some very base abstract > methods. You're basically forced to decide which set of restrictions you want, and all derived classes are stuck with them. Do you want to be able to use the function in pure code? Then it has to be pure. But if you want to be able to do stuff in derived classes that isn't pure, then you can't make it pure... Basically, attributes and inheritance do not play along nicely at all. That's why we decided to remove opEquals, opCmp, toString, and toHash from Object - you can't possibly get the attributes right for everyone (though unfortunately, progress towards actually removing them has been minimal). So, we have to decide whether it makes sense to restrict message to be nothrow, pure, etc. or whether it makes sense to restrict the caller such that it has to handle exceptions from message to be nothrow or make it so that it can't be pure. nothrow almost certainly makes sense - certainly, I can see there being a good argument for considering it an Error for message to not work, and I seriously doubt that anyone is going to be handling exceptions thrown from the message member of an existing exception. pure _might_ make sense (certainly, ideally it would be pure - but it would mean that to do stuff like have a static variable, it would require a member variable that referred to that static variable), but it would make some implementations more unwieldy (e.g. using a static variable). Ultimately, all pure would be doing here is making it so that you can call message in pure code and so that you have to work at it to access mutable, "global" variables (and thus won't do it accidentally). It doesn't really prevent you from doing anything, but it doesn't protect you from much either, and it definitely doesn't enable any optimizations. However, the fact that pure _can_ be gotten around in this case via member variables but that you can't sanely get around the fact that the function isn't pure if you want to call it in pure code does make it seem like making it pure is the more flexible choice. @safe though is actually pretty questionable when you consider that there's a decent chance that an exception class would have the const(char)[] be a slice of a static array if it's trying to avoid allocations. To be safe, anyone who wants to save the message needs to (i)dup it (and actually, the documentation should probably reflect that). A lot of it comes down to whether we want to restrict the caller more or the classes that override message more. If I had to pick right now, I'd go with @system pure nothrow.
Comment #5 by public — 2016-01-21T01:02:25Z
As actual addition has been reverted for now, the issue has become unapplicable.