diff --git a/docs/release-notes/.FSharp.Core/10.0.300.md b/docs/release-notes/.FSharp.Core/10.0.300.md index c6012363182..125844e2a49 100644 --- a/docs/release-notes/.FSharp.Core/10.0.300.md +++ b/docs/release-notes/.FSharp.Core/10.0.300.md @@ -2,6 +2,8 @@ ### Added +* Added generic `print` and `println` functions (`'T -> unit`) to `ExtraTopLevelOperators` for simple value printing to stdout. ([RFC FS-1125](https://github.com/fsharp/fslang-design/blob/main/RFCs/FS-1125-print-printn-functions.md), [PR #19265](https://github.com/dotnet/fsharp/pull/19265)) + ### Changed * Added complexity documentation (Big-O notation) to all 462 functions across Array, List, Seq, Map, and Set collection modules. ([PR #19240](https://github.com/dotnet/fsharp/pull/19240)) diff --git a/src/FSharp.Core/fslib-extra-pervasives.fs b/src/FSharp.Core/fslib-extra-pervasives.fs index 924f057b7e1..e99ebc63e2c 100644 --- a/src/FSharp.Core/fslib-extra-pervasives.fs +++ b/src/FSharp.Core/fslib-extra-pervasives.fs @@ -277,6 +277,14 @@ module ExtraTopLevelOperators = let eprintfn format = Printf.eprintfn format + [] + let print (value: 'T) = + Console.Out.Write(string value) + + [] + let println (value: 'T) = + Console.Out.WriteLine(string value) + [] let async = AsyncBuilder() diff --git a/src/FSharp.Core/fslib-extra-pervasives.fsi b/src/FSharp.Core/fslib-extra-pervasives.fsi index 1e38995a2bd..41234811a34 100644 --- a/src/FSharp.Core/fslib-extra-pervasives.fsi +++ b/src/FSharp.Core/fslib-extra-pervasives.fsi @@ -56,6 +56,33 @@ module ExtraTopLevelOperators = [] val eprintfn: format: Printf.TextWriterFormat<'T> -> 'T + /// Converts the value to a string using the string operator and writes it to the standard output. + /// + /// The value to print. + /// + /// + /// + /// print "Hello, " + /// print "World!" + /// // output: Hello, World! + /// + /// + [] + val print: value: 'T -> unit + + /// Converts the value to a string using the string operator and writes it to the standard output, followed by a newline. + /// + /// The value to print. + /// + /// + /// + /// println "Hello, World!" + /// // output: Hello, World! + /// + /// + [] + val println: value: 'T -> unit + /// Print to a string using the given format. /// /// The formatter. diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl index 5bd39b09a39..617e5087293 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -1073,6 +1073,8 @@ Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToStringThenFail[T,TR Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToString[T](Microsoft.FSharp.Core.PrintfFormat`4[T,Microsoft.FSharp.Core.Unit,System.String,System.String]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToTextWriter[T](System.IO.TextWriter, Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormat[T](Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValue[T](T) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValueLine[T](T) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceExpression[T](Microsoft.FSharp.Quotations.FSharpExpr`1[T]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceUntypedExpression[T](Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Core.ExtraTopLevelOperators: T[,] CreateArray2D[a,T](System.Collections.Generic.IEnumerable`1[a]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl index 8096acb15a1..779e1740d75 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -1073,6 +1073,8 @@ Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToStringThenFail[T,TR Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToString[T](Microsoft.FSharp.Core.PrintfFormat`4[T,Microsoft.FSharp.Core.Unit,System.String,System.String]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToTextWriter[T](System.IO.TextWriter, Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormat[T](Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValue[T](T) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValueLine[T](T) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceExpression[T](Microsoft.FSharp.Quotations.FSharpExpr`1[T]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceUntypedExpression[T](Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Core.ExtraTopLevelOperators: T[,] CreateArray2D[a,T](System.Collections.Generic.IEnumerable`1[a]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl index 95ebeea8a37..61e0d754a3f 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -1076,6 +1076,8 @@ Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToStringThenFail[T,TR Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToString[T](Microsoft.FSharp.Core.PrintfFormat`4[T,Microsoft.FSharp.Core.Unit,System.String,System.String]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToTextWriter[T](System.IO.TextWriter, Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormat[T](Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValue[T](T) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValueLine[T](T) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceExpression[T](Microsoft.FSharp.Quotations.FSharpExpr`1[T]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceUntypedExpression[T](Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Core.ExtraTopLevelOperators: T[,] CreateArray2D[a,T](System.Collections.Generic.IEnumerable`1[a]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl index c4106d360c4..551b1c2bd80 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -1076,6 +1076,8 @@ Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToStringThenFail[T,TR Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToString[T](Microsoft.FSharp.Core.PrintfFormat`4[T,Microsoft.FSharp.Core.Unit,System.String,System.String]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormatToTextWriter[T](System.IO.TextWriter, Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T PrintFormat[T](Microsoft.FSharp.Core.PrintfFormat`4[T,System.IO.TextWriter,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValue[T](T) +Microsoft.FSharp.Core.ExtraTopLevelOperators: Void PrintValueLine[T](T) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceExpression[T](Microsoft.FSharp.Quotations.FSharpExpr`1[T]) Microsoft.FSharp.Core.ExtraTopLevelOperators: T SpliceUntypedExpression[T](Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Core.ExtraTopLevelOperators: T[,] CreateArray2D[a,T](System.Collections.Generic.IEnumerable`1[a]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj b/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj index 16e45542174..b250d992e5e 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj @@ -73,6 +73,7 @@ + diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Core/PrintTests.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Core/PrintTests.fs new file mode 100644 index 00000000000..e70ce3928a9 --- /dev/null +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Core/PrintTests.fs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +// Various tests for: +// Microsoft.FSharp.Core.ExtraTopLevelOperators.print +// Microsoft.FSharp.Core.ExtraTopLevelOperators.println + +namespace FSharp.Core.UnitTests + +open System +open System.IO +open Xunit + +[] +type PrintTests() = + + let captureConsoleOut (f: unit -> unit) = + let oldOut = Console.Out + use sw = new StringWriter() + Console.SetOut(sw) + try + f () + sw.ToString() + finally + Console.SetOut(oldOut) + + [] + member _.``print writes string value``() = + let result = captureConsoleOut (fun () -> print "hello") + Assert.Equal("hello", result) + + [] + member _.``print writes integer value``() = + let result = captureConsoleOut (fun () -> print 42) + Assert.Equal("42", result) + + [] + member _.``print writes float with InvariantCulture``() = + let result = captureConsoleOut (fun () -> print 3.14) + Assert.Equal("3.14", result) + + [] + member _.``print writes bool value``() = + let result = captureConsoleOut (fun () -> print true) + Assert.Equal("True", result) + + [] + member _.``print writes Some value``() = + let result = captureConsoleOut (fun () -> print (Some 42)) + Assert.Equal("Some(42)", result) + + [] + member _.``print writes None value``() = + let result = captureConsoleOut (fun () -> print None) + Assert.Equal("", result) + + [] + member _.``print writes list value``() = + let result = captureConsoleOut (fun () -> print [1; 2; 3]) + Assert.Equal("[1; 2; 3]", result) + + [] + member _.``println writes value followed by newline``() = + let result = captureConsoleOut (fun () -> println "hello") + Assert.Equal("hello" + Environment.NewLine, result) + + [] + member _.``multiple prints concatenate``() = + let result = captureConsoleOut (fun () -> + print "Hello, " + print "World!") + Assert.Equal("Hello, World!", result) + + [] + member _.``println writes integer with newline``() = + let result = captureConsoleOut (fun () -> println 42) + Assert.Equal("42" + Environment.NewLine, result)