• sugar_in_your_tea
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    10 months ago

    deduplication

    The best solution here is a map, using keys as the set. So something like:

    func dedup(arr []T) (ret []T) {
        m := make(map[T]bool)
        for _, t := range T {
            m[t] = true
        }
        
        // optimization: make ret the right size
        for t := range m {
            ret = append(ret, t)
        }
    }
    

    I haven’t used Go’s new generics, but I’m guessing this would work fine, provided T is a value type (or can be converted to one). If you know you need deduplication at the start, just use a map at the start.

    If you don’t have value types, you’re going to have a hard time regardless of language (would probably need some OOP features, which adds a ton of complexity). But you can get pretty far with that pattern. If you add a Hash() int to your type:

    func dedup(are []T) (ret []T) {
        m := make(map[int]bool)
        for _, t := range arr {
            h := t.Hash()
            if !m[h] {
                m[h] = true
                ret = append(ret, t)
            }
        }
    }
    

    err… people just did not print any of the relevant information in error cases

    That’s what error wrapping is for:

    if err != nil {
        return fmt.Errorf("context: %w", err)
    }
    

    This makes it so you can use the errors package to unwrap errors or check if an error is a given type. Or you can propagate it like I’ve shown above.

    So I see this as programmer error. Rust has the same issue since it’s easy to just throw a ? in there and bail early without additional context. The simpler form is easier to catch in Go vs Rust in a code review because it’s more verbose.

    It seems you don’t like verbosity, which is fair. I’m fine with verbosity, I don’t like surprises, and Go has enough of those that I generally avoid it.