www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why does Nullable implicitly casts when assigning a variable but not

reply Lettever <real email.com> writes:
```
import std;

Nullable!int func() => 3;
void main() {
     Nullable!int a = 3;
     //works fine
     Nullable!int b = func();
     //does not compile
}
Apr 10
next sibling parent reply Andy Valencia <dont spam.me> writes:
On Wednesday, 10 April 2024 at 20:41:56 UTC, Lettever wrote:
 ```
 import std;

 Nullable!int func() => 3;
 void main() {
     Nullable!int a = 3;
     //works fine
     Nullable!int b = func();
     //does not compile
 }
Why make func() Nullable? It just wants to give you an int, right? Making it a function returning an int fixes this. Andy
Apr 10
parent Lettever <real email.com> writes:
On Wednesday, 10 April 2024 at 21:38:22 UTC, Andy Valencia wrote:
 On Wednesday, 10 April 2024 at 20:41:56 UTC, Lettever wrote:
 ```
 import std;

 Nullable!int func() => 3;
 void main() {
     Nullable!int a = 3;
     //works fine
     Nullable!int b = func();
     //does not compile
 }
Why make func() Nullable? It just wants to give you an int, right? Making it a function returning an int fixes this. Andy
Its an example
Apr 10
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, April 10, 2024 2:41:56 PM MDT Lettever via Digitalmars-d-learn 
wrote:
 ```
 import std;

 Nullable!int func() => 3;
 void main() {
      Nullable!int a = 3;
      //works fine
      Nullable!int b = func();
      //does not compile
 }
Technically, no implicit conversion is going on here. What's happening is that you're effectively using an alternate syntax for construction. So, Nullable!int a = 3; gets treated as Nullable!int a = Nullable!int(3); And this only happens in cases where the compiler must do construction, which is what you're doing when you declare a variable and give it a value that isn't the exact same type as the variable, since construction is the only thing that it can do in that case. It's either that or requiring that you call the constructor explicitly, and for better or worse, the compiler interprets it as a constructor call without the explicit constructor call. But it only works, because it's explicit that a variable is being declared, and therefore it must be the case that you're constructing it when you use = to give it a value. On the other hand, when you're returning a value from a function, you're not telling the compiler to construct anything, because unlike when declaring a variable, construction isn't necessary. So, at that point, the value being returned has to either have the same type as the return type, or it needs to implicitly convert to the return type, and int does not implicitly convert to Nullable!int, so you get an error. The only implicit conversions that the language has for user-defined types are 1. When a type has an alias this, it defines an implicit conversion _to_ the type that the alias evaluates to. 2. When a type has a base type (e.g. a class or an enum), then it will implicitly convert to its base type. There is no way to implicitly convert via construction, since having that makes it harder to keep track of what happens when calling a function. This can get very bad in C++ given that it allows you to declare a type to implicitly convert to, and it has implicit construction. They had to add the ability to mark parameters as explicit to block implicit conversions, because it causes enough problems. So, Walter decided to simplify how implicit conversions work in D, and we don't have implicit construction. Of course, there are times when the lack of implicit construction can get annoying (and Nullable is a prime example of that), but other problems are reduced as a result. For Nullable, the solution is to use the nullable helper function so that you don't have to repeat the type. E.G. Nullable!int func() => nullable(3); or auto func() => nullable(3); And in many cases, rather than implicitly calling the constructor when declaring a variable, it's arguably better to just use auto with an explicit constructor call (and it definitely helps with Nullable). E.g. auto a = nullable(3); allows you to not bother giving the explicit type of the Nullable at all. - Jonathan M Davis
Apr 10