diff --git a/changelog/remove-nullable-alias-get-this.dd b/changelog/remove-nullable-alias-get-this.dd new file mode 100644 index 00000000000..cd51c0e7880 --- /dev/null +++ b/changelog/remove-nullable-alias-get-this.dd @@ -0,0 +1,15 @@ +`Nullable` `alias get this` has been deprecated + +`Nullable`'s feature of implicitly converting to its contained value has been marked deprecated. + +All sites where a `Nullable!T` is implicitly converted to `T`, potentially throwing an error at runtime, +will now produce a deprecation warning or error with `-de`. + +To fix this, explicitly use `.get` to access the contained value of the `Nullable`. + +`alias get this` is the only implicit conversion in D that may throw an error. Since it is an implicit conversion, +it can easily be used accidentally and lead to unexpected runtime errors. By explicitly invoking `get`, +the developer acknowledges that the operation has a chance of error. Conversely, by not implicitly converting +`Nullable!T` to `T`, the compiler gives the developer a chance to spot forgotten `isNull` checks. + +This feature will be removed after release 2.096. diff --git a/std/typecons.d b/std/typecons.d index 53737632563..e07ef043fb8 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -2960,7 +2960,6 @@ Params: Gets the value if not null. If `this` is in the null state, and the optional parameter `fallback` was provided, it will be returned. Without `fallback`, calling `get` with a null state is invalid. -This function is also called for the implicit conversion to `T`. Params: fallback = the value to return in case the `Nullable` is null. @@ -2981,7 +2980,9 @@ Returns: return isNull ? fallback : _value.payload; } -/// +//@@@DEPRECATED_2.096@@@ +deprecated( + "Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly.") @system unittest { import core.exception : AssertError; @@ -2999,24 +3000,33 @@ Returns: assert(i == 5); } + //@@@DEPRECATED_2.096@@@ + deprecated( + "Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly.") + @property ref inout(T) get_() inout @safe pure nothrow + { + return get; + } + /// @safe pure nothrow unittest { int i = 42; - Nullable!int ni2; - int x = ni2.get(i); + Nullable!int ni; + int x = ni.get(i); assert(x == i); - ni2 = 7; - x = ni2.get(i); + ni = 7; + x = ni.get(i); assert(x == 7); } /** Implicitly converts to `T`. `this` must not be in the null state. +This feature is deprecated and will be removed after 2.096. */ - alias get this; + alias get_ this; } /// ditto @@ -3046,8 +3056,8 @@ auto nullable(T)(T t) if (!queryResult.isNull) { //Process Mr. Doe's customer record - auto address = queryResult.address; - auto customerNum = queryResult.customerNum; + auto address = queryResult.get.address; + auto customerNum = queryResult.get.customerNum; //Do some things with this customer's info } @@ -3071,6 +3081,9 @@ auto nullable(T)(T t) assertThrown!Throwable(a.get); } +//@@@DEPRECATED_2.096@@@ +deprecated( + "Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly.") @system unittest { import std.exception : assertThrown; @@ -3124,10 +3137,10 @@ auto nullable(T)(T t) assert(s == S(6)); assert(s != S(0)); assert(s.get != S(0)); - s.x = 9190; - assert(s.x == 9190); + s.get.x = 9190; + assert(s.get.x == 9190); s.nullify(); - assertThrown!Throwable(s.x = 9441); + assertThrown!Throwable(s.get.x = 9441); } @safe unittest { @@ -3156,7 +3169,7 @@ auto nullable(T)(T t) assert(s.isNull); s = S(5); assert(!s.isNull); - assert(s.x == 5); + assert(s.get.x == 5); s.nullify(); assert(s.isNull); } @@ -3276,10 +3289,10 @@ auto nullable(T)(T t) auto x2 = immutable Nullable!S1(sm); auto x3 = Nullable!S1(si); auto x4 = immutable Nullable!S1(si); - assert(x1.val == 1); - assert(x2.val == 1); - assert(x3.val == 1); - assert(x4.val == 1); + assert(x1.get.val == 1); + assert(x2.get.val == 1); + assert(x3.get.val == 1); + assert(x4.get.val == 1); } auto nm = 10; @@ -3292,8 +3305,8 @@ auto nullable(T)(T t) static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); })); static assert(!__traits(compiles, { auto x3 = Nullable!S2(si); })); auto x4 = immutable Nullable!S2(si); - assert(*x1.val == 10); - assert(*x4.val == 10); + assert(*x1.get.val == 10); + assert(*x4.get.val == 10); } { @@ -3303,10 +3316,10 @@ auto nullable(T)(T t) auto x2 = immutable Nullable!S3(sm); auto x3 = Nullable!S3(si); auto x4 = immutable Nullable!S3(si); - assert(*x1.val == 10); - assert(*x2.val == 10); - assert(*x3.val == 10); - assert(*x4.val == 10); + assert(*x1.get.val == 10); + assert(*x2.get.val == 10); + assert(*x3.get.val == 10); + assert(*x4.get.val == 10); } } @safe unittest @@ -3397,16 +3410,6 @@ auto nullable(T)(T t) assert(c.canary == 0xA71FE); } -// Regression test for issue 18539 -@safe unittest -{ - import std.math : approxEqual; - - auto foo = nullable(2.0); - auto bar = nullable(2.0); - - assert(foo.approxEqual(bar)); -} // bugzilla issue 19037 @safe unittest {