www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Any way to automatically convert structs on return?

reply Emma <VuLXn6DBW PPtUm7TvV6nsw.com> writes:
This code works:

```d
struct None {}

struct Option(T) {
     bool hasSome;
     T value;

     this(None) {}

     this(T v) {
         hasSome = true;
         value = v;
     }
}

Option!int a = 123;    // automatically constructs an Option!int 
from a bare int
Option!int b = None(); // same as above but with None
```

but this doesn't:

```d
Option!int something() {
   return None(); // Error: cannot implicitly convert expression 
`None()` of type `None` to `Option!int`
}
```

This kind of prevents ergonomic code like the above. Instead you 
have to use a function like `Option!T None(T)() => Option!T()` 
and then you have to repeat yourself with `return None!int` and 
etc... it's quite annoying :(

In C++ you may do this fairly easily, but of course there are 
various pitfalls because it's C++. But at least you can opt out 
with `explicit` most of the time.

Thanks in advance!
Aug 01
next sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
No, D does not support implicit construction.

However in saying that, I will continue to argue in support of sum types 
when they get added to the language to support implicit construction!
Aug 01
prev sibling next sibling parent reply IchorDev <zxinsworld gmail.com> writes:
On Thursday, 1 August 2024 at 07:25:53 UTC, Emma wrote:
 This code works:

 ```d
 struct None {}

 struct Option(T) {
     bool hasSome;
     T value;

     this(None) {}

     this(T v) {
         hasSome = true;
         value = v;
     }
 }

 Option!int a = 123;    // automatically constructs an 
 Option!int from a bare int
 Option!int b = None(); // same as above but with None
 ```
 but this doesn't:
 ```d
 Option!int something() {
   return None(); // Error: cannot implicitly convert expression 
 `None()` of type `None` to `Option!int`
 }
 ```
 This kind of prevents ergonomic code like the above. Instead 
 you have to use a function like `Option!T None(T)() => 
 Option!T()` and then you have to repeat yourself with `return 
 None!int` and etc... it's quite annoying :(

 In C++ you may do this fairly easily, but of course there are 
 various pitfalls because it's C++. But at least you can opt out 
 with `explicit` most of the time.

 Thanks in advance!
I’m pretty sure this is intentional to prevent ambiguity, but I can’t quite remember what the point of that is. You can always just write the constructor manually, but yes it’s a hassle. I wonder how open people would be to changing this restriction? P.S. You might want to put `value = void`, otherwise it’ll always be default-constructed. Phobos also has `Nullable` if you want another implementation for reference.
Aug 01
next sibling parent reply user1234 <user1234 12.de> writes:
On Thursday, 1 August 2024 at 08:46:00 UTC, IchorDev wrote:
 [...]
 I’m pretty sure this is intentional to prevent ambiguity, but I 
 can’t quite remember what the point of that is.
The problem would be that sorting the candidates of an overload set would be more complicated. Also in certain cases it would be less obvious to get which one is selected.
Aug 01
parent reply IchorDev <zxinsworld gmail.com> writes:
On Thursday, 1 August 2024 at 09:55:08 UTC, user1234 wrote:
 The problem would be that sorting the candidates of an overload 
 set would be more complicated. Also in certain cases it would 
 be less obvious to get which one is selected.
Please elaborate about how this would interact with function overloads at all? The function has the same parameters, same return type, same attributes… what’s different exactly?
Aug 01
parent reply user1234 <user1234 12.de> writes:
On Thursday, 1 August 2024 at 10:59:03 UTC, IchorDev wrote:
 On Thursday, 1 August 2024 at 09:55:08 UTC, user1234 wrote:
 The problem would be that sorting the candidates of an 
 overload set would be more complicated. Also in certain cases 
 it would be less obvious to get which one is selected.
Please elaborate about how this would interact with function overloads at all?
That was a general criticism of implicit construction. The classic example is ```d struct S {int i;} function f(S s); function f(int i); unittest { f(0); } // both match ``` unless the idea would rather be to allow implicit construction only in the context of initialization.
Aug 01
parent IchorDev <zxinsworld gmail.com> writes:
On Thursday, 1 August 2024 at 14:20:29 UTC, user1234 wrote:
 That was a general criticism of implicit construction.
We are only talking about it in the context of returning from a function.
 The classic example is

 ```d
 struct S {int i;}
 function f(S s);
 function f(int i);

 unittest { f(0); } // both match
 ```

 unless the idea would rather be to allow implicit construction 
 only in the context of initialization.
You are wasting my time. Show me how this applies to retuning from within a function.
Aug 01
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Thursday, 1 August 2024 at 08:46:00 UTC, IchorDev wrote:
 P.S. You might want to put `value = void`, otherwise it’ll 
 always be default-constructed.
Doing `= void` can violate the assumptions of a destructor of T. Nullable uses a union to store T, so it can decide when to call the destructor.
Aug 01
prev sibling next sibling parent Dukc <ajieskola gmail.com> writes:
Emma kirjoitti 1.8.2024 klo 10.25:
 This kind of prevents ergonomic code like the above. Instead you have to 
 use a function like `Option!T None(T)() => Option!T()` and then you have 
 to repeat yourself with `return None!int` and etc... it's quite annoying :(
While this isn't exactly less verbose, I mention it because at least you don't have to write the type twice: ```D Option!int something() { return typeof(return)(None()); }
Aug 01
prev sibling next sibling parent Lance Bachmeier <no spam.net> writes:
On Thursday, 1 August 2024 at 07:25:53 UTC, Emma wrote:

 but this doesn't:

 ```d
 Option!int something() {
   return None(); // Error: cannot implicitly convert expression 
 `None()` of type `None` to `Option!int`
 }
 ```
For the program you've written, I'm happy it doesn't compile, because a lot of the time the compiler would be making buggy code compile - though I would love to have a way to do it explicitly. In this case you can change your definition of None to use alias this and it will compile: ``` struct None { alias convert this; Option!int convert() { return Option!int(None()); } } ```
Aug 01
prev sibling next sibling parent Emma <VuLXn6DBW PPtUm7TvV6nsw.com> writes:
Thanks everyone for the replies! I just thought it was weird that 
implicit construction is seemingly supported when directly 
initialising a struct but not in any other case. I guess it's 
because it's clearly less ambiguous.

On Thursday, 1 August 2024 at 13:07:09 UTC, Lance Bachmeier wrote:
 For the program you've written, I'm happy it doesn't compile, 
 because a lot of the time the compiler would be making buggy 
 code compile - though I would love to have a way to do it 
 explicitly. In this case you can change your definition of None 
 to use alias this and it will compile:
The alias this doesn't work generically, though. Either way I agree that implicit construction, if it was present in D, should not be the default, instead being opt-in like say through an `implicit this(...)` or whatever instead of C++'s horrendous implicit by default behaviour.
Aug 01
prev sibling parent Juraj <zero vec4.xyz> writes:
On Thursday, 1 August 2024 at 07:25:53 UTC, Emma wrote:
 ```d
 Option!int something() {
   return None(); // Error: cannot implicitly convert expression 
 `None()` of type `None` to `Option!int`
 }
 ```
Not D per se, but you can check Adam D. Ruppe's current work. If I am not mistaken, the thing you are asking for is already possible in the nightly release. https://dpldocs.info/this-week-in-arsd/Blog.Posted_2024_02_20.html#implicit-construction Juraj
Aug 02