Closed pongo closed 3 years ago
Hey, thanks :heart: for benchmarking and reporting this.
Using exceptions was actually one my design goals as I like (and kind of depend) on its easy composability within my other projects. I'm already wrapping things internally to keep things fast and did not really optimize for the failing part :D to be honest.
I did not know though that there is a way to make Error creation and throwing faster. Have to check what utils.inherit
does as I need this library to work in browsers too.
Or I might as well publish and document the internal interface that returns a Fail
object instead of throwing an Error
.
I'll go and use your benchmark to check your suggestions.
If you can use custom errors (without stacktrace) and add option "return errors instead throw" — it would be great. Or may be option "ignore errors" (just return false
).
Oh yeah, let me try both - an additional .check
method similar to how other runtype libs do it and a (maybe as a configurable option bc. I don't need the fail-efficiency in the frontend) stackless efficient error object. It will take some days though bc. I've got a deadline at work :cry:
@pongo had a look into this:
I think stackless errors are too surprising for a user and I (in front and backend code) rely heavily on stacktraces to find where bad data came from. Its already hard enough with async code - not having traces at all might be too frustrating.
Benchmarking without try/catch and throwing errors results in a tremendous speedup just as expected.
But now I need your input:
Would you prefer a global check<T>(Runtype<T>, v: unknown): ValidationResult<T>
function or rather that function as a method on all runtypes so it can be easily chained and discovered?
Chaining is more discoverable via autocomplete but IMO harder to implement as I'd probably need to have some kind of base class that implements .check(v :unkown): ValidationResult<T>
and passes it to runtypes via prototype to reduce overhead.
On the other hand, I'm not using chaining at all in this library so one would actually expect a st.check()
function because that's where all the other functions are. And its simpler to implement.
Anyway, I'm starting with a check()
function for now.
Added the option to use a runtype and let it return a validation result instead of throwing an error: st.use(thatRuntype, unknownValue)
: https://github.com/hoeck/simple-runtypes/blob/907f687907fe489d23170519096a5b5c54d04d11/src/custom.ts#L51
Hello. You've created an good library, but there is a performance problem.
Look at this benchmark. We validate two cases: correct data and incorrect data. io-ts in both cases has approximately the same performance. But simple-runtypes has a significant performance decrease on incorrect data.
In my opinion, this is because you are throwing errors. The standard error should collect a stacktrace — it's slow. Throwing is also slow.
What can we do?
1. Throw away
Error
and use stackless error objects2. Stop throwing errors
You can, for example, return a ValidationResult: