News for hackers. Stuff that matters.
Re:Things Go needs more than generics by zeckalpha on Monday October 04, 2021 @08:05AM (#28745611)
You just described an implementation of Option types, albeit one with syntactic sugar of a ? Rather than Option<String>.
Re:Things Go needs more than generics by tel on Monday October 04, 2021 @09:00AM (#28746104)
I don't know Kotlin, but these usually are distinct from Options in an important way, idempotency `String?? = String?` or `String|null|null = String|null`.

This equation makes sense for some mental models, but isn't quite the same as Option. In particular, Option[T] has the nice property that you can map over its inner type in a naive fashion `forall S. (T -> S) -> (Option[T] -> Option[S])` whereas the coalescing version above needs an additional assumption that `S` is non-nullable.

    forall S not null. (T -> S) -> (T? -> S?)
This can really get in the way of some kinds of generic programming.
Re:Things Go needs more than generics by ohgodplsno on Monday October 04, 2021 @08:24AM (#28745756)
Not necessarily. Not only is it Option.Some/None/ProbablySomeBuyMaybeNoneBecauseJava, it doesn't offer the exact separation that Options can offer: you can stick a value in Option.None (String? can contain null or ""). Nullable types are different to options.

(Bonus point for Java that has introduced Option types, that can still be null)

Re:Things Go needs more than generics by nemetroid on Monday October 04, 2021 @08:44AM (#28745933)
That sounds like an Option type to me:

  String? :: Option
  String :: Option.Some
  null :: Option.None
Re:Things Go needs more than generics by Nullabillity on Monday October 04, 2021 @09:17AM (#28746293)
The problem with Kotlin is that it only has one global "anything-but-null", so nested ?s are collapsed (String?? is equivalent to String?). This is because it needs to run on the JVM, which only knows about is-null and is-not-null.

This interacts terribly with generics, since it means that only one side of the generic boundary can "own" the null value at any one time. To simplify a case where this can cause issues:

    class Loadable<T>(
      // null until value is loaded
      var valueIfLoaded: T?,
    )
    // returns null if user is not found
    fun getUser(id: String): Loadable<User?>
Code that interprets Loadable<T> will get stuck showing a loading bar, since it has no idea about getUser using null for anything else. This doesn't even generate a warning!

The "correct thing to do here would be to add a `T: Any` bound on Loadable, which prevents T from itself being a nullable type. That would notify the author of getUser that they need to box the User?, so that the cases are kept separate:

    data class Box<T>(val value: T)
    class Loadable<T>(
      // null until value is loaded
      var valueIfLoaded: T?,
    )
    // returns null if user is not found
    fun getUser(id: String): Loadable<Box<T?>>
These are things you don't even have to consider when using a typical well-designed Option type (which, mind you, could still have a syntax sugar for T? if you wanted it).
Re:Things Go needs more than generics by dtech on Monday October 04, 2021 @08:55AM (#28746047)
I'd argue that they are fundamentally different. Option is "just another type". You interact with it using constructors, map/flatMap/get etc. You could implement Optional in Java 1.5 but can't implement nullable types in current Java.

Nullable types are a feature of the type system and require language support, but the benefit is that you don't touch typical programming patterns

   val foo: T? = x()
   if(foo == null) { return ... }
   // foo is now T, optionality gone
v.s.

   val foo: Option<T> = x()
   // following must be wrapped and sprinkled in .map, .flatMap, .orElse
You can sort-of achieve the first with .isPresent() + .get(), but it clutters the scope, is more verbose, and is not really idiomatic.
Re:Things Go needs more than generics by nemetroid on Monday October 04, 2021 @09:48AM (#28746642)
> not really idiomatic.

Really? I haven't used Java in a long time, but in the languages where I've used Optional types, you'd always check for presence once and then extract the value before further use.

Re:Things Go needs more than generics by kevinmgranger on Monday October 04, 2021 @09:08AM (#28746194)
There is no way to have the equivalent of an Option<Option<String>>, so it's not quite the same.

That said, if one ever finds themselves seriously using a nested Option, it's probably time to write a new enum for that use case.