Open Bodigrim opened 3 months ago
Not sure how to fit lazy Text
though. Should Data.Text
export default IsString (StrictText, String)
and Data.Text.Lazy
export default IsString (LazyText, String)
? But then if someone exports both, defaults will clash and annihilate.
We can put default IsString (StrictText, String)
into Data.Text
and then default IsString (LazyText, StrictText, String)
into Data.Text.Lazy
. If someone exports both, defaults will subsume one another resulting in the latter one. Yet in this case pretty much any string literal will be lazy Text
, which is not terribly helpful.
What I don't know is whether defaults are imported through qualified imports.
There are also Builder
s. What should they declare as defaults?
@blamario any suggestions?
My understanding is that the use of strict lazy text is approximately evenly divided in practice, so there's no reason to prefer one over the other. My preferred choice would then be to
default IsString (StrictText, String)
into Data.Text
,default IsString (LazyText, String)
into Data.Text.Lazy
, etc for builders;Data.Text.Default
and Data.Text.Lazy.Default
which would re-export the parent module as well as default IsString (StrictText, LazyText, String)
and default IsString (LazyText, StrictText, String)
respectively, with the sole purpose of resolving the ambiguity.My understanding is that the use of strict lazy text is approximately evenly divided in practice, so there's no reason to prefer one over the other.
In general yes, but for literal strings I'd imagine strict Text
to be much more relevant, because there is no point to chunk it.
What I don't know is whether defaults are imported through qualified imports.
Could you please clarify this?
Yes, any import of a module will import all the defaults it exports. Same behaviour as with class instances, except the latter are also implicitly exported.
The thing is that people commonly import all three modules at once. This is especially true for Builder
and lazy Text
: I can barely imagine a module that imports Data.Text.Lazy.Builder
but not Data.Text.Lazy
. If would be unfortunate if such common situation annihilates conflicting default
s.
The suggestion with *.Default
modules does not feel appealing to me.
If would be unfortunate if such common situation annihilates conflicting defaults.
If and when it does, the one-line fix would be to add a de-conflicting default
declaration to the importing module. That's why I said I'd add the *.Default
modules only if necessary, i.e. if the user base clamours for an even easier solution.
One can imagine a use case where having default IsString (String)
but also using text
is desirable. It feels that the exportable defaults are just lacking in that respect. (In particular, why wouldn't Prelude
export default IsString (String)
? There are Num
defaults, and maybe I want Int
instead of Integer
99% of the time)
I feel, that it's better for text
to not do anything in source, but add a note in the documentation, so the users who need could add default IsString (Text)
to their modules. Note that asking people to do default IsString (Text)
themselves is virtually the same as providing *.Default
module proposed above.
One can imagine a use case where having default IsString (String) but also using text is desirable.
A default
declaration doesn't prevent you from using text
, or anything else for that matter: if a module already compiles, it will continue compiling with additional defaults exactly the same.
why wouldn't Prelude export default IsString (String)?
The Prelude
could export default IsString (String)
. As per above, this wouldn't break anything, and it would be a precondition for adding OverloadedStrings
to the GHC2025
edition.
this wouldn't break anything
Yes, but it will break utility of default IsString (Text)
as proposal says
If a class has neither a local default declaration nor an imported default declaration that subsumes all other imported default declarations for the class, the conflict between the imports is unresolvable.
So if there are exported default IsString (String)
in Prelude
, and default IsString (Text)
in Data.Text
, then as far as I understand for all users of Prelude
and Data.Text
the situation will be as without any defaults, i.e .as today.
OTOH, if default IsString (String, Text)
(or (String, StrictText, LazyText, Builder)
is added, then some other library with own type (e.g. os-string
) will then conflict still. The default
doesn't seem to behave well in diamond dependency graphs.
Also note, the extra default IsString (Text, String)
may change the code which used to see default IsString (String)
only. That would be spooky action at the distance: an added import (at least slightly) changing the result of elaboration!
GHC will pick the first type which satisfies all constraints, but if Text
and String
both satisfy everything, then it will flip.
Once https://gitlab.haskell.org/ghc/ghc/-/merge_requests/11853 is merged (which is presumably in time for GHC 9.12), we should add under appropriate CPP guard
CC @blamario