rhombus-prototype icon indicating copy to clipboard operation
rhombus-prototype copied to clipboard

Multiple items and keywords in display/print/write

Open gus-massa opened this issue 6 years ago • 3 comments

For debugging, I use a lot of times

(displayln (list "Result=" x y z))

It would be nice to be able to write

(displayln "Result=" x y z)

So my proposal is that to change the signature of display/print/write to something like

(define (display #:port [port (current-output-port)]
                 #:separator [separator " "]
                 #:newline [newline #f]
                 . items)
  ...)

Python also has a #:flush keyword (or their equivalent version) and uses #:file instead of #:port, but I think #:port or #:output-port makes more sense. The real version is

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

More questions:

Is it better to use #:newline (boolean) or #:end (string/bytes) or #:end (any)?

Add #:start (string/bytes//any)?

Add #:before-last like string-join?

Collapse display and displayln in a single function?

gus-massa avatar Sep 20 '19 15:09 gus-massa

Would an approach like printf that's based on format strings work instead?

(printf "Result= ~v, ~v, ~v\n" x y z)

jackfirth avatar Sep 21 '19 02:09 jackfirth

It is totally possible but with printf I have to count the number of arguments and modify the format string each time I add or remove or #;comment a variable. It uses almost the double of characters.

More questions: . Unify e/f/printf with print?

gus-massa avatar Sep 21 '19 11:09 gus-massa

Python has:

  • print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
  • repr for converting an object to a string that (hopefully) can be parsed back. E.g., repr("abc") == "'abc'"
  • String interpolation via .format string method. In recent Python, f"..." literal string subsumes the method. E.g.,
    world = 1.2345
    f"hello {world:10.3f}" #=> 'hello      1.234'
    
  • Deprecated printf-like string interpolation via % operator.

Racket has:

  • print, write, display, and ln variants, where the second optional argument is for specifying the port. It accepts exactly one argument.
  • printf, fprintf, format
  • ~a, ~v, ~s
  • @-expression

My personal opinion is that printing in Python is far more friendly than in Racket.

  • write, print, and display are similar but subtly different. It is not friendly to beginners who are overwhelmed by all these functions. They just want to show something on screen!

    • Object printing requires you to implement at least two methods (and at most three). For people who just want to display an object on screen, this is really inconvenient.
    • I believe that most regular programmers would use display more than write (or even print). write only makes sense when you want to read a datum back, but I don't think most programmers will do that.
    • What if we remove (write x), and replace all uses with (display (repr x)) where repr = ~s. Does this reduce the complexity?
  • The inability to accept multiple arguments for print-like function is probably to maintain backward-compat to Scheme. Being able to print several objects in one invocation is obviously better, especially for debugging purpose, and it should be easy to implement this by moving the port argument to keyword argument.

  • I wish for f"..."-equivalent construct in Racket. Currently, this could be approximated by (let ([world 1.2345]) @~a{hello @(~r world #:precision 3)}) (see https://www.greghendershott.com/2015/08/at-expressions.html), but we need to full @-expression for it to work. Also, it seems verbose somewhat...

    • I really dislike printf. I need to go back and forth between the format string and argument list. I think Python made the right call to switch to the newer string format.
  • I think we should have both print and println. In some Python projects I saw end='' all over the file. That seems not ideal.

I have some concern re: keyword argument. The port seems to be suitable for keyword argument because if users want to call print only a few times, then it's OK to write (print ... #:port ...). If they want to call it a lot, they'd better switch to (with-output-to-port ... (print ...) ...), so that's OK as well. But stuff like #:precision in ~r somehow gives me a different feeling.... So when is keyword argument acceptable, and when is it not?

sorawee avatar Sep 21 '19 13:09 sorawee