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

feat(builtin): add dump() for easy print-based debugging #1269

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions builtin/builtin.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ fn assert_not_eq[T : Eq + Show](T, T, loc~ : SourceLoc = _) -> Unit!

fn assert_true(Bool, loc~ : SourceLoc = _) -> Unit!

fn dump[T](T, name? : String, loc~ : SourceLoc = _) -> T //deprecated

fn fail[T](String, loc~ : SourceLoc = _) -> T!Failure

fn ignore[T](T) -> Unit
Expand Down
15 changes: 15 additions & 0 deletions builtin/console.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
///|
fn println_mono(s : String) -> Unit = "%println"

///|
fn any_to_string[T](any : T) -> String = "%any.to_string"

///|
pub fn println[T : Show](input : T) -> Unit {
println_mono(input.to_string())
Expand All @@ -26,6 +29,18 @@ pub fn print[T : Show](input : T) -> Unit {
println(input)
}

///|
/// Prints and returns the value of a given expression for quick and dirty debugging.
/// @alert deprecated "This function is for debugging only and should not be used in production"
Copy link
Contributor Author

@rami3l rami3l Nov 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is marked as deprecated because it seems to be the only way to generate warnings with it. In Rust this logic is handled by clippy instead of rustc so there haven't been such concerns.

pub fn dump[T](t : T, name? : String, loc~ : SourceLoc = _) -> T {
let name = match name {
Some(name) => name
None => ""
}
println("dump(\{name}@\{loc}) = \{any_to_string(t)}")
t
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any_to_string is introduced for arbitrary code transformations where T is not sure if it satsifies Show. How is this different from dump[T:Show](...)
cc @Guest0x0 it makes sense to introduce support of ArgsRepr which is essentialy a stringified repr of args. so that we can do something like this:

pub fn dump[T:Show](t : T, name~ : ArgsRepr = _, loc~ : SourceLoc = _) -> T

Copy link
Contributor Author

@rami3l rami3l Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bobzhang One thing that distinguishes Swift's dump() from Rust's dbg!() is that the former doesn't pose any restrictions on T whereas the latter depends on T: Debug (which is exclusively used for print-oriented pretty-printing, compensating for the lack of a built-in dumper in Rust) 1.

I think the Show trait in MoonBit corresponds to the Display trait (which subsumes .to_string() in Rust) rather than Debug, so it makes more sense to add no bounds at all.

OTOH ArgsRepr will definitely be a nice addition.

Footnotes

  1. The lack of distinction between Display and Debug seems like a common reason for which print-based debugging is less popular in traditional tech stacks; both approaches here allow the mitigation of this issue.

///|
pub fn to_string(self : Bool) -> String {
if self {
Expand Down
Loading