Skip to main content
union type not supertype
Source Link

?string is a supertypeunion type of string and null, thus no existing callers break. I can release an update to my library and not break any of its consumers.

foo('sdf'); // requires no change as ?string'sdf' is aallowed supertypein the type union of string.`null | string` 

The same problem with Option also exists in the reverse -- when making return types provide stronger guarantees.

I.e.,

Changing foo(): Option<string> to foo(): string shouldn't be considered a breaking change.

Of course foo(): string to foo(): Option<string> is breaking (and should be breaking) since a new type is added.

?string is a supertype of string and thus no existing callers break. I can release an update to my library and not break any of its consumers.

foo('sdf'); // requires no change as ?string is a supertype of string. 

The same problem with Option also exists in the reverse -- when making return types provide stronger guarantees.

?string is a union type of string and null, thus no existing callers break. I can release an update to my library and not break any of its consumers.

foo('sdf'); // requires no change as 'sdf' is allowed in the type union of `null | string` 

The same problem with Option also exists in the reverse -- when making return types provide stronger guarantees.

I.e.,

Changing foo(): Option<string> to foo(): string shouldn't be considered a breaking change.

Of course foo(): string to foo(): Option<string> is breaking (and should be breaking) since a new type is added.

simplified the examples, focused on function arguments.
Source Link

Providing Stronger GuaranteesRelaxing Requirements

Take a look at the following code:

function bar(x: string): Option<string> {...} let y = bar('sdf'); if (y.isEmpty()) { console.log('No result!'); } else { console.log(y); } 

Looks good. Bar expresses that it may or may not return a string. Callers of bar are forced to handle both cases -- when a string is returned and when a string is not. And better yet, the compiler forces us to do this checking since Option is part of the type system.

This code gets released into the wild and tons of people are calling bar. Great success.

Now, as the author of bar, I want to provide a stronger guarantee to my users. I can now guarantee that bar will always return a string in all cases.

function bar(x: string): string; 

Shit. Well what just happened to all of the callers of bar? They BROKE! They no longer compile because I'm returning string rather than Option<string>.

However, if the language understood nullable types we wouldn't have this problem.

function bar(x: string): ?string; let y = bar('sdf'); if (y != null) { console.log('No result!'); } else { console.log(y); } 

?string has all the safety as Option but when changing ?string to string in a return type, we do not break any callers. Everything continues to work as expected.

Now lets look at the reverse.

Relaxing Requirements

This same problem occurs when taking in arguments to a function.

function foo(x: string): string {...} 

Callers doing foo('sdf'); must be updated to foo(Option('sdf'));. Pretty problematic if this is a library released publicly.

However, this isn't an issue in TypeScript and other languages that understand null references. In those languages I would do:

?string is a supertype of string and thus no existing callers break. I can release an update to my library and not break any of its consumers.

foo('sdf'); // requires no change as ?string is a supertype of string. 

The same problem with Option also exists in the reverse -- when making return types provide stronger guarantees.

Providing Stronger Guarantees

Take a look at the following code:

function bar(x: string): Option<string> {...} let y = bar('sdf'); if (y.isEmpty()) { console.log('No result!'); } else { console.log(y); } 

Looks good. Bar expresses that it may or may not return a string. Callers of bar are forced to handle both cases -- when a string is returned and when a string is not. And better yet, the compiler forces us to do this checking since Option is part of the type system.

This code gets released into the wild and tons of people are calling bar. Great success.

Now, as the author of bar, I want to provide a stronger guarantee to my users. I can now guarantee that bar will always return a string in all cases.

function bar(x: string): string; 

Shit. Well what just happened to all of the callers of bar? They BROKE! They no longer compile because I'm returning string rather than Option<string>.

However, if the language understood nullable types we wouldn't have this problem.

function bar(x: string): ?string; let y = bar('sdf'); if (y != null) { console.log('No result!'); } else { console.log(y); } 

?string has all the safety as Option but when changing ?string to string in a return type, we do not break any callers. Everything continues to work as expected.

Now lets look at the reverse.

Relaxing Requirements

This same problem occurs when taking in arguments to a function.

function foo(x: string): string {...} 

However, this isn't an issue in TypeScript and other languages that understand null. In those languages I would do:

?string is a supertype of string and thus no existing callers break. I can release an update to my library and not break any of its consumers.

Relaxing Requirements

Take a look at the following code:

function foo(x: string): string {...} 

Callers doing foo('sdf'); must be updated to foo(Option('sdf'));. Pretty problematic if this is a library released publicly.

However, this isn't an issue in TypeScript and other languages that understand null references. In those languages I would do:

?string is a supertype of string and thus no existing callers break. I can release an update to my library and not break any of its consumers.

foo('sdf'); // requires no change as ?string is a supertype of string. 

The same problem with Option also exists in the reverse -- when making return types provide stronger guarantees.

added 129 characters in body
Source Link

This is a re-hash of Clojure author Rich Hickey's discussion of maybe types here: https://www.youtube.com/watch?v=YR5WdGrpoug

While not as bad a untyped null references,

While not as bad a untyped null references,

This is a re-hash of Clojure author Rich Hickey's discussion of maybe types here: https://www.youtube.com/watch?v=YR5WdGrpoug

While not as bad a untyped null references,

Source Link
Loading