docs: DeleteFunc, Collect

This commit is contained in:
2026-05-04 19:16:42 -04:00
parent cddc205fe8
commit 5c84ed7794

View File

@@ -319,7 +319,19 @@ The following changes will be made to accomodate for congruency:
To solve this, we need a new function: To solve this, we need a new function:
```go ```go
func EqualFunc[K, V1, V2 any](t1 *Table[K, V1], t2 *Table[K, V2], eq func(V1, V2) bool) bool func EqualFunc[K, V1, V2 any](t1 *Table[K, V1], t2 *Table[K, V2], eq func(V1, V2) bool) bool {
if t1.Size() != t2.Size() {
return false
}
for k, v1 := range t1.Entries() {
if v2, ok := t2.Get(k); !ok || eq(v1, v2) {
return false
}
}
return true
}
``` ```
This function is free, and not bound as a receiver function. This function is free, and not bound as a receiver function.
@@ -339,6 +351,10 @@ So, we must assume that:
- Both tables have `EqualFunc`'s which 'agree' on the identity of the keys present in the tables. - Both tables have `EqualFunc`'s which 'agree' on the identity of the keys present in the tables.
Agreement is defined as: if two keys are distinct in one table, they are distinct in the other. Agreement is defined as: if two keys are distinct in one table, they are distinct in the other.
The name `EqualFunc` is already taken by `EqualFunc[K, V]`: an alias for `func(a, b K) bool`.
Inlining `EqualFunc[K, V]` would solve this problem.
The documentation attached to it would be moved to `DefaultEqualFunc`.
</details> </details>
<details> <details>
@@ -363,25 +379,38 @@ Once again, the function is free because it is symmetric.
This functionality requires a new receiver: This functionality requires a new receiver:
```go ```go
func (t *Table[K, V]) Insert(seq *iter.Seq2[K, V]) error func (t *Table[K, V]) Insert(seq iter.Seq2[K, V]) error {
for k, v := range seq {
if err := t.Put(k, v); err != nil {
return err
}
}
return nil
}
``` ```
A receiver fits better even though `maps.Insert` is a free function, because copying it is asymmetric. A receiver fits better even though `maps.Insert` is a free function, because copying it is asymmetric.
Map `dst` receives entries from map `src`. Map `dst` receives entries from map `src`.
It is only free because Go's standard map is built into the language, and so cannot have receivers. It's only free because Go's standard map is built into the language, and so cannot have receivers.
In terms of naming, `t.Extend` is more accurate, and has precedent in [Python](docs.python.org/3/tutorial/datastructures.html#more-on-lists) and [Rust](https://doc.rust-lang.org/std/iter/trait.Extend.html). In terms of naming, `t.Extend` is more accurate, and has precedent in [Python](docs.python.org/3/tutorial/datastructures.html#more-on-lists) and [Rust](https://doc.rust-lang.org/std/iter/trait.Extend.html).
Ultimately, `t.Insert()` is a better choice because of When [adding iterator function](https://github.com/golang/go/issues/61900) to the `maps` package, the Go team chose to frame it as 'sources' and 'sinks'.
With this model, `maps.Insert` made more sense than `maps.Extend`.
Ultimately, `t.Insert()` is a better choice to be consistent with `maps`.
</details> </details>
<details> <details>
<summary><code>maps.Copy(dst, src)</code></summary> <summary><code>maps.Copy(dst, src)</code></summary>
To solve this, we must implement a new receiver: To solve this, we must implement a new receiver.
Luckily, `t.Insert` makes it trivial:
```go ```go
func (t *Table[K, V]) Copy(src *Table[K, V]) error func (t *Table[K, V]) Copy(src *Table[K, V]) error {
return t.Insert(src.Entries())
}
``` ```
A receiver fits better even though `maps.Copy` is a free function, 'copying' it is asymmetric: `dst` is writen into by `src`. A receiver fits better even though `maps.Copy` is a free function, 'copying' it is asymmetric: `dst` is writen into by `src`.
@@ -395,3 +424,54 @@ The name `t.Merge()` might be more accurate, but it does work because:
It simply overwrites the values. It simply overwrites the values.
</details> </details>
<details>
<summary><code>maps.DeleteFunc(m, fn)</code></summary>
A few function can fill this gap:
```go
func (t *Table[K, V]) DeleteFunc(del func(K, V) bool) {
for k, v := range t.Entries() {
if del(k, v) {
t.Drop(k)
}
}
}
```
It would have the same functionality as `maps.DeleteFunc`.
A free function could work here, but `t` has clear authority over `del`.
Other than being consistent with the `maps` package, `t.DeleteFunc` follows the Go convention of appending `Func` to higher-order equivalents of functions.
This trumps names like `t.DeleteIf`, which lend more to [Java](https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#removeIf-java.util.function.Predicate-) or [C++](https://en.cppreference.com/cpp/algorithm/remove).
The word `Delete` is also convention, tying back to the built-in `delete()`.
</details>
<details>
<summary><code>m := maps.Collect(seq)</code></summary>
This functionality would benefit from a new constructor.
Luckily, `t.Insert` makes this easy:
```go
func Collect[K comparable, V any](seq iter.Seq2[K, V]) (*Table[K, V], error) {
t := New[K, V]()
err := t.Insert(seq)
return t, err
}
```
</details>
<details>
<summary><code>m := map[K]V{...}</code></summary>
This functionality is complicated, because entries are generic; their addition cannot be through table options.
A new constructor must support this functionality.
Should it support options or custom hashes or `keyFunc`'s?
No, because
</details>