-
-
Notifications
You must be signed in to change notification settings - Fork 416
Add message() to object.Throwable #1445
Conversation
3ec4db2
to
88a4ae2
Compare
I won't get into all the the bikeshedding and deprecation process discussions that this PR will inevitably trigger, but let me point out that the method should probably take a sink delegate instead of returning the string such as to enable the user to avoid GC allocations. |
The sink delegate method is incompatible with using ranges. |
?! It allows a strict superset of what the |
Few comments:
|
I'm not sure I fully understand that though. How do you plan to make |
Wouldn't it make more sense to turn Then if there's concern about that breaking code, another overload which takes The only code that would break that way would be code that passed And if we go that route, then pretty much only the code that declares exceptions will have to change, whereas with the current proposal, we'd be looking to change all code that uses |
There's also this related PR that I never merged, because there wasn't enough feedback on it: |
Or even better, the delegate overload could just have a different name (e.g. |
So, if I were to propose a specific course of action, it would be to go with #1411 rather than this PR but deprecate the setter overload of |
No, in absence of class CustomEx : Exception
{
private char[] reusable_buffer;
override const(char)[] message () { return this.reusable_buffer; }
}
catch (Exception e)
{
log(e.message());
} Sink-based version would still have to allocate here unless logging facility is changed to support it (hardly an option). I'd love to see both overloads but plain All talk about breaking changes is hardly relevant because nothing gets deprecated or changed - it is all purely additive and will only matter for new code which wants to support the facility. |
Hmmm. The problem with const(char)[] is that it's going to lead to unnecessary allocations in many cases, because the return value will have to be duped to get a
Having both |
Only because some libraries are ridiculous in designing
Tango logger + our extensions. Though
I don't think such breakage (assuming you will eventually remove it at all) is justified compared to minor issue of wrong exception formatting in case of |
Seems like a DIP is in order here, as for any other contentious change to what is effectively the core language. @mihails-strasuns-sociomantic: Let me point out that in case your |
@klickverbot : Lazy construction of the message (or logical The point is that |
@mathias-lang-sociomantic: Then why not make an By the way, I think something like this should be a (crude, admittedly) workaround for the issue as you described it: string toStringMsgOnly(Throwable t) {
auto oldInfo = t.info;
scope (exit) t.info = oldInfo;
t.info = null;
return t.toString();
} Of course, you still need to sort out the const/immutable differences for |
@mihails-strasuns-sociomantic:
Not necessarily: |
It assumes we have control over all the |
You can just use The design mistake is having two versions of something that sorta, but not quite, do the same thing, where neither is a replacement for the other nor offers clear advantages (like being able to avoid an allocation for string concatenation, such as when using ranges for constructing the error message). Yes, |
@klickverbot the point was :
Again, this is basic information hiding. Why do you think using a plain field is better here ? |
I don't, see the last paragraph in my reply. |
Note: #1141 is probably not the issue you want to link to. |
Thanks, fixed the typo. |
Ok, let's clarify the intention. This isn't about workaround to support bad legacy code - I wouldn't bother anyone about it, adding local hacks is easy (currently patched dmd/druntime is used anyway). Quite the contrary, this is an attempt to fix legacy design mistake in D2 so that we can in future use vanilla upstream package without making our code worse. Forcing
Of course there is also (3) - don't use exceptions :) At the same time there isn't any practical reason to require immutability for exception messages. It isn't inherently persistent (only used while exception is being handled) and it not inherently shared. Most likely the decision was completely arbitrary (my guess only) in old days when it wasn't truly acknowledged what does it mean to be a
It also becomes rather awkward when you try to use it with formatting: catch (Exception e)
{
logNoLineBreak("message: ");
e.message(&logNoLineBreak);
log("");
// vs
log("message: %s", e.message());
} Again, this isn't about inventing workarounds (I have some as backup plan already). It is about making legitimate use case implementable without workaround. Because I believe our approach is perfectly fine and it is druntime that has issues in this regard. #1411 is reasonable on its own but unrelated to this PR because here I speak about exceptions that actually get thrown (often several times a second) and processed. |
It's not clear if you're aware of this from your post, but phobos does support sink-based toString methods in log("message: %s", e); if log uses |
No, I didn't know this, thanks for the hint. It doesn't work with |
Ping. |
Hi, there, I'm sorry to intercede with some information that it might be a bit off-topic in this issue, but I just want to explain the dimension this issue has for us. We are spending a lot of time and effort to move to D2. Our main goal to do this is to be able to contribute to D more, to leave the bubble we are living in. For us from a purely practical point of view, there is very little gain from this move. Even more, given our current memory allocation constraints we probably won't even be able to use phobos or any other library out there. But we want to contribute to make them better to meet our requirements too. Even more, we want to release some internal libraries, that we think it might be useful for many other users out there, but it makes no sense to do so if we still use D1. I know is always shitty to ask for support for particular use cases from corporate users, but we believe this will actually make the language better. We don't think we are the only ones with these requirements out there. Is also quite unfortunate that we are still a company, and there are some things we just can't afford (like another rewrite on Tango's logging system to of the rewrite we are already doing to move to D2). So what I am asking is to try to do an effort to collaborate on finding a solution to this issue. The alternative of keep forking the language (right now we are basically maintaining our own fork of D1) would be a catastrophe for us, after investing so much effort on this, not being able to fully merge with upstream would be heartbreaking. So I'd like to ask you to think very hard about the cost-benefit here. Specially if we are trying to find a good long term solution for high-performance users in general. A few crude reality facts:
So, please don't let this PR die, and please let's try hard to collaborate to find a solution for this that makes all parties happy, and allow Sociomantic to use upstream to be able to contribute back to the community. Last but not least, I'm not trying to start a big discussion about this (I actually don't want to start a discussion at all!). I'm just telling you what's going on with Sociomantic. I don't want to cause a big fuzz. Thanks! :) |
There is no backwards compatibility issue with this PR. |
With this PR, using So, no, this PR doesn't strictly speaking break any code, but it does mean that in the long run, any code using |
I could try look into implementing dfix/dscanner rule for turning |
Sadly, libdparse doesn't seem to support such complicated semantic analysis yet :( |
Well, fortunately, it's an easy fix to change code from |
We need to address the question of |
There are 3 major issues w/ this.
The second and particularly the third problem too critical to release this. I'd suggest to revert this change and reevaluate the design for the next release. |
This is just wrong, whether or not a sink-based method allocates depends on the implementation of class MyException
{
const(char)[] message1();
void message2(scope void delegate(const(char)[] sink));
}
void test
{
log(e.message()); // @nogc if both log and message are @nogc
e.message(&log); // @nogc if both log and message are @nogc
e.message(msg => log(msg)); // use any log function
e.message(&bufferedSink!(msg => log(msg))); // composable in case you want to write the whole message at once
} BUT, w/ the first signature the Exception implementation has to use a local buffer, and in practice will often just concat strings, to format the message. With a sink it's possible to format in place. The typical implementations would look like this. class Exception
{
int status;
const(char)[] message1()
{
return "Request returned "~status.to!string~".";
return format("Request returned %s.", status);
}
void message2(scope void delegate(const(char)[] sink))
{
formattedWrite(sink, "Request returned %s.", status);
}
} A sink based method is a strict superset of the method returning a buffer. |
No, a sink is an output range is a sink is an output range. |
Well, there's never any way around adding a symbol being a potential breaking change. Even adding a free function can do that. The only way we could avoid that would be to never add any symbols ever again. So, I certainly don't think that that's sufficient reason not to add this. That being said, I definitely agree that using a sink would be better in the general case and more in line with how the rest of how druntime/Phobos works. But the whole reason that this is here is because of the Sociomantic folks and what they wanted, and they didn't want a sink solution. Part of the problem though is that a sink solution does not work well with how std.experimental.logger is currently designed - or presumably the Tango logger (based on what's been said here) - and that's really want the Sociomantic folks need solved (if I understand correctly). So, presumably, one or both loggers would need to be improved in order for a sink solution to work for the Sociomantic folks. But if it were up to me, I'd definitely go with the sink solution over what this PR has done. |
But that's not true, see #1445 (comment). e.message(msg => log(msg)); // use any log function |
FYI: there is a live chat with @MartinNowak , @andralex and some guys from our side planned, I will delay any further commenting here until it becomes more clear where are we heading :) |
Revert "Merge pull request #1445 from WalterBright/message"
@MartinNowak can you please write down the relevant summary from the discussion here? Just for the public PR record. |
With regards to |
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
To be able to test Ocean we need to build a dmd-transitional compiler which includes some changes to upstream DMD that are still under discussion. See: * dlang/DIPs#55 * dlang/druntime#1445 * MartinNowak/druntime@80e5059
Having
msg
as a user accessible field turns out to make customized exceptions more difficult than they should be. Turning it into a property function can break existing code. So added an overridablemessage
function instead, and undocumentedmsg
.