Sets, types and type checking
31–36 of 36 posts
Re: Sets, types and type checking
#32> In Rust we have Option , which is equivalent to T | null No, not true! As the author correctly states earlier in the post, unions are not an exclusive-or relation. Unions are often made between disjoint types, but not always . This becomes important when T itself is nullable. Let's say T is `U | null`. `Option >` in Rust has one more inhabitant than `U | null | null` in TypeScript - `Some(None)`. Union types can ce…
You can do this:
const user = await fetchUserDTO(123);
// user is Result
if(!isOk(user)) { something(user.err); return; }
user.name; // user is narrowed to UserDTO
Source: export const FailSym: unique symbol = (globalThis as any).____FailSym ?? Symbol('FailSym');
(globalThis as any).____FailSym = FailSym;
export type Result = T | {
[FailSym]: true,
err: E
}
export function Ok(val: T): Result { return val; }
export function Fail(err: E): Result { return {[FailSym]: true, err}; }
export function isOk(val: Result): val is T { return !(typeof val == 'object' && val != null && FailSym in val); }
export function isFail(val: Result): val is Result { return typeof val == 'object' && val != null && FailSym in val; }
export function resultify(promise: Promise): Promise> {
return promise.then(Ok, err => Fail(err as any));
}Re: Sets, types and type checking
#33> In Rust we have Option , which is equivalent to T | null No, not true! As the author correctly states earlier in the post, unions are not an exclusive-or relation. Unions are often made between disjoint types, but not always . This becomes important when T itself is nullable. Let's say T is `U | null`. `Option >` in Rust has one more inhabitant than `U | null | null` in TypeScript - `Some(None)`. Union types can ce…
Could you give an example of this? The only case I can imagine is a union null <=: T, T | null. This would cause unexpected behaviour, i.e. a if T = (U | null), the function orElse : T | null → T → T would always return the second argument if the first is null, but this is perfectly consistent with the fact that T itself is a union type. The idea that it should do anything different is presuming that the null assigned to T is different from the null assigned to T | null (that union types are disjoint). But this is an invalid assumption. It's still a validly typed program that obeys a consistent set of rules. It's just that there is no tagging in the union type (you don't know if a member comes from the left or right side). This is only an issue if you write code expecting the union to work like a tagged union.
Re: Sets, types and type checking
#34> In Rust we have Option , which is equivalent to T | null No, not true! As the author correctly states earlier in the post, unions are not an exclusive-or relation. Unions are often made between disjoint types, but not always . This becomes important when T itself is nullable. Let's say T is `U | null`. `Option >` in Rust has one more inhabitant than `U | null | null` in TypeScript - `Some(None)`. Union types can ce…
Rich Hickey has a presentation titled 'Maybe Not' that talks about this exact distinction, but he actually argues the reverse (and often criticized quite wildly, even though both sides are sort of right here, I believe). He says that nullability is better [1], as refactoring a function that accepted T to T?, or a function's return type from T? to T are both backwards compatible, while the sum type variants require co…
I've always found this to be a silly argument. In both cases, the problem can be solved by interface versioning. If you have f : T → Maybe T and you should like to change the type, just create f_v2 : Maybe T → T assign f x = just (f_v2 (just x)). The real shame is that most languages do not support interface versioning as a proper feature. There should really be some way to use a package and declare that you want to use v1/2 of the interface, then subsequently package.f would either be f or f_v2. You would eventually have to change the code that deals with f if you want to stay up to date, but realistically you should remove redundant error checking code anyway so you aren't much better off.
You could also frame it as a tooling problem. Given that the transformation between types is trivial, you should be able to write a program that automatically updates code to newer versions. It seems like this is a relatively niche issue in either direction (union types not being disjoint, vs having to change code that deals with options), but its a more solvable problem in the second case.
Re: Sets, types and type checking
#35Earlier quoted context omitted.
Rich Hickey has a presentation titled 'Maybe Not' that talks about this exact distinction, but he actually argues the reverse (and often criticized quite wildly, even though both sides are sort of right here, I believe). He says that nullability is better [1], as refactoring a function that accepted T to T?, or a function's return type from T? to T are both backwards compatible, while the sum type variants require co…
> as refactoring a function that accepted T to T?, or a function's return type from T? to T I've always found this to be a silly argument. In both cases, the problem can be solved by interface versioning. If you have f : T → Maybe T and you should like to change the type, just create f_v2 : Maybe T → T assign f x = just (f_v2 (just x)). The real shame is that most languages do not support interface versioning as a pr…
Re: Sets, types and type checking
#36Earlier quoted context omitted.
> as refactoring a function that accepted T to T?, or a function's return type from T? to T I've always found this to be a silly argument. In both cases, the problem can be solved by interface versioning. If you have f : T → Maybe T and you should like to change the type, just create f_v2 : Maybe T → T assign f x = just (f_v2 (just x)). The real shame is that most languages do not support interface versioning as a pr…
Do you know of a language that supports interface versioning? I often wished for one (as I like writing programs by "iterative refining", where I basically copy the good parts into a completely new project), but have never heard of a language that does something like that.