Uh oh!
There was an error while loading. Please reload this page.
RFC FS-1125 - print and println functions - #13597
Conversation
Since these functions would likely be the first functions beginners encounter, the XML documentation should either avoid use of technical jargon such as |
albert-du
commented
Aug 1, 2022
I changed the xml docs to remove references to stdout |
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Brian Rourke Boll <brianrourkeboll@users.noreply.github.com>
brianrourkeboll
commented
Aug 1, 2022
Note that |
Happypig375
commented
Aug 2, 2022
In that case, an explanation of what |
abelbraaksma
commented
Aug 3, 2022
@albert-du, I believe it is customary to mention the RFC also in the title of the PR (something like: |
albert-du
commented
Aug 4, 2022
@abelbraaksma Thank you! |
albert-du
commented
Aug 4, 2022
I adjusted the wording on the xml docs to add a remark describing stdout, it may need more depth but should suffice for a basic explanation. |
Happypig375
commented
Aug 4, 2022
Remarks won't be visible in Visual Studio tooltips though. |
albert-du
commented
Aug 4, 2022
Did not know that, @Happypig375 any idea how it should be done? |
Happypig375
commented
Aug 4, 2022
Probably as part of summary. |
vzarytovskii
commented
Aug 8, 2022
That looks good to me. One thought is that maybe in some future PR we can unify it to use printf, and have the latter to accept both plain string and format (via the when guards with type matches?). |
Happypig375
commented
Aug 9, 2022
@vzarytovskii Currently |
There was a problem hiding this comment.
Hey I was wondering, why it is restricted to strings, especially since TextWriter has a bunch of useful strongly typed overrides.
Did you consider a design looking like this:
open System
module PrintStuff =
let print<'T> (v'T) =
Console.Out.Write(v)
let println<'T> (v:'T) =
Console.Out.WriteLine(v)
The sig file looks like:
[<CompiledName("Print")>]
val print<'T>: v:'T -> unit
[<CompiledName("PrintLine")>]
val println<'T>: v:'T -> unit
Which would be really terribly useful like this:
module test =
PrintStuff.println $"{1} is not {2} see {1 <> 2}"
PrintStuff.println true
PrintStuff.println "one"
PrintStuff.println 1
PrintStuff.println 1.1
let x = 7.5
PrintStuff.println x
Produces output looking like:
C:\Temp\abc>Program.exe
1 is not 2 see True
True
one
1
1.1
7.5
You can print some blank lines using:
PrintStuff.println ()
PrintStuff.println ()
PrintStuff.println ()
PrintStuff.println ()
PrintStuff.println ()
Happypig375
commented
Aug 14, 2022
@KevinRansom One problem of that would be being easier to fall into the trap of globalization variances. |
KevinRansom
commented
Aug 14, 2022
This is what I see:, it looks like it is obeying international rules pretty much how I would expect:, am I missing something? And this is fsi |
Happypig375
commented
Aug 14, 2022
@KevinRansom That's what I mean: globalization will be implicit and will be unexpected for beginners, as that is not how corresponding code is written. |
@Happypig375, as long as internally the This principle of least surprise and idempotency regardless where your code runs is, I believe, one of the underpinnings of F#. So, if we use @KevinRansom’s suggestion, I think that’s the way to go. This would also give better predictability, as we won’t rely on any changes to |
KevinRansom
commented
Aug 14, 2022
I may have lost the thread somehow. Are we suggesting that the globalization mechanisms built into the CLR are wrong and should be avoided? |
We (at my current company) actually have a coding guideline for the opposite. Use F# type-safe formatting (i.e., use
Yeah, it's a tricky mess. I've fallen for the trap in your "code review" example many times. Just as often I asked a programmer (from USA): "how do you think this will render on my machine, you think your test will pass"? Since I'm in NL, it often won't.
The real question is: what do people expect? Most people are surprised that auto-internationalization is even a thing. If you write an English website, you don't want the numbers and dates to be localized in the native language of the user. And yes, this happens a lot: accidentally localized pages :). |
abelbraaksma
commented
Aug 16, 2022
One other big pool of bugs with these pitfals: serialization. We just uncovered major bugs where some programmers hand-crafted JSON serialization. Little did they know that the string interpolation would make their output different, depending where the code ran. it wasn't machine-parsable anymore. |
Update rfc to reflect discussion in dotnet/fsharp/pull/13597
@albert-du, I see you are updating this, and the RFC. But I'm not sure if there's consensus. @KevinRansom, what do you think? @dsyme, TLDR: we ended up discussing Bottom line of that discussion is, if we go the Differences are abound. I.e., do we want W.r.t Invariant Culture, if we do not go that route, it means that, just like We could vote. Choices:
|
Please note that ideally design discussion on the RFC would happen on the RFC discussion thread: fsharp/fslang-design#675 Still, let's continue here for now |
The approved RFC was for valprint:'T ->unitI don't think we can realistically make this change. A generic
Plus there's the problem that the generic functions are just less safe - e.g. you can easily end up printing an unapplied function value, which results in nothing useful, just some garbage ToString of a closure type. I honestly think it's Aside information about localization, please follow up at fsharp/fslang-suggestions#897 The design intent of FSharp.Core functionality has always been "use invariant culture unless explicitly specificed otherwise".
For visual outputs from F# Interactive, the user can specify Some of these issues are captured here: fsharp/fslang-suggestions#897 Finally, I'm surprised it's never been suggested that I'd encourage people to review https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/plaintext-formatting and contribute to it. There should really be a specific separate section on locales - there are mentions in the doc but a separate section should cover the above. |
albert-du
commented
Aug 16, 2022
I reverted the implementation back to the original rfc spec |
dsyme
commented
Aug 16, 2022
@albert-du This discussion has raised important questions. I'll do my best to capture these as unresolved questions in the text of the RFC. I think it's best to put the implementation on hold until we resolve those design questions. In private conversation Kevin is pretty adamant that the "use print to any data" scenario is under-represented in the discussion and that we shouldn't introduce a This is partly my fault, because in the design process I didn't adequately predict or list out the scope of the unresolved issues in the RFC. |
charlesroddie
commented
Aug 17, 2022
The suggestion A generic function would remove some of this simplicity for beginners. The type signature gets slightly more complex, and understanding what it does gets a lot more complex. It will add to the existing So I believe that |
vzarytovskii
commented
Aug 17, 2022
I think it is something we can easily compensate this with good XML docs and examples. The decision is tough because once the function is there (in FSharp.Core), there's no way back or no way of changing it, and it would be a shame if we waste such a great name for something we didn't give a good thought. That's why we have to thing really good about it. |
jasiozet
commented
Aug 17, 2022
I completely understand that this need to be very well thought out, because Fairly recently (less than year ago) I was a complete F# beginner and what I did use a lot when experimenting doing tutorials etc was: That was my newbish console debugging, but to be honest I still do it from time to time.
But I would actually want to open another angle of discussion. |
bisen2
commented
Aug 17, 2022
I definitely agree with Vlad that this deserves careful consideration before making a change that might be regretted down the line. My apologies for having been a bit preemptive in submitting the RFC and letting it get to the point of implementation before these concerns came up. Personally, I think that a generic |
NatElkins
commented
Aug 17, 2022
@jasiozet This is how adding lettest=0
printfn "%A" test // `printfn` is `Printf.TextWriterFormat<int -> unit> -> int -> unit` and `"%A"` is `Printf.TextWriterFormat<int -> unit>`.
printfn $"{test}"// `printfn` is `Printf.TextWriterFormat<unit> -> unit` and `$"{test}"` is `Printf.TextWriterFormat<unit>`
printn $"{test}"// `printn` is `string -> unit` and `$"{test}"` is `string`.Describing F# I would say that in F# you need to understand all the types involved and then the code will almost write itself.
It's possible but the A separate conversion to string step is more composed and explicit. But educationally, I believe understanding types fully is more important than understanding behaviour fully, so if users write |
dsyme
commented
Oct 27, 2022
Some interesting feedback here: fsharp/fslang-suggestions#1092 (comment) |
dsyme
commented
Oct 27, 2022
I'm now pretty convinced that if we add anything for I'll close this, as the implementation would be very different @albert-du I want to thank you again for your contribution and apologise for approving the "string" suggestion before taking into account enough points of view. This is on me, and we're immensely grateful for you taking the time to engage with this. |
ShalokShalom
commented
Jan 2, 2023
And where do we track the new implementation? |
@ShalokShalom, it’s a little bit all over the place, and some of it is captured in the RFC as unresolved questions (linked in the description). The discussion about the RFCs and to records decisions should go here: fsharp/fslang-design#675. Some discussion has happened in the original suggestion (linked from RFC) and in this thread (also linked from RFC). There’s also a wider encompassing suggestion to overhaul the text output printing and formatting stuff: fsharp/fslang-suggestions#897. |
@ShalokShalom (been a while, lol), I'm trying to spark renewed interest in this comment thread: fsharp/fslang-design#675 (comment) |



implements RFC FS-1125, fsharp/fslang-suggestions#1092
Adds print and println functions with examples.