Skip to content

Instantly share code, notes, and snippets.

@avh4

avh4/crash.md Secret

Last active February 9, 2018 01:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save avh4/ec82d9b41fc385a4cbfb8bb73e6d5abb to your computer and use it in GitHub Desktop.
Save avh4/ec82d9b41fc385a4cbfb8bb73e6d5abb to your computer and use it in GitHub Desktop.
Are there valid uses of Debug.crash in published packages?

Are there valid uses of Debug.crash in published packages?

Looking up an index that is known to exist

A simple example of this is checking the size of an array or matrix, then calling into recursive functions where you will look up values at particular indexes that you know are not out of bounds.

Examples:

A more complex example is when implementing a dynamic programming algorithm or similar, and storing the computed values in a Dict (or Array, or Matrix). If your algorithm is correctly implemented, then the values of other nodes needed to compute the current node will already have been computed and inserted into the Dict. Using Debug.crash is desirable when developing because it is a critical implementation mistake if the crash is ever encountered, and is possibly desirable in production so that a request to report the issue to the package author can be provided.

Examples:

Mathematically-provable invariants

There are more complex examples of implementing an algorithm which can be proven to never hit certain cases, but writing them in Elm requires handling the impossible case. Using Debug.crash is desirable when developing because it is a critical implementation mistake if the crash is ever encountered, and is possibly desirable in production so that a request to report the issue to the package author can be provided.

Examples:

Certain messages only happen at certain times

A program's model has Maybe x, and the program's init performs a Cmd that populates it with a Just value, and then initiates Msgs that require a Just to process.

Better solution: processing the messages should do nothing instead of crashing if there is Nothing.

However, when developing, the crash can be desirable so that it's obvious what went wrong.

Examples:

Invalid inputs

Non-empty lists

Better solution: functions that require a non-empty list should instead take a first item and "rest" items.

However, this makes it annoying to use those APIs with literal lists:

Examples:

More complicated cases

Better solution: the function in question should return Result String a instead of a.

However, this can make the API tedious to work with for most common uses.

Examples:

Values in private data that can never be constructed

Examples:

@rtfeldman
Copy link

Re: "Looking up an index that is known to exist" - the nonempty list one seems reasonable, but I would not call the other three valid.

imeckler/iterator/Iterator.elm:82 (Using Array.get with an index known to be less than the array's length)

The author could have used Array.foldl instead of Debug.crash, and it would likely have much better performance.

jvoigtlaender/elm-gauss/src/Gauss.elm:42 (Using Matrix.get with an index known to exist)

The author chose to use a Matrix package which does not expose fold, and they're using Debug.crash here to implement their own fold on top of a Matrix that doesn't support it. Instead, they could have chosen a Matrix package that did offer fold, or forked the one they were using to add fold themselves.

prozacchiwawa/elm-keccak/src/Keccak.elm:134

The author translated C code directly to Elm, crashes and all. They're using Array to represent mutable memory slots, like what polyfilled Web Assembly does. I'd like to think that if Debug.crash were not available, the author would have been drawn to think through their approach more.

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