Skip to content

add Iter[String]::join #1301

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

Merged
merged 5 commits into from
Feb 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions builtin/builtin.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ impl Iter {
head[A](Self[A]) -> A?
intersperse[A](Self[A], A) -> Self[A]
iter[T](Self[T]) -> Self[T]
join(Self[String], String) -> String
just_run[T](Self[T], (T) -> IterResult) -> Unit
last[A](Self[A]) -> A?
map[T, R](Self[T], (T) -> R) -> Self[R]
Expand Down
16 changes: 16 additions & 0 deletions builtin/iter.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,22 @@ pub fn Iter::collect[T](self : Iter[T]) -> Array[T] {
result
}

///|
/// Collects the elements of the iterator into a string.
pub fn join(self : Iter[String], sep : String) -> String {
let buf = StringBuilder::new()
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. there are some duplications with Logger::write_iter, can you factor out some common parts
  2. if separator == "" this rarely happens, such optimization is not worth it

Copy link
Contributor Author

@hackwaly hackwaly Jan 20, 2025

Choose a reason for hiding this comment

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

Logger::write_iter has unexpected behavior which turn "Test" to "\"Test\"" before write.

Copy link
Contributor

@gmlewis gmlewis Jan 21, 2025

Choose a reason for hiding this comment

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

I vote for sep : String... that way you always see the one argument that is passed to join and it is always extremely clear what the code is doing:

arr.iter().join("")
arr.iter().join(", ")
arr.iter().join(" ")
etc.

Additionally, you don't have the jarring noise of sep= cluttering the code unnecessarily.

And it is much easier to write, and muscle memory takes over so that you don't have to think about it, because joins happen frequently in code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Now, if the MoonBit compiler could simply perform the .iter() under the covers whenever an iter is needed where it is obvious that the array must be iterated, then that would get us back to the original, beautiful syntax which was one of the reasons early on that I liked MoonBit so much in the first place!!!

arr.join("")
arr.join(", ")
arr.join(" ")
etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I vote for sep : String... that way you always see the one argument that is passed to join and it is always extremely clear what the code is doing:

arr.iter().join("")
arr.iter().join(", ")
arr.iter().join(" ")
etc.

Additionally, you don't have the jarring noise of sep= cluttering the code unnecessarily.

And it is much easier to write, and muscle memory takes over so that you don't have to think about it, because joins happen frequently in code.

lgtm.

let mut first = true
for str in self {
if first {
first = false
} else {
buf.write_string(sep)
}
buf.write_string(str)
}
buf.to_string()
}

///|
/// Iter itself is an iterator.
/// so that it works with array spread operator. e.g, `[..iter]`
Expand Down
20 changes: 20 additions & 0 deletions builtin/iter_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -543,3 +543,23 @@ test "peek function - random cases" {
let iter5 = [0, 0, 0].iter()
inspect!(iter5.peek(), content="Some(0)")
}

test "@builtin.join/empty_iter" {
let empty_iter : Iter[String] = Iter::empty()
inspect!(empty_iter.join(""), content="")
}

test "@builtin.join/single_element" {
let single_elem_iter : Iter[String] = Iter::singleton("Test")
inspect!(single_elem_iter.join(""), content="Test")
}

test "@builtin.join/multiple_elements_with_separator" {
let iter : Iter[String] = ["A", "B", "C"].iter()
inspect!(iter.join(","), content="A,B,C")
}

test "@builtin.join/multiple_elements_without_separator" {
let iter : Iter[String] = ["A", "B", "C"].iter()
inspect!(iter.join(""), content="ABC")
}
Loading