diff --git a/adr/001_interface_design.md b/adr/001_interface_design.md index 6aba8f2..0ba381c 100644 --- a/adr/001_interface_design.md +++ b/adr/001_interface_design.md @@ -319,7 +319,19 @@ The following changes will be made to accomodate for congruency: To solve this, we need a new function: ```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. @@ -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. 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`. +
@@ -363,25 +379,38 @@ Once again, the function is free because it is symmetric. This functionality requires a new receiver: ```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. 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). -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`.
maps.Copy(dst, src) -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 -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`. @@ -395,3 +424,54 @@ The name `t.Merge()` might be more accurate, but it does work because: It simply overwrites the values.
+ +
+maps.DeleteFunc(m, fn) + +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()`. + +
+ +
+m := maps.Collect(seq) + +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 +} +``` + +
+ +
+m := map[K]V{...} + +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 + +