text
text copied to clipboard
Add tshow function
In multiple different projects that I have worked on I've encountered variations on the following function:
tshow :: Show a => a -> Text
tshow = T.pack . show
It would be great if the text package could add this to eliminate the redundancy and confusion.
A variant of this has been proposed before (and rejected) in https://github.com/bos/text/issues/106.
That's actually a different thing. The text-show package gives you a standalone type class specifically for the purpose of converting to a Builder. I'm specifically talking about the existing Show class. That package also has more dependencies than text, and is therefore not an acceptable answer for what I want.
Perhaps it would make sense as Data.Text.show? In the spirit of many other functions that are defined in Data.Text and generally imported qualified (e.g. null, map, reverse, etc.), this would be a direct analogy of Prelude.show.
I don't have much of an opinion what the name is. I'm just interested in squashing the unnecessary proliferation and fragmentation of pointless reimplementations of this function.
Hi there! Is this issue still relevant? If so, would any of the maintainers be interested in providing some mentorship/general help on resolving this so that the newcomers and first-time contributors would have an easier time?
I would like to add this as one of the issues for the upcoming Haskell Weekly's Call for Participation section. See discussion in #75.
These are the guidelines we'd like to stick to in the future:
- Ensure that your project has at least one open-source licence. (we've decided to not define the term "open-source" and it is left to your own interpretation).
- Ensure that the issue tracker for your project is publicly accessible.
- Create a new issue in your issue tracker and clearly describe the task. Also mention the difficulty level (easy/medium/hard/tedious), either as a tag/label or somewhere in the title/description.
- If you have specific requirements for contributors (e.g., copyright waiver), it must be mentioned in the description of the task (preferably with a link to CONTRIBUTING.md).
Thank you!
This is definitely still relevant, and it's a very easy issue to fix. The main question at this point is maintainer buy-in.
Personally, I've written this function upwards of 20 times. +1
I'd prefer the minimum possible code for a performant text show be added to text and to implement this function with that.
On Jul 13, 2017 11:59 AM, "Remy Goldschmidt" [email protected] wrote:
Personally, I've written this function upwards of 20 times. +1
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bos/text/issues/183#issuecomment-315139223, or mute the thread https://github.com/notifications/unsubscribe-auth/AANyNy8i4HiUZMy0dTDc5OvTSlRbINXfks5sNkzVgaJpZM4NmxR5 .
@codygman That makes sense, although I think there might actually be two different things people are talking about here:
- An alias for
T.pack . show, just because it's super annoying to type that out all the time. - A more performant way of producing
Textrepresentations of datastructures
To me, these both seem very useful, and possibly quite different. For (2), I'm not sure what kinds of implementations people have in mind, but it seems like it might be a lot more involved than (1). In particular, it's not clear to me whether or how we can enforce that (2)'s instances agree with "classic" Show instances.
If it makes sense to others here, I would personally really like to see a solution to (1) happen independently of (and sooner than) a solution to (2). However, I can't say I've thought about the matter deeply, and I certainly wouldn't want something introduced that makes things tougher down the line.
Indeed, I'd be fine with fixing (1) in isolation.
As for (2), there are a number of solutions currently available. There's @bos's own text-format, and there's also my own text-show library, which aims to be character-for-character compliant with Show for Strings.
This issue is specifically asking for (1), not (2).
Sure, I'm not proposing that we implement (2) in text. (I only mention it since some folks here appear to want (2), or are at least waggling their eyebrows furtively in that general direction.)
2 would address 1 wouldn't it? I think that adding the a show based version goes against the performant nature of the text library.
I envision hundreds of future newbie's recounting experiences along the lines of:
"I tried the string library and it was slow, I tried text (using Text.show) and it was slow. Haskell is slow"
This can be avoided by only providing 2 without any loss in functionality.
On Jul 13, 2017 3:52 PM, "Ryan Scott" [email protected] wrote:
Sure, I'm not proposing that we implement (2) in text. (I only mention it since some folks here appear to want (2), or are at least waggling their eyebrows furtively in that general direction.)
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bos/text/issues/183#issuecomment-315198793, or mute the thread https://github.com/notifications/unsubscribe-auth/AANyN66Jpd1a5dCHNeU9DMYhHEVAKqGMks5sNoOQgaJpZM4NmxR5 .
@codygman No, 2 does not address 1. Sometimes you actually want the existing Show type class. If we could rewind the clock and make Show render to Text instead of String, then 2 could address 1. But we can't, and therefore there are times when you specifically want Show because that is what is used by other code. It also should not be called show because that conflicts with the function exported by Show. It should be called tshow or something similar.
I'd like this too! I've had tshow and tlshow available in most code I've written. Since these functions would be going into Data.Text/Data.Text.Lazy modules directly then I'd call them both show -- there's plenty of name overlap already, so people are already accounting for that.
@godygman I don't think hurt to the reputation about being slow will be an issue since due to the same overlap issue newbies need to do some work to actually use these functions, either by hiding show from prelude or explicitly qualifying it. In both cases they would probably encounter the documentation which explains the implications.
Sorry, folks, I'm not going to take this. I know this is a widely used function, but saving 5 or 6 keystrokes isn't worth expanding an already-big API.
Hey Bryan, it's really about a lot more than 5 or 6 keystrokes. It's about uniformity and standardization. In different places and projects I've seen it called tshow, showt, and present. This presents a much higher cognitive overhead for everyone because people have to remember which variant is being used in the context they're currently working in. On top of this, people have to figure out where to put the function, as it doesn't have an obvious home in those contexts. The payoff / effort ratio is really high here.
I revisited this ticket a few times, and however I try to persuade myself in the argument of @bos, my opinion remains unwavered. I must respectfully express my disagreement. I am also going to support it by mathematics.
- The bigger the interface, the relatively cheaper is an addition of a single new entry point. ("A drop in an ocean.") At the same time, the speed of search in a large collection could be made logarithmic , thus allowing for very large (multiple volumes) paper dictionaries and encyclopediae. No one keeps the whole
Textinterface in their head at once anyway. Yet again, the performance of any individual function or the size of the build products would barely be affected beyond statistical significance, and even if they were, it would be filed as a GHC bug. Therefore the argument to an "already big" API does not stand, neither in humanitarian nor technological regard. - The longer the people have to type
(pack . show), read(pack . show)with their eyes and mind, and define their owntshowaliases, the more savings accumulate. I would say the amount saved is the integral of the use of the library over time, so the more popular Haskell andTextbecome, the more keystrokes per second would be saved. Therefore, the argument to "saving 5 or 6 keystrokes" does not stand. (The basic version of this consideration was put forward by Edsger Dijkstra in EWD1300.)
The strategic consideration that I do not see mentioned before is that Text is supposed to supersede String in most regards. It already offers a replacement for many Stringy Prelude functions, such as readFile. There is no reason to make Show an exception, and, while it is infeasible to change the type of Prelude.show at the moment, there is nothing to fetter the provision of a drop-in replacement that is automagically consistent with the usual show.
In JavaScript, there would already be a widely used single function package on npm solving this problem. Haskell does not have this micropackage culture, so the maintainer is the king. This one time, the king's judgement is unsound.
It is Monday, 3 of October 2022. I am writing this function again.
@Bodigrim please revisit this situation.
Ideally maybe we can also add tread ∷ Read α ⇒ Text → Maybe α, such that tread ∘ tshow = Just for standard types.
If we cannot even add this small function, then how can we ever hope to replace String with Text in base?
Fundamentally I'd like tshow = Data.Text.pack . Prelude.show to be clear about its performance, which is even worse than Prelude.show itself, because an entire String must be allocated to calculate its length, while Prelude.show can at least in theory fuse.
I have a question to the proponents of tshow. Why isn't text-show satisfactory enough for you?
I definitely had written code like toUrlPiece (UserId i) = tshow i, where i :: Int and toUrlPiece @UserId :: UserId -> Text, in fact http-api-data itself provides showTextData which by default uses Show. (I probably should change that to always use text-show, but I'm not in the mood doing major releases atm).
TL;DR existence of text-show is hard to remember (or know!) and such a nuisance to use if I only want to convert an Int to a Text.
EDIT: also Show is easy to derive for about anything and is derived for most types in other libraries, text-show is barely used. So if say a logger takes Text and you want just put something there, tshow is very tempting.
Converting Int to Text is stupidly difficult indeed, I'm absolutely open to offering foo = Data.Text.Lazy.toStrict . Data.Text.Internal.Builder.toLazyText . Data.Text.Lazy.Builder.Int.decimal from Data.Text, as this often involves importing three otherwise redundant modules.
Wrt discoverability, we can certainly advertise text-show directly from class Show haddocks in base.
Let me put it this way: the right thing to do is to use text-show. I'm worried that offering tshow from text will quash any incentive to do the right thing.
I think that a somewhat loud or at least hard to ignore message discouraging users from using Show and to default to text-show would strike a good balance.
@codygman ... Show isn't bad. It's bad if the end goal is to convert to Text, but that's not the only use-case for Show.
Let me put it this way: the right thing to do is to use
text-show. I'm worried that offeringtshowfromtextwill quash any incentive to do the right thing.
I strongly disagree. You cannot impose a one-size-fits-all definition of right in this situation. They're two different type classes and they have two different purposes. As I mentioned above, if I'm using Show (and therefore thinking about tshow), I almost never want text-show. I want Show and precisely Show because there's a whole ecosystem of reasons to use Show. If I want something more suited to performance or whatever my purposes are, I usually make something specific to my needs rather than bringing in a new dep like text-show (which is also not all that light). If you feel that strongly about the performance ramifications of tshow just slap a big fat haddock warning and be done. I just want to stop rewriting this function every time I start a new Haskell project.
They're two different type classes and they have two different purposes.
Could you please elaborate? TextShow is char-to-char compatible to Show.
In the vast majority of situations I don't care about char-to-char compatibility or performance. I care about avoiding an additional (heavy) dep way more.
The dependency footprint for text-show is less than, say, for aeson. Which of dependencies are the most problematic from your perspective?
All of them. You shouldn't have to incur a single extra dependency just to get a composition of two functions you're already depending on. It would still be unacceptable if its only dependency was base.