4 ms·
I guess a third option would be to use an "Option" but with much more syntactic sugar. So, rather than calling func(some(3)), you'd just call func(3) and the co
by snarkypixel 6y ago
I guess a third option would be to use an "Option" but with much more syntactic sugar. So, rather than calling func(some(3)), you'd just call func(3) and the compiler would automatically wrap it up. Func would be declared this way: def func(int?) to indicate that it's an optional type. IMO you get the best of both world. And then, in many places in the code, you'd have to do "r?.foo()" if r is an Option type. It's different than javascript where the "?" isn't enforced by the compiler.
- sabellito 6y agoTypeScript and, AFAIK, Kotlin provide exactly that. The problem with that special syntax sugar is that then there's no monad to compose with. But it does feel nice for many use cases.
- int_19h 6y agoTypeScript also uses union types for null & undefined. But then on top of that, it has optionals. So you can have: function foo(x: number | undefined); or you can have: function foo(x?: number); The type of x inside foo is the same in both cases, but the type of foo differs. The first version can only be called as foo(x) - where x is possibly undefined - but the second one can also be invoked as foo(), which then has the same meaning as foo(undefined). But this is mostly because they were trying to come up with a type system to capture existing JavaScript patterns. I doubt it'd look like that if it could be designed from scratch.
- bern4444 6y agoIf you have a function that works on numbers: const add3 = val => val + 3; and need to make it work on optional<number>, all you need is map const optionally6 = Some(3).map(add3); where Optional.map works just like array.map. Its the same idea when you map over an array: const add3 = val => val + 3; [1, 2, 3].map(add3); Though an even nicer approach is to use static versions of these functions: const add3 = val => val + 3; const add3ToArrayVals = Array.map(add3); const add3ToOptionals = Optional.map(add3); const someSix = add3ToOptionals(Some(3)); // Some(6); const some456 = add3ToArrayVals([1, 2, 3]);// [4, 5, 6]; This is just a static version of Array.map (doesn't officially exist in JS but is trivial to write) or Optional.map const staticArrayMap = (fn) => (array) => array.map(fn); Edit to add, from your example func(some(3)) would just become some(3).map(func); and then you can do some(3) .map(func) .map(otherFunc) .map(yetAnotherFunc);
- munificent 6y ago> So, rather than calling func(some(3)), you'd just call func(3) and the compiler would automatically wrap it up. You can do implicit conversions and that helps somewhat, but it's not quite the same as actual subtyping. In many cases, there's no natural or efficient way to insert that conversion so you still run into restrictions. For example, in a language with nullable types you can write: int sumPresentValues(Iterable<int?> values) { var result = 0; for (var value in values) if (value != null) result += value; return result; } main() { Iterable<int> values = [1, 2, 3, 4]; print(sumPresentValues(values)); // <-- } The marked line is passing an `Iterable<int>` to a function expecting an `Iterable<int?>`. That works because `int` is an actual subtype of `int?` with no conversion required. With a boxing step, you'd need to somehow wrap the entire collection in one that does the conversion.
- mrkeen 6y agoIn terms of compiler comfort I'd much rather the compiler be able to look at func(3) and deduce that "func accepts an int" rather than "maybe func accepts an int and maybe func accepts an Option<Int>"