GHC2021: DeriveAnyClass

Dear all, I’ve found as a surprise that several members of the Committee have voted against, or even marked as dangerous, the DeriveAnyClass extension. Given that I am a great fan of it, I would like to open the debate about the particular extension. In my case, most of my uses are to derive ToJSON and FromJSON from the Aeson package. I find it very nice to be able to pack all the information about auto-derived instances in a small block, instead of including Eq and Show in the deriving block, and then a few empty instance declarations below. This is definitely mainly a aesthetic reason. The other reason for adoption is that it makes classes such as Eq or Show less “special”, so one does not have to explain to beginners that some classes can be derived in this way, some others in that other way, and so on. So my other reason for inclusion would be a uniformity one. Regards, Alejandro

My worry with DeriveAnyClass that a user might try to derive a class not intended for use with DeriveAnyClass. For instance:
class Pretty a where -- render something for users, not debuggers ppr :: a -> String ppr x = pprs [x]
pprs :: [a] -> String pprs xs = "[" ++ intercalate "," (map ppr xs) ++ "]"
instance Pretty a => Pretty [a] where ppr xs = pprs xs
instance Pretty Int where ppr n = show n
data T = MkT1 Int | MkT2 Bool deriving Pretty
With -XDeriveAnyClass, this compiles without any warnings -- and it seems like something a user might plausibly attempt. Attempting to ppr (MkT1 5) yields an infinitely long string. A more knowledgeable user would have written a MINIMAL pragma in Pretty (or perhaps designed the class differently), but not all users are experienced. If, say, we required an explicit deriving strategy to use DeriveAnyClass, or required a MINIMAL pragma, then I would feel differently. As it is, I think the extension is potentially dangerous, as it can create unexpected runtime behavior without warnings. Richard
On Nov 30, 2020, at 2:42 PM, Alejandro Serrano Mena
wrote: Dear all, I’ve found as a surprise that several members of the Committee have voted against, or even marked as dangerous, the DeriveAnyClass extension. Given that I am a great fan of it, I would like to open the debate about the particular extension.
In my case, most of my uses are to derive ToJSON and FromJSON from the Aeson package. I find it very nice to be able to pack all the information about auto-derived instances in a small block, instead of including Eq and Show in the deriving block, and then a few empty instance declarations below. This is definitely mainly a aesthetic reason.
The other reason for adoption is that it makes classes such as Eq or Show less “special”, so one does not have to explain to beginners that some classes can be derived in this way, some others in that other way, and so on. So my other reason for inclusion would be a uniformity one.
Regards, Alejandro _______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Hi, I concur with Richard: DeriveAnyClass is convenient where it works, but too implicit and too magical for my taste. It’s a cute trick, but in general “just write an empty instance and hope for the best” isn't a particular convincing solution to this problem. There was a recent blog post, written tongue in cheek, about removing type class features in Haskell … here it is: https://www.parsonsmatt.org/2020/11/10/simplifying_deriving.html and the gist here is: With DerivingVia we don’t need DeriveAnyClass: newtype Generically a = Generically a instance (Generic a, GToJSON (Rep a)) => ToJSON (Generically a) where toJSON (Generically a) = gtoJSON a data X = X deriving stock Generic deriving ToJSON via Generically X And the last line is easier to understand and safer than DeriveAnyClass. In light of these alternatives, I am still inclined to not give DeriveAnyClass the seal of “harmless and uncontentious” :-) Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

I’ve found as a surprise that several members of the Committee have voted against, or even marked as dangerous, the DeriveAnyClass extension. Given that I am a great fan of it, I would like to open the debate about the particular extension.
I’m a great fan of Template Haskell, but I didn’t put it in the “on by default” category.
There are lots of “deriving” extensions. I treated them as a group, but you could perhaps argue that doing so isn’t right. Is there a reason to choose one over the others to be in the on-by-default set?
Simon
From: ghc-steering-committee

Am Dienstag, den 01.12.2020, 08:14 +0000 schrieb Simon Peyton Jones via ghc-steering-committee:
There are lots of “deriving” extensions. I treated them as a group, but you could perhaps argue that doing so isn’t right. Is there a reason to choose one over the others to be in the on-by-default set?
I think so! There are extensions like DerivingVia or StandaloneDeriving that come with new, obvious syntax. These, like many other, have the property that you can see that they are being used because, well, they are being used, and requiring the user to write the language extension explicitly isn’t so useful. Then there are those that are less visible, but totally harmless and a natural continuation of what we have, namely more stock deriving extensions (DerivingFunctor, etc.). For all those above, even someone who isn't intimately acquainted with the extensions will not be thrown off when reading it; for the first group they will see something they don’t know and can read about it. For the second group… there isn’t even anything to think about, it does what you think it does. And then there are those that do “implicit magic”, in particular DeriveAnyClass. Here, an unsuspecting reader might fully understand what’s going on. Worse: With this extension on by default, beginners might try to put MyCustomClass into their deriving set, and get very unhelpful error messages: Prelude> class Test a where test :: a Prelude> data Foo = Foo deriving Test <interactive>:4:25: error: • Can't make a derived instance of ‘Test Foo’: ‘Test’ is not a stock derivable class (Eq, Show, etc.) Try enabling DeriveAnyClass • In the data declaration for ‘Foo’ Prelude> :set -XDeriveAnyClass Prelude> data Foo = Foo deriving Test <interactive>:6:25: warning: [-Wmissing-methods] • No explicit implementation for ‘test’ • In the instance declaration for ‘Test Foo’ With my (past) educator’s hat on, given that error messages, I say “please no!”. And with my Haskell author’s head on, I say “Lets get away from DeriveAnyClass and move to using deriving via to _explicitly_ say what’s going on here”. I have absolutely no qualms like this about the other Deriving extensions. Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

Thanks for the illuminating discussion! I’ve been convinced that we should
move away from DeriveAnyClass, and provide and start using ‘via
Generically’ instead. Which happily also gets rid of DefaultSignatures,
which I never liked due to the intimate bundling with the class declaration.
Alejandro
On 1 Dec 2020 at 09:25:26, Joachim Breitner
Am Dienstag, den 01.12.2020, 08:14 +0000 schrieb Simon Peyton Jones via ghc-steering-committee:
There are lots of “deriving” extensions. I treated them as a group,
but you could perhaps argue that doing so isn’t right. Is there a
reason to choose one over the others to be in the on-by-default set?
I think so!
There are extensions like DerivingVia or StandaloneDeriving that come with new, obvious syntax. These, like many other, have the property that you can see that they are being used because, well, they are being used, and requiring the user to write the language extension explicitly isn’t so useful.
Then there are those that are less visible, but totally harmless and a natural continuation of what we have, namely more stock deriving extensions (DerivingFunctor, etc.).
For all those above, even someone who isn't intimately acquainted with the extensions will not be thrown off when reading it; for the first group they will see something they don’t know and can read about it. For the second group… there isn’t even anything to think about, it does what you think it does.
And then there are those that do “implicit magic”, in particular DeriveAnyClass. Here, an unsuspecting reader might fully understand what’s going on.
Worse: With this extension on by default, beginners might try to put MyCustomClass into their deriving set, and get very unhelpful error messages:
Prelude> class Test a where test :: a Prelude> data Foo = Foo deriving Test
<interactive>:4:25: error: • Can't make a derived instance of ‘Test Foo’: ‘Test’ is not a stock derivable class (Eq, Show, etc.) Try enabling DeriveAnyClass • In the data declaration for ‘Foo’ Prelude> :set -XDeriveAnyClass Prelude> data Foo = Foo deriving Test
<interactive>:6:25: warning: [-Wmissing-methods] • No explicit implementation for ‘test’ • In the instance declaration for ‘Test Foo’
With my (past) educator’s hat on, given that error messages, I say “please no!”.
And with my Haskell author’s head on, I say “Lets get away from DeriveAnyClass and move to using deriving via to _explicitly_ say what’s going on here”.
I have absolutely no qualms like this about the other Deriving extensions.
Cheers, Joachim
-- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

On Tue, Dec 1, 2020 at 9:47 AM Alejandro Serrano Mena
Thanks for the illuminating discussion! I’ve been convinced that we should move away from DeriveAnyClass, and provide and start using ‘via Generically’ instead. Which happily also gets rid of DefaultSignatures, which I never liked due to the intimate bundling with the class declaration.
This is a statement that I can't necessarily get behind. I've got enough experience with DerivingVia to say that it is a pretty esoteric extension. The error messages are pretty bad, and it's easy to get bitten by the lack of higher-order roles (see also: roles). But more importantly, it's simply difficult to grasp how to use this extension, it's its own language inside the language. DerivingVia is likely to remain very advanced Haskell for quite a while. Whereas DeriveAnyClass is rather simple, even if fraught with subtle traps like we've discussed here; hence probably not worth including in our first round of default where we rather want to stay conservative, until we have fewer extensions to consider and we can scrutinise them more carefully.
participants (5)
-
Alejandro Serrano Mena
-
Joachim Breitner
-
Richard Eisenberg
-
Simon Peyton Jones
-
Spiwack, Arnaud