Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add default IsString (Text, String) #610

Open
Bodigrim opened this issue Aug 10, 2024 · 10 comments
Open

Add default IsString (Text, String) #610

Bodigrim opened this issue Aug 10, 2024 · 10 comments

Comments

@Bodigrim
Copy link
Contributor

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

{-# LANGUAGE NamedDefaults #-}
default IsString (Text, String)

CC @blamario

@Bodigrim
Copy link
Contributor Author

Bodigrim commented Aug 10, 2024

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 Builders. What should they declare as defaults?

@blamario any suggestions?

@blamario
Copy link

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

  1. put default IsString (StrictText, String) into Data.Text,default IsString (LazyText, String) into Data.Text.Lazy, etc for builders;
  2. if necessary, and only if necessary, also add modules 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.

@Bodigrim
Copy link
Contributor Author

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?

@blamario
Copy link

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.

@Bodigrim
Copy link
Contributor Author

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 defaults.

The suggestion with *.Default modules does not feel appealing to me.

@blamario
Copy link

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.

@phadej
Copy link
Contributor

phadej commented Aug 13, 2024

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.

@blamario
Copy link

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.

@phadej
Copy link
Contributor

phadej commented Aug 13, 2024

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.

@phadej
Copy link
Contributor

phadej commented Aug 13, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants