Skip to content

Instantly share code, notes, and snippets.

@jimmyfrasche
Created September 6, 2018 16:36
Show Gist options
  • Save jimmyfrasche/f2cd6aff16db5e46c577da44ec0cfa72 to your computer and use it in GitHub Desktop.
Save jimmyfrasche/f2cd6aff16db5e46c577da44ec0cfa72 to your computer and use it in GitHub Desktop.
error handling feedback

My concern with the check/handle mechanism is that it makes the error interface and the zero value special.

This can be avoided at the cost of an increase in implementation complexity and slightly less decrease in boilerplate. Perhaps it's better to avoid the complexity, but this is what it would look like if it were generalized:

handle requires a type and a conditional. It looks more like an if statement:

handle err error; err != nil {
  // ...
}

This creates multiple handler chains per type. So this would also be valid

handle ok bool; !ok {
  // ...
}

as is

handle n int; n < 0 {
  // ...
}

check can only be used if there is handler chain of a matching type in scope, which is easily verifiable at compile time.

At runtime, when a check is executed, it checks the conditionals of each appropriately-typed handler in scope. If none succeed, the value is discarded and execution carries on as usual. That does mean that is is possible to write code like this:

func f() {
  handle ok bool; ok {
    fmt.Println("ok!")
  }
  handle ok bool; !ok {
    fmt.Println("!ok")
  }
  check randomBool()
}

Because this can be used with booleans, it should work with the comma-ok operations: check m[k] and check <-c.

This increases the amount written in the common case of err error; err != nil only slightly and it still needs to be written less often than the current status quo.

Aside from bool and error it's unlikely that there will be many legitimate use-cases, but that is no reason to create an overly-specialized mechanism. The generalized mechanism theoretically increases the ability of writing very complicated code with many handlers of different type and condition, but any code written that obliquely would have surely found another means to obfuscate in the absence of this temptation.

@networkimprov
Copy link

A large fraction of the responses suggest named handlers in lieu of (or addition to) a chain. Any thoughts thereon?

@gregwebs
Copy link

gregwebs commented Sep 6, 2018

This is advocating pattern matching (or guards). This concept was also mentioned as a comment on my handlers as functions proposal.

Pattern matching and guards are a wonderful feature, but I think it will need its own proposal to flesh out where it would be useful in the language. It would be good to get one started to see how it would interact with error handling.

@jimmyfrasche
Copy link
Author

I don't have a problem with the status quo not solved by error values proposal. I mostly just find it odd that errors and the zero value are being special cased.

Named handlers look too complicated.

This isn't really related to pattern matching.

@networkimprov
Copy link

networkimprov commented Dec 14, 2018

I moved this to the Requirements section of the feedback wiki.

The concept of multiple typed and/or guarded handlers is subject to a common criticism of try/catch exception handling; that one cannot tell which handler(s) may be invoked by a tried function call (in this case a checked function call).

However I do agree that definable handler types are desirable; error-only handlers are needlessly limiting. And that probably drives a need for named handlers, which is suggested by 18 separate posts on the wiki, at last count.

@refola
Copy link

refola commented Feb 27, 2019

Out of curiosity, would this allow a check statement to be checked? E.g., would this be valid?

func f() (string, int, bool, error) {
	// ...
}

func g() string {
	handle err error; err != nil {
		// ...
	}
	handle ok bool; !ok {
		// ...
	}
	handle n int; n < 0 {
		// ...
	}
	return check check check f()
}

@jimmyfrasche
Copy link
Author

That question could be asked of the original as well:

func f() (s string, a, b, c error) {
  // ...
}
func g() string {
  // handlers...
  return check check check f()
}

If it is allowed, in any case, probably don't do that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment