Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'd say you want something like 'debug_msg()' for this.

'print()' should be async because it does IO. In the real world most likely you'd see the output once you yield.



“The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.” — Brian Kernighan, co-creator of Unix


In my experience the best debugging tool in Python is judiciously placed asserts, breakpoints and PDB. Not print.


Huh, typically print is the debug message function vs explicitly writing to stdout


I don’t think so.

Normally print isn’t a debug message function, people just use it like that. (it normally works on non debug builds)


Production builds should retain all debug prints, only hide them behind a flag. This helps you preserve sanity when troubleshooting something.


Printing directly to the console, even in a console app, is for debug purposes only.

If your console app is writing output to any device, it must, for instance, handle errors gracefully.

That means, at least in Rust, write! rather than print!.


What makes you say that? I almost always use println! over write!.

From the docs: "Use println! only for the primary output of your program. Use eprintln! instead to print error and progress messages."


What makes me say that a well-built program properly handles errors?


Panic is a perfectly proper way for a well-built program to stop execution.

There is no point in juggling around Result types if a failure means that you can not recover/continue execution. That is in fact exactly what panic! is intended for [1].

[1]: https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-pa...


A failure to write to stdout should not be unexpected given that stdout is routinely redirected to files or to pipes, both of which can be suddenly closed or otherwise fail from the other direction. Yes, you can't recover in this case, but you should at least properly report the error to stderr before exiting, in a way that lets the end user (rather than app dev) properly diagnose the error.

Now if you fail to write to stderr, yeah, that's a good reason for a console app to panic. The onus is on the user to provide something that is "good enough" in that case.

IMO the real problem is that print() etc defaults to stdout historically, but is used mostly for diagnostic information rather than actual output in practice, so it should really go to stderr instead. This would also take care of various issues with buffering etc.


Woah woah woah let's not get hasty. We can have panicking and nonpanicking versions of the API (at least until somebody builds the nonpanicking version of Rust, that will be great). The panicking version is for quick, off-the-cuff usage, and the nonpanicking one for production use.

There's value in the Hello, World and println-debugging style print, even if it should be eschewed in most general contexts.


I didn't say that there isn't value in "hello world" or println-debugging style print. The point is that both should go to stderr rather than stdout (and then panic if they fail). But for stdout, which is the channel for output and not for logging, the default should be to require error handling.

Consider something as trivial as `cat foo >readonly_file` to see why.


Panic is perfectly fine in certain cases, but it's absolutely not a general error-handling mechanism for Good Programs (TM). (Some contexts excluded, horses for courses and all that)

You can and should recover from bog standard IO failures in production code, and in any case you'd better not be panicking in library code without making it really clear that it's justified in the docs.

If your app crashes in flames on predictable issues it's not a good sign that it handles the unpredictable ones very well.


In rust, the common debug message function would be log::info! or log::debug!, with two lines of setup to make logs print to stderr. Or for something more ad-hock, there's dbg! (which adds context what you are printing, and doesn't care about your logging config). Not that people don't use print for the purpose, but it's basically never the best choice. I assume Dada is conceived with the same mindset.


I disagree—println! is far more common for every day printf debugging than the log crate is. Do i have any evidence of this? No, but it takes less to type and is harder to mess up with log levels while working just as effectively.


Print is a debug function in some languages, but it's usually just stdout. You can add all kinds of logging libraries that wrap around print() with prefixes and control sequences to add colours, but I generally don't bother with those myself. In those circumstances, I would use something like logger.debug() instead of plain print(), though.

I personally find myself using print debugging as a last resort when the debugger doesn't suffice.


There seems to be a conflation in two subtly different types of debugging here—one is simply regurgitating state while tracking down a specific bug on a local machine and should not be committed and the other is intended to be checked into possibly production code with the assumption being sent to a log aggregator. I think both are valid techniques, but one clearly benefits from the use of the `log` crate more than the other.


> 'print()' should be async because it does IO

What if I want to do synchronous IO?


Just from glancing over the docs, that doesn't seem supported:

> Dada, like JavaScript, is based exclusively on async-await. This means that operations that perform I/O, like print, don't execute immediately. Instead, they return a thunk, which is basically "code waiting to run" (but not running yet). The thunk doesn't execute until you await it by using the .await operation.

Good riddance, IMO — never been a fan of blocking IO. Dada does have threads though, so I wonder how that works out. (Forcing async/await makes a lot more sense in JavaScript because it's single-threaded.)


Node lets you cheat with "synchronous" APIs: it stops the whole event loop. If you start making exceptions for "little" bits of IO like printing to the console or reading files, the async parts of your code are "async when someone hasn't done something synchronous". Doing a `readFileSync` even on a small file in a hot code path means you're meaningfully tanking the performance of your code.

What you're asking for is "stop running my code until I've finished printing to the console". That's what the `.await` does. Synchronous IO on `print()` would mean _everything in the whole application that logs_ suddenly blocks the whole application from doing _anything_ while the console is being written to, not just the currently running code.

If you want synchronous stop-the-world IO (like Python, where async/await is bolted on), you shouldn't choose a language based around async/await concurrency.


Then use .await?


gevent handles async fine without the explicit async/await

.NET core will introduce something similar


The cost of it is that when you need to make something explicitly async, you have to wrap it into a greenlet in a much more involved way.

JavaScript lets you do it much more ergonomically.


Doesn't seem very involved; for example (cilk inspired syntax):

    let f = spawn { print() }  // fork
    ...
    wait f // join. f is a linear type
You only pay the complexity cost if you need it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: