www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Annoying deprecation messages when using EnumMembers with enum that

reply uranuz <neuranuz gmail.com> writes:
Hello! I don't no if such behaviour was made by intention or just 
an accident, but this is very annoying. There is bugzilla issue 
already for that. So I am not the only person who is concerned 
about this.
https://issues.dlang.org/show_bug.cgi?id=19864

I try to support my compiler output as clear as possible, so if 
there is some real errors. So I could find these errors as fast 
as possible without scrolling several `screens` of text about 
warnings that I am actulally unable to fix.

This error occurs when I am using std.conv: to with std.json in 
my code. So I am not the person who actually marked these enum 
members deprecated. So I can't do something with this.
Oct 06
parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Sunday, 6 October 2019 at 07:58:41 UTC, uranuz wrote:
 Hello! I don't no if such behaviour was made by intention or 
 just an accident, but this is very annoying. There is bugzilla 
 issue already for that. So I am not the only person who is 
 concerned about this.
 https://issues.dlang.org/show_bug.cgi?id=19864

 I try to support my compiler output as clear as possible, so if 
 there is some real errors. So I could find these errors as fast 
 as possible without scrolling several `screens` of text about 
 warnings that I am actulally unable to fix.

 This error occurs when I am using std.conv: to with std.json in 
 my code. So I am not the person who actually marked these enum 
 members deprecated. So I can't do something with this.
I also think it would be useful to have some way to suppress deprecations in a block of code. This is going to become important in the next version of D, where deprecated unittests will become basically impossible to use with unit-threaded because there'll be no way for unit-threaded to call a deprecated unittest without incurring a deprecation message. (That I can see.)
Oct 07
parent reply uranuz <neuranuz gmail.com> writes:
On Tuesday, 8 October 2019 at 04:31:22 UTC, FeepingCreature wrote:
 On Sunday, 6 October 2019 at 07:58:41 UTC, uranuz wrote:
 [...]
I also think it would be useful to have some way to suppress deprecations in a block of code. This is going to become important in the next version of D, where deprecated unittests will become basically impossible to use with unit-threaded because there'll be no way for unit-threaded to call a deprecated unittest without incurring a deprecation message. (That I can see.)
It is curious if it needs some language support to suppress deprecation messages or if it is just a library issue?
Oct 07
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, October 8, 2019 12:39:28 AM MDT uranuz via Digitalmars-d wrote:
 On Tuesday, 8 October 2019 at 04:31:22 UTC, FeepingCreature wrote:
 On Sunday, 6 October 2019 at 07:58:41 UTC, uranuz wrote:
 [...]
I also think it would be useful to have some way to suppress deprecations in a block of code. This is going to become important in the next version of D, where deprecated unittests will become basically impossible to use with unit-threaded because there'll be no way for unit-threaded to call a deprecated unittest without incurring a deprecation message. (That I can see.)
It is curious if it needs some language support to suppress deprecation messages or if it is just a library issue?
Any non-deprecated code that uses deprecated symbols will result in a deprecation message when it's compiled. This includes stuff like template constraints and type introspection. So, when you start doing things like using EnumMembers on an enum type which has a deprecated member, then it's definitely going to result in deprecation messages, because the deprecated member is actually used in the code. This isn't really a new problem, but finally being able to deprecate enum members has certainly made it worse. And there isn't an obvious solution either. After all, just because an enum member was deprecated doesn't mean that it shouldn't be used, and if it is used, there really should be a deprecation message indicating that it was used. The main problem is that you're using it indirectly, so you don't really have any control over it. A related issue would be what should happen with final switch. A final switch is supposed to have a case for _every_ enum member, and that would include deprecated enum members. If it didn't, then you have an enum member that's perfectly valid (just deprecated) which could be given to the final switch, and it wouldn't be able to handle it, since it wouldn't think that it was a valid value for that enum type. You can't even say that it should do one thing in a function that's deprecated and another thing in a function that's not deprecated, because not only could a deprecated enum value be passed to a non-deprecated function, but code isn't compiled differently based on whether it's in a deprecated context or not. A function's internals are going to compile exactly the same way whether the function is deprecated or not. The only difference is that if the function isn't deprecated, and it uses deprecated symbols, then you're going to get a deprecation message (or an error if -de is used). The generated code is the same. If we had a trait for testing whether a symbol was deprecated or not, and using it on a deprecated symbol did not trigger a deprecation message, then code could choose to test whether something was deprecated and skip it if it were, so we could then have a version of EnumMembers which ignored deprecated members, but again, that would cause problems with final switch, and code like std.conv.to isn't going to use it, because code that worked before that enum member was deprecated needs to continue to work (and work the same way) as long as that enum member still exists. Compiling a piece of code differently based on whether a symbol is deprecated or not could be useful in some circumstances, but it also makes it so that there's a real risk of code breaking simply because a symbol was deprecated, and deprecations result in messages by default rather than errors precisely because we're trying to give people a chance to fix their code before the symbol is removed rather than forcing them to change their code immediately. If you're looking for something like std.conv.to to not spit out deprecation messages when compiled to convert to or from an enum, you're basically asking it to generate a deprecation message based on whether you use the deprecated enum member or not, which can't std.conv.to can't know until runtime. A related issue is the -de flag, which arguably is really bad in that it makes it so that is expressions and __traits(compiles, ...) expressions have a different result depending on whether -de is used or not, because -de turns deprecation messages into errors. Meaning that code that compiled just fine before the deprecation may not compile anymore, or it may compile with different behavior. So, there are a number of subtleties to this whole situation that make it kind of hard to figure out what the best approach is. We don't want deprecation messages being printed when the code isn't really doing anything that needs to be changed, but we also don't want the code's behavior to change just because something was deprecated. And how to tweak what we're doing to fix that in a reasonable way is not obvious. Regardless, there are really only two ways to shut up deprecation messages when -de isn't used: 1. Change the code so that it doesn't use the deprecated symbol (which we don't really have a way to do when type introspection is involved and whether we would want to not see those messages with type introspection depends on what the type introspection is doing; it's also not always possible or reasonable to change generated code like with std.conv.to). 2. Use -d to shut up all deprecation messages (which means that you won't see them and won't know when you actually need to update your code, so in all likelihood, your code will just end up breaking when the deprecated symbol is finally removed). If -de is used, then code using deprecated symbols in is expressions or __traits(compiles, ...) expressions shouldn't trigger deprecation messages, because compilation errors are ignored in such expressions beyond determining whether the code compiles or not so that the compiler can give you a boolean result. - Jonathan M Davis
Oct 08
next sibling parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Tuesday, 8 October 2019 at 10:06:18 UTC, Jonathan M Davis 
wrote:
 A related issue is the -de flag, which arguably is really bad 
 in that it makes it so that is expressions and 
 __traits(compiles, ...) expressions have a different result 
 depending on whether -de is used or not, because -de turns 
 deprecation messages into errors. Meaning that code that 
 compiled just fine before the deprecation may not compile 
 anymore, or it may compile with different behavior.
I'm gonna argue this :) -de makes sense if one interprets it as "generate the code that would result if all deprecated symbols were removed." Of course this doesn't quite work right with stuff like final switch and enums... but it works with pretty much everything else. (?) Should __traits(allMembers) ignore deprecated enum members with -de? Under this interpretation, it seems that it should. And regarding expressions having a different result, well, yes, just like they'll have when the deprecated symbol is removed. :) Separately: the problem with unittest and deprecations is that a "deprecated unittest" results in a deprecated unittest function in __traits(getUnitTests), which there's no way to call without incurring recursive deprecation all the way to deprecated void main. This is arguably wrong - imo deprecated unittest shouldn't mean the *test* is deprecated, just that it tests a deprecated feature. This can be seen by the fact that D's runtime calls deprecated unittests with no warning, -de or otherwise. So you should be able to call them from framework code too.
Oct 08
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, October 8, 2019 5:50:48 AM MDT FeepingCreature via Digitalmars-d 
wrote:
 On Tuesday, 8 October 2019 at 10:06:18 UTC, Jonathan M Davis

 wrote:
 A related issue is the -de flag, which arguably is really bad
 in that it makes it so that is expressions and
 __traits(compiles, ...) expressions have a different result
 depending on whether -de is used or not, because -de turns
 deprecation messages into errors. Meaning that code that
 compiled just fine before the deprecation may not compile
 anymore, or it may compile with different behavior.
I'm gonna argue this :) -de makes sense if one interprets it as "generate the code that would result if all deprecated symbols were removed." Of course this doesn't quite work right with stuff like final switch and enums... but it works with pretty much everything else. (?) Should __traits(allMembers) ignore deprecated enum members with -de? Under this interpretation, it seems that it should. And regarding expressions having a different result, well, yes, just like they'll have when the deprecated symbol is removed. :)
-de is for those who want to force code in a code base to be updated when a deprecation message pops up instead of letting it be fixed later. It does not do exactly the same thing as having the deprecated symbol removed, since the symbol still exists and still affects stuff like overloading and type introspection. Yes, an expression which tests whether a piece of code compiles or not which uses the deprecated symbol will then fail to compile similar to what it would do once the symbol has been removed, but you could still get subtle differences like a piece of code that doesn't compile because of a conflicting symbol which then compiles fine once the deprecated symbol has actually been removed. So, I'd advise against using -de to see what the code would do once the symbol was removed. The effect will be similar, but it won't be the same, and depending on the code involved, the difference could matter. All in all though, -de has a lot of the same problems that -w does. Whenever a compiler flag can change what is and isn't an error, there are going to be subtle problems - especially when it's possible to have code which compiles different branches depending on whether a particular piece of code compiles or not. It's not necessarily the case that it's a problem to use -de or -w, but there are risks involved.
 Separately: the problem with unittest and deprecations is that a
 "deprecated unittest" results in a deprecated unittest function
 in __traits(getUnitTests), which there's no way to call without
 incurring recursive deprecation all the way to deprecated void
 main. This is arguably wrong - imo deprecated unittest shouldn't
 mean the *test* is deprecated, just that it tests a deprecated
 feature. This can be seen by the fact that D's runtime calls
 deprecated unittests with no warning, -de or otherwise. So you
 should be able to call them from framework code too.
I expect that the problem here has to do with how things get lowered. Underneath the hood, a unittest block is basically a normal function and thus is going to tend to follow the same rules that a normal function would. As such, it would make sense that it would be a problem to have a non-deprecated function calling a unittest function or that a piece of code which is introspecting unit test stuff would get deprecation messages due to deprecated unittest blocks. I don't know enough of the details about how the unit test stuff works to say how it should be fixed, but I agree that the current behavior isn't great for alternate test runners. - Jonathan M Davis
Oct 08
parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Tuesday, 8 October 2019 at 16:03:20 UTC, Jonathan M Davis 
wrote:
 I don't know enough of the details about how the unit test 
 stuff works to say how it should be fixed, but I agree that the 
 current behavior isn't great for alternate test runners.

 - Jonathan M Davis
Maybe just ignore the deprecation if we're calling a function that's a unittest?
Oct 09
parent reply Seb <seb wilzba.ch> writes:
On Wednesday, 9 October 2019 at 07:24:04 UTC, FeepingCreature 
wrote:
 On Tuesday, 8 October 2019 at 16:03:20 UTC, Jonathan M Davis 
 wrote:
 I don't know enough of the details about how the unit test 
 stuff works to say how it should be fixed, but I agree that 
 the current behavior isn't great for alternate test runners.

 - Jonathan M Davis
Maybe just ignore the deprecation if we're calling a function that's a unittest?
If you want to test deprecated features, you can mark the unittest as deprecated too. deprecated unittest { ... } This won't result in deprecations of the unittest's code block triggered. Example: https://run.dlang.io/is/eRxCtd
Oct 09
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, October 9, 2019 1:58:56 AM MDT Seb via Digitalmars-d wrote:
 On Wednesday, 9 October 2019 at 07:24:04 UTC, FeepingCreature

 wrote:
 On Tuesday, 8 October 2019 at 16:03:20 UTC, Jonathan M Davis

 wrote:
 I don't know enough of the details about how the unit test
 stuff works to say how it should be fixed, but I agree that
 the current behavior isn't great for alternate test runners.

 - Jonathan M Davis
Maybe just ignore the deprecation if we're calling a function that's a unittest?
If you want to test deprecated features, you can mark the unittest as deprecated too. deprecated unittest { ... } This won't result in deprecations of the unittest's code block triggered. Example: https://run.dlang.io/is/eRxCtd
If I understand his complaint correctly, deprecated unittest blocks result in deprecation messages when you use third party test runners instead of the default one, and if that's what's happening, that should probably be fixed. - Jonathan M Davis
Oct 09
parent FeepingCreature <feepingcreature gmail.com> writes:
On Wednesday, 9 October 2019 at 08:28:00 UTC, Jonathan M Davis 
wrote:
 On Wednesday, October 9, 2019 1:58:56 AM MDT Seb via 
 Digitalmars-d wrote:
 On Wednesday, 9 October 2019 at 07:24:04 UTC, FeepingCreature

 wrote:
 Maybe just ignore the deprecation if we're calling a 
 function that's a unittest?
If you want to test deprecated features, you can mark the unittest as deprecated too. deprecated unittest { ... } This won't result in deprecations of the unittest's code block triggered. Example: https://run.dlang.io/is/eRxCtd
If I understand his complaint correctly, deprecated unittest blocks result in deprecation messages when you use third party test runners instead of the default one, and if that's what's happening, that should probably be fixed. - Jonathan M Davis
That's correct. It's not been a problem in the past since deprecations were ignored in mixins, so unit-threaded worked "by coincidence."
Oct 09
prev sibling parent reply =?UTF-8?Q?S=c3=b6nke_Ludwig?= <sludwig+d outerproduct.org> writes:
Am 08.10.2019 um 13:50 schrieb FeepingCreature:
 On Tuesday, 8 October 2019 at 10:06:18 UTC, Jonathan M Davis wrote:
 A related issue is the -de flag, which arguably is really bad in that 
 it makes it so that is expressions and __traits(compiles, ...) 
 expressions have a different result depending on whether -de is used 
 or not, because -de turns deprecation messages into errors. Meaning 
 that code that compiled just fine before the deprecation may not 
 compile anymore, or it may compile with different behavior.
I'm gonna argue this :) -de makes sense if one interprets it as "generate the code that would result if all deprecated symbols were removed." Of course this doesn't quite work right with stuff like final switch and enums... but it works with pretty much everything else. (?) Should __traits(allMembers) ignore deprecated enum members with -de? Under this interpretation, it seems that it should. And regarding expressions having a different result, well, yes, just like they'll have when the deprecated symbol is removed. :) Separately: the problem with unittest and deprecations is that a "deprecated unittest" results in a deprecated unittest function in __traits(getUnitTests), which there's no way to call without incurring recursive deprecation all the way to deprecated void main. This is arguably wrong - imo deprecated unittest shouldn't mean the *test* is deprecated, just that it tests a deprecated feature. This can be seen by the fact that D's runtime calls deprecated unittests with no warning, -de or otherwise. So you should be able to call them from framework code too.
For the particular issue of filtering out deprecated members, I've written a little workaround some time ago, using the fact that warnings inside of _traits(compiles) are gagged: https://github.com/s-ludwig/dynamic/blob/79b73a9afe14432da6917fd519563655300092d1/source/dynamic.d#L82-L85 It doesn't help when actual access to these members is desired.
Oct 09
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 09, 2019 at 07:38:34PM +0200, Sönke Ludwig via Digitalmars-d wrote:
[...]
 For the particular issue of filtering out deprecated members, I've
 written a little workaround some time ago, using the fact that
 warnings inside of _traits(compiles) are gagged:
 
 https://github.com/s-ludwig/dynamic/blob/79b73a9afe14432da6917fd519563655300092d1/source/dynamic.d#L82-L85
 
 It doesn't help when actual access to these members is desired.
Interesting idea. I wonder if it's possible to (ab)use __traits(compiles) to extract information from deprecated members while gagging the deprecation messages. Like, arrange for an expression inside __traits(compiles) to compile or not, based on some desired boolean criteria, then use static if outside to extract this information. This would be a really nasty hack, though, so probably should not be used in production! T -- First Rule of History: History doesn't repeat itself -- historians merely repeat each other.
Oct 09
prev sibling parent reply Gregor =?UTF-8?B?TcO8Y2ts?= <gregormueckl gmx.de> writes:
On Tuesday, 8 October 2019 at 10:06:18 UTC, Jonathan M Davis 
wrote:
 So, there are a number of subtleties to this whole situation 
 that make it kind of hard to figure out what the best approach 
 is. We don't want deprecation messages being printed when the 
 code isn't really doing anything that needs to be changed, but 
 we also don't want the code's behavior to change just because 
 something was deprecated. And how to tweak what we're doing to 
 fix that in a reasonable way is not obvious.
Would it help to be able to explicitly suppress these warnings in certain regions of code? So e.g. std.conv.to could disable these warnings when iterating over enum members. Other code that is generic and cannot opt out of handling deprecated things could be expected to do the same. This shifts the onus from the compiler to the programmer. But given the complexity of the issue, it might be the right choice.
Oct 09
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, October 9, 2019 8:32:36 AM MDT Gregor Mückl via Digitalmars-d 
wrote:
 On Tuesday, 8 October 2019 at 10:06:18 UTC, Jonathan M Davis

 wrote:
 So, there are a number of subtleties to this whole situation
 that make it kind of hard to figure out what the best approach
 is. We don't want deprecation messages being printed when the
 code isn't really doing anything that needs to be changed, but
 we also don't want the code's behavior to change just because
 something was deprecated. And how to tweak what we're doing to
 fix that in a reasonable way is not obvious.
Would it help to be able to explicitly suppress these warnings in certain regions of code? So e.g. std.conv.to could disable these warnings when iterating over enum members. Other code that is generic and cannot opt out of handling deprecated things could be expected to do the same. This shifts the onus from the compiler to the programmer. But given the complexity of the issue, it might be the right choice.
AFAIK, it's not currently possible to surpress deprecation messages other than turning them off entirely. As for whether it would be desirable... I don't know. On the one hand, it's kind of annoying that something like std.conv.to would spit out deprecation messages for things like deprecated enum members. On the other hand, that happens because the code is actually using those deprecated enum members, and it's quite possible that it will be passed an enum value equal to a deprecated enum member. Enum members get a bit weird, because deprecating them doens't necessarily mean that their values are being deprecated, and even if the values are supposed to go away, it's quite easy to have enum values that don't match any members (personally, I wish that our enums were a lot stricter about that than they are, but they aren't). Normally, deprecation messages indicate that something needs to be updated to no longer use a deprecated symbol, because that symbol is going to be removed later. However, in the case of generated code, it could end up using a deprecated symbol thanks to something like EnumMembers, and yet such code shouldn't actually be changed. It's just going to naturally take care of itself once the deprecated enum member is gone. So, on that basis, the deprecation message is arguably inappropriate, but making it possible to selectively ignore deprecation messages in such code could be problematic as well. For instance, consider the case where opCast is deprecated. That would result in a deprecation message from std.conv.to, but it's one where the caller would almost certainly need to be updated to not use std.conv.to (though that could get a bit murky if the idea was that std.conv.to would switch to using a constructor once the opCast was removed). So, at minimum, it's not the case that std.conv.to should just be eating deprecation messages. Even if we did decide that we wanted to add a way to selectively ignore deprecation messages, I don't know what that should look like, and depending on what it looked like, it could have other negative consequences. Honestly, I suspect that in the vast majority of cases, the current situation is not an issue. It's popped up now primarily because of the new ability to deprecate enum members, and while I think that it's great to be able to do so, I also think that deprecating enum members gets a bit iffy once things like EnumMembers come into play anyway. Certainly, generated code like that needs to continue to use deprecated symbols, otherwise it would break existing code, meaning that it can't actually be updated the way that you would normally update code using deprecated symbols, and there's a real risk that once the symbol is actually removed, code will end up breaking due to the symbol then being gone. So, I don't know how much sense it makes to deprecate enum members in practice much as it's desirable in theory. Personally, the place that I've primarily had issue with needing to use deprecated symbols in code that isn't deprecated is in template constraints that are trying to disallow a deprecated type. In particular, last time I tried to deprecate TickDuration, I ran into problems with a bunch of deprecation messages that I had a hard time figuring out how to get rid of. It may be that we need to make some kind of change here with regards to when deprecation messages pop up and/or how the programmer can control that, but I'm not sure that we really understand the situation well enough to do a good job with that at the moment. I think that we need to have a good understanding of the situations where deprecation messages are popping up when the code doesn't actually need to be changed - both what's happening and why - before we can really put forward a good solution to the problem. - Jonathan M Davis
Oct 12