temperlang / temper

3 stars 0 forks source link

Proposal: Explicit exception kinds to support panics #164

Open tjpalmer opened 1 month ago

tjpalmer commented 1 month ago

TLDR:

Said otherwise, I realized I basically landed on Java checked exceptions, except:

See also:

Goals:

Also:

Defining error kinds:

// No further details and no inheritance, because backends are diverse.
// Error values might need relocated to some top-level enum on some backends.
// On other backends, they'll be converted to classes.
// TODO Other syntax options?
// TODO Should we allow as values outside of bubbling or catching?
error case Baddie;
// let Something = error(); ???

Bubbling requires an error kind:

throw Baddie;
// or throw(Baddie) or bubble(Baddie) ???

You can only bubble what's declared:

let calcSomething(n: Int): Int throws Baddie {
  // TODO Explicit `try` or `!` or ... required to propagate, or do we automate?
  try checkRange(n);
  // Illegal without some handling because we don't throw Other.
  // TODO Do we auto wrap caught errors when throwing? Wrapping is best effort.
  // TODO Some explicit syntax for that? Or special syntax to avoid default wrapping?
  // somethingElse(somethingElse(n - 1) orelse(e) panic(e)) orelse(e) throw Baddie(e)
  somethingElse(somethingElse(n - 1) orelse panic()) orelse throw Baddie
}

let checkRange(n: Int) void throws Baddie {
  if (n < 0) {
    throw Baddie;
    // Would be illegal.
    // throw Other;
  }
}

let somethingElse(n: Int): Int throws Other {
  if (n == 0) {
    throw Other;
  }
  n + 1
}

Try sugar:

try doSomething(n);
// or maybe
doSomething(n)!;
// equivalent to
doSomething(n) orelse throw;
// or maybe we switch to `catch` since we don't want it *too* common and then
try doSomething(n);
// is equivalent to
try { doSomething(n) }
// is equivalent to
try { doSomething(n) } catch { throw; }
// is equivalent to
try { doSomething(n) } catch (e) { throw e; }
// is equivalent to
try { doSomething(n) } catch (e: <error kinds that are declared to be thrown in block>) { throw e; }
// And in the case of `catch` instead of `orelse`, things like this might also work, but we need curlies?:
try doSomething(n) catch { 0 }
// Orelse panic gets uglier with curles:
try doSomething(n) catch { panic() }

Explicit types on orelse?:

doSomething(n) orelse(e: Baddie | Other) 0
// or just catch as above
try doSomething(n) catch (e: Baddie | Other) { 0 }

Optional best effort case/kind hint for panic?

// Might or might not get specialized for some backends?
// Maybe message is more interesting?
panic(OutOfBounds);
panic("out of bounds: ${...}");
// Message on errors as best effort? Or don't get people's hopes up with any of this?
// Maybe better just to log message then throw plain?
throw MyError("my message");

More: