carbon-lang icon indicating copy to clipboard operation
carbon-lang copied to clipboard

Debug output/printing syntax

Open jonmeow opened this issue 3 years ago • 9 comments

What should debug output/printing syntax look like?

Note, I think there's a related question of "how should the prelude be implemented". However, I think there are questions about printing that are at least somewhat separate. I think there are three key pieces:

  • Rosetta for comparison - C++: std::cout and fprintf are available as options. - Python: print prints multiple arguments with space separators and a newline. end='' for no newline, sep='' for no separator. - Swift: print is Python-like. - Go: fmt.Print prints multiple arguments with no separators and no newline. fmt.Prinln for a newline, fmt.Printf for formatted printing. - Rust: print! does formatted printing with no newline. println! for a newline. - Kotlin: print prints a single argument with no newline. println for a newline. - JS/TS: console.log takes either multiple objects to print appended, or the first argument can be a substitution string and later arguments are substituted.

At present, explorer provides Print, as do front page snippets. The design does Console.Print, changing to Carbon.Print with #2017 based on a discussion about where the library should really be located modulo the prelude.

What I'm trying to get answered here isn't where the debug printing function belongs library-wise, but rather what the idiomatic syntax should look like (potentially desugared).

  1. What should the name be?
    • Ignoring casing, is "print" or "Print" agreeable?
    • Should it be namespaced to a package and require something more like Carbon.Print?
    • Should it be print and have a keyword reservation that points at the actual symbol?
  2. Should multiple arguments be allowed?
    • @chandlerc had brought up the idea of requiring a single, formatted string as a way to avoid function syntax.
      • For reference, this was partly to avoid having a function-like keyword.
      • Can use string interpolation for formatting.
      • Note a downside of requiring string interpolation for multiple arguments is it can interfere with internationalization, but the only option that'd work well is requiring a formatting string, and that seems uncommon as a requirement cross-language.
    • Most languages seem to support either multiple arguments or formatting directly.
  3. Is it fine to assume that a newline is included by default?
    • This skew somewhat from C++ printf etc, but maybe we can support something like Python's end='' if a way to supply named arguments is provided.
    • Some of this is affected by what happens for named parameters -- it's easier to say we default to having a separator if there's a way to easily turn it off.

My suggestion for the time being would be:

  1. Support print as a function-like keyword
    • Maybe desugars to Carbon.Print, but having easy to remember and type syntax will help developers and is consistent with i32, etc.
    • Similar naming to several other languages
    • Does mean we will have function-like keyword(s)
  2. My suggestion is support default arguments, with spaces separating.
    • Echoing Python and Swift should make it familiar to many developers.
  3. A newline will help.
    • Avoid having a separate println, ideally using #505 to solve this.
    • Newlines are probably a common use-case for debug printing; developers reading code and seeing print shouldn't need to remember to add a newline (or use println)

Essentially, print should feel like Python/Swift from a developer perspective.

jonmeow avatar Aug 25 '22 21:08 jonmeow

I think a keyword for Print() doesn't fit since functions start with uppercase later.

hydroper avatar Aug 25 '22 23:08 hydroper

I think a keyword for Print() doesn't fit since functions start with uppercase later.

Precedent exists for types (bool, i32) and constants (true, false), which are also UpperCamel normally. Extending this to functions (print) is consistent in that sense.

jonmeow avatar Aug 26 '22 14:08 jonmeow

What is the exact benefit of print being a keyword instead of a regular function?

maikel avatar Aug 26 '22 14:08 maikel

What about giving it the powers of JS like 'console.whatYouWant' with formatted string a method to the 'console' equivalent to Carbon? Something like show.error(), show.format("Hi i am {name}"), show.plain("Hi I am Ritesh")

r12esh avatar Aug 28 '22 10:08 r12esh

#2143 reminded me, particular for point 2, there are a few multi-argument approaches to consider:

  • concatenated, i.e. print(str, val) (with or without a separating space, as noted originally)
  • printf-like, i.e. print("%s %d", str, val);
  • indexed substitution, i.e. print("{0} {1}", str, val);

I suspect though that the leaning will be either to do the first or none at all, because it's most compatible with string interpolation (which the latter two might work with, but would require escaping to avoid double-formatting). Formatting would then be something supported through a different api, e.g. print("{0} {1}".Format(str, val));

jonmeow avatar Sep 06 '22 03:09 jonmeow

print ( not Print ) and have a keyword reservation . multiple arguments to be allowed - indexed substitution or printf-like . newline by default ( newline is mostly required )

FromCppToCarbon avatar Oct 17 '22 21:10 FromCppToCarbon

I'd personally discourage having a print keyword:

  • print can be a useful name for a user-defined method
  • Python 3 made a breaking change to convert print into a function (see PEP 3105 for the rationale)
  • We might want related functions (e.g. print, printLn, fprint) and let users define other adjacent functions

I think the safest is to start with a single argument print function:

  • Variations can easily be added later
  • This means the language needs a good way to create strings (e.g. string interpolation) - which is useful anyway

I think it's better to first design string interpolation (or anything similar). The multi-argument print function can provide a convenient shortcut, but we'll see the need after trying to use string interpolation inside a print.

laurentlb avatar Nov 10 '22 00:11 laurentlb

We triage inactive PRs and issues in order to make it easier to find active work. If this issue should remain active or becomes active again, please comment or remove the inactive label. The long term label can also be added for issues which are expected to take time. This issue is labeled inactive because the last activity was over 90 days ago.

github-actions[bot] avatar Feb 08 '23 02:02 github-actions[bot]

We've now decided #2113 and picked the package name Core for the prelude.

I'd like to suggest we resolve this as:

  • A normal function in the prelude (not a keyword or special syntax).
    • It's easy to add if we end up wanting it, and good to wait until we're motivated.
  • Named Core.Print
    • Seems like a really solid and unsurprising default. I don't think we need to add more handling of edge cases here, we can teach folks learning Carbon how this API works.
  • Without any special formatting -- let's try to build those as composable features. Maybe this involves string interpolation, or something like "{0}, {1}".Format(str, val) as in an example above.
    • Let's explore orthogonal and composable formatting. if we discover a particularly common pattern that we want to directly support with more terse syntax, we can add it then.
  • Includes a newline, always.
    • Almost certainly the right default.
    • Easy to add a specialized version for the rare case.
    • The goal of having something like this in the language is make the on-ramp easy and useful for printing human oriented information back out during development or when building tools. For more in-depth or complex output cases where this stops being the right default, we should provide a separate API that can be effectively composed with things like other I/O sinks, etc.

Thoughts?

chandlerc avatar Feb 22 '23 03:02 chandlerc