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

print and printn alongside printf and printfn #1092

Open
5 tasks done
Happypig375 opened this issue Nov 6, 2021 · 25 comments
Open
5 tasks done

print and printn alongside printf and printfn #1092

Happypig375 opened this issue Nov 6, 2021 · 25 comments

Comments

@Happypig375
Copy link
Contributor

Happypig375 commented Nov 6, 2021

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 with printf:

  • It forces the notion of "f" - formatting, and all the variations on formatting specifiers
  • It does not take string, so
let x = "Hello world"
printf x

Would surprise beginners, and we have to

let x = "Hello world"
printf "%s" x
  • For formatting we should first introduce string interpolation anyways, since that understanding of formatting specifiers for it is optional.

Compare this with Python's print("Hello World") which has no f to understand.

Moreover, we already have failwith alongside failwithf, but no print alongside printf.

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 to fun x -> match x with.

List.iter (printfn "Here is an integer: %d") [1..9]
List.iter (fun i -> printn $"Here is an integer: {i}") [1..9]

I propose that we add two variations of print: print and printn, as printf and printfn variants that take strings.
Our "Hello World" is now as simple as Python's, even simpler without parentheses:

print "Hello World"

And this would work:

["String 1"; "String 2"; "String 3"]
|> List.iter print

Pros and Cons

The advantages of making this adjustment to F# are

  1. We can make a good impression with a simple 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
  2. Have an actual function that can print messages without adding an unnecessary %s
    and prevent subtleties like
let x = "Hello World"
printf x // Why is this not working!?
  1. Easier piping with pre-interpolated strings, |> 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 use stdout.Write and stdout.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:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement and/or test this

For Readers

If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.

@ghost
Copy link

ghost commented Nov 6, 2021

let x = "Hello World"
printf x // Why is this not working!?

can be written as

let x = "Hello World"
printf $"{x}"

@Happypig375
Copy link
Contributor Author

@dulanov When we have the $ for interpolation, the f "formatting" in printf becomes redundant.

@dsyme
Copy link
Collaborator

dsyme commented Nov 6, 2021

I like this suggestion. cc @KathleenDollard

@WhiteBlackGoose
Copy link

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?

@TheJayMann
Copy link

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?

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.

@cartermp
Copy link
Member

cartermp commented Nov 7, 2021

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 console
  • printn - prints to console with newline
  • printf - print with format string
  • printfn - print with format string with newline

I think that's the most reasonable, since changing this pattern will probably just get confusing to beginners once they get into formatted printing anyways.

@charlesroddie
Copy link

charlesroddie commented Nov 9, 2021

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

@dsyme
Copy link
Collaborator

dsyme commented Nov 9, 2021

Marking this as approved-in-principle. Since the design is simple by all means proceed straight to an RFC and PR :)

@KathleenDollard
Copy link

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!

@dsyme
Copy link
Collaborator

dsyme commented Nov 10, 2021

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.

@Happypig375
Copy link
Contributor Author

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

@zanaptak
Copy link

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.

@abelbraaksma
Copy link
Member

abelbraaksma commented Mar 27, 2022

For comparison, I counted what other languages commonly use (see Rosetta for with and without newline):

With newline (520 examples)

  • printfn: 1x (only F#)
  • print: ~100-150x (hard to measure, quite a few require a \n explicitly added, and some others don't)
  • printn: 1x
  • println: 48x
  • put: 9x
  • puts: ~20x
  • putln: 1x

Some have other syntax, obviously, like write or cout, but let's stick to the variants closest to what we already have.

Without newline (171 examples)

  • print: ~70-90x (again hard to measure, but ~35-50% of all languages)
  • prints: 1x
  • printf: ~20x
  • puts: 3x
  • put: 5x

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

@charlesroddie
Copy link

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.

@brianrourkeboll
Copy link

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 stdoutstderr symmetry.

@Happypig375
Copy link
Contributor Author

Happypig375 commented Aug 2, 2022

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?

@abelbraaksma
Copy link
Member

abelbraaksma commented Aug 3, 2022

For future reference, the final RFC 1125 is here, in case you missed it. And a PR is underway, see dotnet/fsharp#13597, great work @albert-du!

@dsyme
Copy link
Collaborator

dsyme commented Aug 16, 2022

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 #897 and dotnet/fsharp#13597.

I think this puts the RFC and this suggestion on ice somewhat.

@abelbraaksma
Copy link
Member

abelbraaksma commented Aug 16, 2022

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

@dsyme
Copy link
Collaborator

dsyme commented Aug 16, 2022

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

@abelbraaksma
Copy link
Member

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.

@abelbraaksma
Copy link
Member

abelbraaksma commented Aug 19, 2022

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.

@AdamBebko
Copy link

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! 🙏

@dsyme
Copy link
Collaborator

dsyme commented Oct 27, 2022

@AdamBebko Thank you for this feedback!

@abelbraaksma
Copy link
Member

abelbraaksma commented May 24, 2024

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.

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

No branches or pull requests