Nullable/Non-Nullable function return type depending on nullability of input

Hi Guys,
I am currently trying to enable null-safety for code like this:

class Test {
  public static function main() {
    var input1:String = "12345";
    input1 = left(input1, 3);

    var input2:String = null;
    input2 = left(input2, 3);
  }

  public static function left(str:String, len:Int):String {
    if (str == null)  return null;
    if (str.length <= len) return str;
    return str.substring(0, len);
  }
}

So naturally I went changing the left function’s signature to left(str:Null<String>, len:Int):Null<String>

This however now also means that if I call the function with a non-nullable input I get a nullable result which I then have to manually handle and means changes to a lot of code locations.

Is it possible using some macro/abstract/generics magic to make the return type nullable/non-nullable depending on the input value? Something like

public static function left<T:Either2<String,Null<String>>(str:T, len:Int):T { ... }

Or can I somehow overload the method so I have to definitions:

public static function left(str:String, len:Int):String { ... }
public static function left(str:Null<String>, len:Int):Null<String>) { ... }

and the compiler picks the right one?

Any ideas are appreciated.

Apparently this seems to work:

class Test {
  public static function main() {
    var input1:String = "12345";
    input1 = left(input1, 3);

    var input2:String = null;
    input2 = left(input2, 3);
  }

  public static function left<T:String>(str:T, len:Int):T { // <-- introduced T
    if (str == null)  return null;
    if (str.length <= len) return str;
    return cast str.substring(0, len);  // <-- added cast
  }
}

Is this the proper/best solution or does this rely on a compiler bug?

If you don’t specify the return type, the compiler will infer one, hopefully accounting for nullability (so remove :String from the function)

@haxiomic thanks for your response. unfortunately not specifying the return type didn’t work.

Ahh I think I understand your issue a bit better now

And yes I think a type parameter solution is the best if that works (I can’t seem to get this to work however)

Without type parameters the function has a single signature, either returning String or Null<String>. Overloads might be useful for this but they’re not quite there yet

I think at a higher level however, things will get simpler for you if you don’t have null checks like this and instead keep functions simple and non-nullable; is left(null) -> null a useful design? Or should this null have been eliminated earlier and so left(null) is never called?

1 Like