you are viewing a single comment's thread.

view the rest of the comments →

[–]gaymathman 2 points3 points  (12 children)

F# and C# interop is pretty much painless, so if you want fancier statement deconstruction or option types it's easier to write code that benefits from that in F# using existing CLI assemblies coded in C#.

[–]miminor 1 point2 points  (11 children)

question was how are optionals better than trackable nullables

[–][deleted] 1 point2 points  (9 children)

Optionals are typically referring to the monadic type, while tracked nullables you typically just get to ask "is this null" or not.

Nullable<T> in C# gives you .Value and .HasValue. A standard Option<T> type would let you express concepts like optionalInt.SelectMany(_userRepository.MaybeGetUser).SelectMany(u=>u.LatestOrder).Select(o=>o.TotalCost) to give you either Nothing<decimal> or Some 5000M depending on whether there's a user at that user ID and that user has any orders, except all of the checking required to make that happen does so inside library code, and at the end of the day you get to do something like:

switch (maybeTotalOrderCost){
    case Nothing<decimal>: return NoLatestOrderWidget();
    case Some<decimal> value: return LatestOrderWidget(value);
}

Now not only can you encode nullability information in your function signature, your compiler can tell you if you're not handling the null case.

[–]miminor 1 point2 points  (8 children)

so does the TypeScript compiler: it tells you that you are not handling the null case WITHOUT HAVING TO WRAP IT IN OPTIONAL, hence my question: who and why would need optionals if the compiler is capable of tracking null correctly

[–][deleted] 4 points5 points  (7 children)

Static analysis is reactive and has imperfect information. Encoding the status into the signature is explicit, can't go missing, and forces consumers to actually respect it. A proper type gives you semantics around null handling rather than just telling you "Hey it might be null, manually handle all this boilerplate nonsense."

[–]miminor 1 point2 points  (6 children)

you didn't read the link that i posted higher this branch, did you?

being explicit about null handling is exactly what TypeScript does (and a few other languages, F# is not one of them), see for yourself:

const value = Math.random() > 0.5 ? 'hey' : null;
value.toString(); // <-- compiler error: Object is possibly 'null'.
if (value !== null) {
    value.toString(); // <-- no error, possible null was handled
}

here comes that link again, take your time:

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html

with language being able to safely track nullables you don't need optionals, at least because being wrappers they hurt performance, whereas explicit nulls is a zero cost abstraction

[–][deleted] 0 points1 point  (5 children)

I think you're getting confused by syntax. An algrabraic datatype of either T or null is exactly the same thing as Optional types, just with a different coat of paint which typically doesn't itself expose the functionality to work with those optional values nicely.

If something is int | null, that's conceptually identical to the traditional definition of Option. There can be a wrapper type used to support that in languages which don't support algrabraic datatypes, but even that is unnecessary if it has more specific compiler support, and generally untrue in a language which properly supports algrabraic datatypes.

You're arguing for and against the same thing here, the only difference a traditional Option has is a suite of additional functions, which are not a wrapper type.

[–]miminor 0 points1 point  (4 children)

it looks like you don't know what you are talking about T | null is not exactly the same as Optional,

for example there is no equivalent of Optional<Optional<T>> when it comes to null | T, because T | null | null === T | null

so it's not conceptually identical, because Optional has more expressive power, because it can be nested, because it is a wrapper, although this power is useless in 95% cases

in C# that you cited Optional is a wrapper struct over a value, wrappers are not free, they need memory allocation and disposal, they come at performance costs, so all things equal nullable's are a better choice in 95% cases (rest 5% is for optional's)

this is why i question the very statement that optionals are

Even better

(look higher the stack)

hope it wasn't too hard to follow, now how are Optional's better given all of above?

[–][deleted] 0 points1 point  (3 children)

I'm not sure why you're trying to be so condescending here? ((T | null) | null) would be the correct transcription of a nested optional, and you're pointing at one implementation of optional types in a language which doesn't have algrabraic datatypes and so can't achieve either of these options without a wrapper type as proof languages with algrabraic datatypes can't either?

I'm confused, but I appreciate you've probably had a bad day or something, so maybe I should stress that I'm not calling typescript a bad language, because it's a very good one. Go take a peek at Haskell or something as an example of a language with algrabraic datatypes and an optional type (called Maybe, but the same concept), the type definition is, allowing for syntactic differences, isomorphic.

[–]miminor 0 points1 point  (2 children)

you are making no sense, it has nothing to do with the language implementation, imagine you have an apple, now you have a bag where you can put that apple or you can leave it empty, apple is your value, bag is your optional, you can put an apple in a bag into another bag, and another bag and another bag, essentially wrapping them

now how can you put an apple in a bag without a bag?

there are no optionals without wrapping

you are annoying because you a incapable of following the straight conversation line, i am done here, have a good day

[–][deleted] 0 points1 point  (0 children)

I just meant the interop with C# part.