Their implicit nature makes it easy to forget to initialize all fields if you don’t have the right warnings on:
data Foo = MkFoo { a :: Int, b :: String }
mkFoo :: IO Foo
mkFoo =
a <- ...
b <- ...
-- good luck catching this if Foo's fields ever changes
pure (MkFoo {..})
NamedFieldPuns are a much better way to support this style.
Thanks for the replies on RecordWildCards. Am I correct to understand that those are reasons not to use it, if it is available, as opposed to reasons not to have it available? (I am contrasting with OverloadedStrings, where it was explained that having it available could break some existing code.)
My interest is that the Stack code base uses it widely, in about 30 of its 183 modules. An example of use is:
-- | Interprets BuildOptsMonoid options.
buildOptsFromMonoid :: BuildOptsMonoid -> BuildOpts
buildOptsFromMonoid BuildOptsMonoid{..} = BuildOpts
{ boptsLibProfile = fromFirstFalse
(buildMonoidLibProfile <>
FirstFalse (if tracing || profiling then Just True else Nothing))
...
-- 26 other fields relying on the 31 fields of a `BuildOptsMonoid` value
...
, boptsDdumpDir = getFirst buildMonoidDdumpDir
}
where
...
Am I correct to understand that those are reasons not to use it, if it is available, as opposed to reasons not to have it available?
I totally agree with you. I think the argument against any extensions being part of GHCxxx (or Haskellxx) is that by accepting it, it will be there forever. By not accepting it, we keep the door open for a new extension with a better design superseded the previous one. A bit like type families was seen as making functional dependencies obsoletes and then not … so we keep both.
However, we all know that it is really unlikely that something come and make RecordWildCard obsolete (let alone removing it).
I am in the opinion that pretty much every thing which has been implemented, enhance the user experience and doesn’t break any code should be included by default.
I think that inclusion of an extension in GHC20XX should also mean that the extension is hard to abuse by those who are unfamiliar with the extension and their possible harmful consequences. Or conversely, if an extension is included then everyone should be encouraged to check it out and try to use it in their programs.
That’s why I am for extensions like RoleAnnotations which are necessary for safety in some cases, and against including things like GADTs and TypeFamilies which often make code overly complicated.
I think RecordWildCards is in a bit of a grey area. It can remove a lot of clutter when dealing with large records, but you need to be careful and enable warnings.
So there is, possibly, an interaction between the choice of a default set of LANGUAGE pragmas and the bundling of GHC warnings (including in project templates: Stack project templates and GHC warnings). In that regard, -Wall includes -Wincomplete-record-updates.
Having been following this conversation, I wonder if we can at least identify the following extensions as being uncontroversial?
LambdaCase
DerivingStrategies
DerivingVia
Also, following this line of thought, it might perhaps be a good idea to make a survey where people can vote both for and against language extensions… in fact, now that I think of it, @taylorfausak did exactly that in the 2022 State of Haskell Survey. Interestingly, I note that OverloadedStrings seemed a lot more popular there than it has been here — I wonder why?
On OverloadedStrings and ‘it breaks existing code heavily’, is there anything that can be done to get a sense of that as a matter of practice (as opposed to as a matter of principle)?
As an experiment, I set OverloadedStrings as default for Stack (default-extensions), deleted my snapshot database (so all of the 176 direct and indirect dependencies would be rebuilt), and rebuilt Stack. Nothing complained. (EDIT: Actually, rebuilding the dependencies may have been pointless; I think the OverloadedStrings default may not affect the dependencies.)
I wondered if, say, one could take the set of 3,000+ package versions in the latest Stackage LTS snapshot (or, perhaps, some older snapshot - if the past is more relevant that the current) and attempt to build them with it as a default, that might provide some intelligence about the extent of code breakage in practice. (EDIT: I see that the effect on packages in Stackage was a consideration when ‘Foldable Traversable in Prelude’ was being considered: Foldable Traversable In Prelude - HaskellWiki).
At this rate, I wonder if any extensions are suitable for GHC2024. If we get it at all, I imagine we’ll have to make compromises somewhere along the line — some people will be unhappy, but that’s how it is.
Yes, I just think it is not a good idea to add even more ways to trigger that unsafety to the default language. As I said:
I wouldn’t want to encourage everyone to start using coerce everywhere and so I don’t want to encourage everyone to use DerivingVia everywhere either.
But I think there is a relatively easy fix: declare once and for all that Data.Coerce is safe (and perhaps check Hackage for unsafe existing code). If we can collectively make that decision (and we improve the error messages) then I think it is fine to add DerivingVia.
The desire to consider Data.Coerce to be Safe is also the motivation for including RoleAnnotations in GHC2024, to indicate that these days, if you want to define an abstract data type, you really have to think about roles as well.
My vote, unavailable in the poll, is this: require GHC2024, whatever it implies, to be specified explicitly. If there’s no {-# LANGUAGE GHCxxxx #-} pragma then the default should be {-# LANGUAGE Haskell2010 #-}.
I, for one, am happy GHC2021 exists so we can use it in our production codebase. Adding a few more syntactic sugar pragmas and other pragmas with explicit “opt-in” syntax would also be appreciated
(e.g. DerivingStrategies, that you don’t use unless you add keywords in specific places)
I’m aware of that. I also think it was a mistake. It may be too late to fix the mistake now, but if not, the time to do it is when the new default is set.
Back on topic: Haskell is becoming and will become a relatively large language. It is convenient and most likely the right path, but I am happy to have hopped in when everything was easier to grasp, because there were less things to learn, and now and then a blog-post popped up with a new extension tutorial.