3 ms·
I second that, to a degree. I write mostly TypeScript and Rust these days and it still behaves unexpectedly sometimes. Example: for a service we wanted to port
by KenanSulayman 7y ago
I second that, to a degree. I write mostly TypeScript and Rust these days and it still behaves unexpectedly sometimes.
Example: for a service we wanted to port Rusts’ Result.
https://gist.github.com/KenanSulayman/34a40daa3ebbd1e1bdf7c734afc815b1 https://gist.github.com/KenanSulayman/34a40daa3ebbd1e1bdf7c7...
Notice the ‘as any’ and ‘_T!: T;’ et al. hacks to make it work.
Other than that it’s completely a one to one port from the Rust core implementation.
- wereHamster 7y agoBecause you're trying to manually optimize code, which is kindof like saying 'I konw what I'm doing so TypeScript please shut up'. Take for example the `map_err` function of the `Ok` class. The function returns a different `Result`, but you're using the `… as any` trick to shut up the compiler. The correct implementation would be: map_err<U>(fn: (arg: E) => U): Result<T, U> { return new Ok<T, U>(this.value) } I see why you're not doing that, because that allocates a new object, and that might seem bad. Even the implementation in Rust 'allocates' a new object, but then it relies on the rust compiler to optimize that out. Here's the relevant code: pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T,F> { match self { Ok(t) => Ok(t), Err(e) => Err(op(e)) } } See the `Ok(t) => Ok(t)` line? That's the same as `return new Ok(…)` in the TypeScript code. Unfortunately TypeScript is not an optimizing compiler, so it's less powerful than rust. You can either use tricks (`… as any`) and give up type safety or be truthful at the expense of performance.
- steveklabnik 7y agoTo be clear, the option type in rust does not heap allocate at all; no need for the compiler to optimize things away.
- phiresky 7y agoYour problem there seems to mostly be that you tried to directly port it without any modifications, and your code is actually incorrect in some places. For example, if you implemented Result<T, E> as a single class that had a `if(this.is_ok()) ...; else ...` it would work fine without any type assertions or any anywhere. As it is, Ok only depends on T and Err only depends on E, so why do you have them depend on both? One problem is that TS does not want to merge unionized function signatures like this: map: (<U>(fn: (arg: "yep") => U) => Ok<U>) | (<U>(fn: (arg: any) => U) => Result<U, "nope">) This can be mostly fixed by removing arguments that you don't need. I couldn't figure out .map_or_else, but .map().or_else() works. Admittedly, with this way you can get an output of Ok<a> | Ok<b> from some functions, but I don't know where that would be a problem (still fully type checked, you would just get the expected error further outside. Here's a updated gist: https://gist.github.com/phiresky/621f8d8ed6eb00c9a0ddb47217eae38a https://gist.github.com/phiresky/621f8d8ed6eb00c9a0ddb47217e...