Skip to content

Wish we could tell if the append happened #21

Closed
@jcorbin

Description

@jcorbin

I've hit a surprising number of cases recently where I wished that multierr.Append would tell me if the append happened or not. It's not so much for dubious micro perf reasons (CPUs being cheap, fast, and plentiful these days), but more on account of simplifying control flow:

  • when I don't need to tell if it happened, I can use the inline form like err = multierr.Append(err, somethingFaliable())
  • but if I need to know if somethingFaliable failed or not in addition to collecting its error, then I have to break that apart, and do my own nil check
  • really the hardest part of this, as always, is choosing what to name someErr ;-)
package main

type T struct{}

type Scanable interface {
	Scan(...interface{}) bool
}

// harvestT loads T from some Scanable source. Since we really like T, we don't
// let mundane details like parsing errors get in our way; instead we continue
// on to harvest as much T as we can, collecting any errors that we encounter.
func harvestT(iter Scanable) ([]T, error) {
	var (
		mess   string // each string from the db
		datum  T      // each parsed item
		data   []T    // all items parsed
		retErr error  // any collected errors
	)

	// with current multierr
	for iter.Scan(&mess) {
		if parseErr := tryToParse(s, &datum); parseErr != nil {
			retErr = multierr.Append(retErr, parseErr)
			continue
		}
		data = append(data, datum)
	}

	// however what if we could:
	for iter.Scan(&mess) {
		retErr, failed = multierr.Appended(retErr, parseErr)
		if failed {
			continue
		}
		data = append(data, datum)
	}

	// or even "better" in this case:
	for iter.Scan(&mess) {
		retErr, failed = multierr.Appended(retErr, parseErr)
		if !failed {
			data = append(data, datum)
		}
	}

	// alternatively, if we used a *error:
	for iter.Scan(&mess) {
		if multierr.AppendInto(&retErr, parseErr) {
			continue
		}
		data = append(data, datum)
	}

	// which of course could be simplified in our singleton case (you wouldn't
	// want to do this if you had more than one faliable step in the loop
	// body):
	for iter.Scan(&mess) {
		if !multierr.AppendInto(&retErr, parseErr) {
			data = append(data, datum)
		}
	}

	return data, retErr
}

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions