Open Happypig375 opened 2 years ago
let x = "Hello World"
printf x // Why is this not working!?
can be written as
let x = "Hello World"
printf $"{x}"
@dulanov When we have the $
for interpolation, the f
"formatting" in printf
becomes redundant.
I like this suggestion. cc @KathleenDollard
I didn't use old versions of F#, so I've in fact always used string interpolation instead of formatted strings 😄 , even when need to print a single object.
Though print
will not add a new line at the end, which... might be a bit counter-intuitive?
I didn't use old versions of F#, so I've in fact always used string interpolation instead of formatted strings 😄 , even when need to print a single object.
Though
print
will not add a new line just like printf
today does not add a new line. That is the purpose of the also proposed printn
function, which will add a new line, just like printfn
does currently.
I think it's worth a quick survey of some languages with a good learning curve and what all they do:
Python
print("yeet")
-- prints "yeet"
and a new line
print("yeet", end="")
-- prints "yeet"
without the new line
JavaScript
console.log("yeet")
-- prints "yeet"
and a new line
...much more complicated to print without the new line, ranging from process.stdout.write("yeet")
to implementing a virtual browser console
Go
fmt.Println("yeet")
-- prints "yeet"
and a new line (recommended via hello world everywhere)
fmt.Print("yeet")
-- prints "yeet"
but without a new line
fmt.Printf("yeet")
-- more general-purpose printer with format strings, does not append a new line
Swift
print("yeet")
-- prints "yeet"
and a new line
print("yeet", terminator:"")
-- prints "yeet"
with no new line
I've excluded C/C++/Java/C# and don't think they're worth looking at.
This suggestion would make F# the most like Go in this list:
print
- print to consoleprintn
- prints to console with newlineprintf
- print with format stringprintfn
- print with format string with newlineI think that's the most reasonable, since changing this pattern will probably just get confusing to beginners once they get into formatted printing anyways.
This is great. Currently to understand the typical beginning F# program printf "Hello world"
(including the types involved), one needs to learn about type-directed inference and TextWriterFormat
, concepts that are not even included in "Expert F#". This addition will mean that being an F# expert is not necessary to start learning F#.
Marking this as approved-in-principle. Since the design is simple by all means proceed straight to an RFC and PR :)
I'd like us to consider println
instead of printn
printn
parallels printfn
, sure. But, for a beginner, what the heck is "n"? "ln" is clearly an abbreviation for "line".
I could also see printline
But it's a great idea, and other than thinking we should reconsider syntax, I love it!
It feels like for consistency we have to use printn
. It feels wrong to have all of println
, printfn
and WriteLine
in the experience. But let's consider.
I see parallels between println
and printfn
in that fn
would expand to formatted ln
, but n
itself can also be interpreted as newline
too. Hmm
How about write
and writeLine
? Rather than 4 print*
functions that differ by 2 chars (not to mention kprintf/sprintf/etc. variations), it would leave the printf
"family" of functions isolated for traditional formatting, and have a more distinct separation for the new functions.
For comparison, I counted what other languages commonly use (see Rosetta for with and without newline):
printfn
: 1x (only F#)print
: ~100-150x (hard to measure, quite a few require a \n
explicitly added, and some others don't)printn
: 1xprintln
: 48xput
: 9xputs
: ~20xputln
: 1xSome have other syntax, obviously, like write
or cout
, but let's stick to the variants closest to what we already have.
print
: ~70-90x (again hard to measure, but ~35-50% of all languages)prints
: 1xprintf
: ~20xputs
: 3xput
: 5xAll in all, it appears that languages that have print
and println
are far in the majority. Some only have print
, sometimes with optional args for the terminator.
I know that we don't "have to do what other languages do" just for the sake of it, but for easy discovery, and considering that printn
is only used by one obscure language, my vote is for the pair of print
and println
as that seems by far the most common in the world.
There should be no syntax for printing without a new line, as that just creates a pitfall for users. Printing without a new line is an very rare thing to want to do. Most of the time someone writes *printf
, the output is unexpected and that *printfn
is intended.
For printing (with a newline) I like print
, printLine
, printLn
, printn
in that order, noting that there will be very few places where it is best to use an old *printn
function given this suggestion and existing interpolated strings, so existing precedents in F# don't need to outweigh what is common in other languages.
Should eprint
and eprintln
be considered as well, for parity's sake? They're less likely to be used by beginners, but it would seem somewhat odd not to keep the existing stdout
– stderr
symmetry.
stderr
seems to be a much more advanced concept than just the console output. Would introducing this be desirable?
Will bprintfn
/fprintfn
etc have parity as well? When to stop?
For future reference, the final RFC 1125 is here, in case you missed it. And a PR is underway, see https://github.com/dotnet/fsharp/pull/13597, great work @albert-du!
Based on the PR discussion thread I've clarified a number of important unresolved issues regarding the PR - most notably whether the functions should be generic, and if so what should their spec be.
@KevinRansom feels strongly that we should not add non-generic print
given the potential future utility of a generic print
- if we can iron out enough wrinkles. Despite having approved the simple non-generic version in this suggestion I can see his point. Additionally, the reliance on interpolated strings print $"..."
to print arbitrary objects means the wrinkles concerning %A
formatting come more to the fore if we add the generic version of this, again discussed in https://github.com/fsharp/fslang-suggestions/issues/897 and https://github.com/dotnet/fsharp/pull/13597.
I think this puts the RFC and this suggestion on ice somewhat.
@dsyme, I noticed that you reverted the RFC's function back from println
to printn
. I know it is only one letter, but you stated above "Let's consider", and in this comment I showed what common names were "in the wild" for such functions.
To follow the principle of least surprise, this would bring us to print & println
(150+ and 50-something times resp.), which is well understood, where printn
happens to exist in only one other language.
I'll certainly be able to live with printn
though, I just find it a very odd name and think parity with existing practice in other language (when and where applicable) makes sense for easier adoption. And I'm not alone in that opinion.
@abelbraaksma Yes the consistency argument is too strong IMHO - I just can't justify another abbreviation for "Line" in FSharp.Core. People got used to printfn
(which was introduced by F#), they'd get used to printn
.
In any case, the title of this suggestion was always print
and printn
, and to the extent we can go ahead with it at all we should stick to that.
Ok, fair enough. In the end there'll always be tooling that shows what we have once we start typing pri
, so the burden on newcomers won't be that large.
For reference, here's a good motivational example of how newcomers (still) struggle with this: https://stackoverflow.com/questions/73416468/hello-printfn-generates-an-error-in-f.
I’m a fairly seasoned C# and python developer and tonight attempted my first foray into F# to potentially use as a tool to teach undergrad intro stats. I currently use either Python or R.
Based on my research and initial trials it has huge potential over python. No virtual environments, easy to install, no anaconda, no silly dynamic typing. No silly this
everywhere in classes. 😃
However, I spent literally an hour trying to figure out why you had to do string formatting to print simple things. I even made a stackoverflow question before stumbling upon this thread. https://stackoverflow.com/q/73823075/4163879
I really support this thread. However, I really hope you all consider just making print()
do what everyone expects it to do and not even include println
. Imagine trying to teach a class of 90 undergrads with no programming experience why print is NOT what that want, and instead that they need to use println
. 🧐“Why?!” They will inevitably ask. To which my answer will be, “because the world hates you and doesn’t want you to learn programming”.
I can already picture 3 students coming to me after the first class in tears because they need to pass my class to continue their degree and their program isn’t working because print
doesn’t add a new line. 😓
Do the right thing. Anyone who wants to print without a new line will already have the skills required to Google it and figure out another function. F# has so much potential to beginners. Please make it easy on them. Add print, and make it add a new line. I implore you! 🙏
@AdamBebko Thank you for this feedback!
For posterity (someone asked):
Afaik, there's currently no new work being done on this, though imo, there's still a strong want for an implementation here, so let's give this another chance.
print and printn alongside printf and printfn
Currently, F#'s "Hello World" looks like this:
printf "Hello World"
We currently couple formatting with printing to the console, as introduction. Problems withprintf
:Would surprise beginners, and we have to
Compare this with Python's
print("Hello World")
which has no f to understand.Moreover, we already have
failwith
alongsidefailwithf
, but noprint
alongsideprintf
.With string interpolation in F# 5, printf formatting should be considered the partial application friendly version of string interpolation when used with lambdas, like
function
is tofun x -> match x with
.I propose that we add two variations of
print
:print
andprintn
, asprintf
andprintfn
variants that take strings. Our "Hello World" is now as simple as Python's, even simpler without parentheses:And this would work:
Pros and Cons
The advantages of making this adjustment to F# are
print "Hello World"
and avoid introducing printf formatters with the "f" in "printf" too early, rather going for interpolation first, and formatting later with partial application|> List.iter (printfn "%s")
vs|> List.iter print
The disadvantages of making this adjustment to F# is another way to do the same thing. However, it can make introductions to beginners easier. Without
print
, we can still usestdout.Write
andstdout.WriteLine
but with quirks related to inference of overloaded methods. Moreover, this also requires teaching the dot notation earlier.Extra information
Estimated cost (XS, S, M, L, XL, XXL): XS
Related suggestions: (none)
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
For Readers
If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.