On 4/1/18 6:01 PM, Jonathan M Davis wrote:
On Sunday, April 01, 2018 11:54:16 Steven Schveighoffer via Digitalmars-d-
learn wrote:
I currently have a situation where I want to have a function that
accepts a parameter optionally.

I thought maybe Nullable!int might work:

void foo(Nullable!int) {}

void main()
{
     foo(1); // error
     int x;
     foo(x); // error
}

Apparently, I have to manually wrap an int to get it to pass. In other
languages that support optional types, I can do such things, and it
works without issues.

I know I can do things like this:

void foo(int x) { return foo(nullable(x)); }

But I'd rather avoid such things if possible. Is there a way around
this? Seems rather limiting that I can do:

Nullable!int x = 1;

but I can't implicitly convert 1 to a Nullable!int for function calls.

You'll have to call nullable. D has no form of implicit construction. You
can use alias this to define how to convert _from_ a type but not _to_ a
type, and alias this is the only way to define implicit conversions in D. I
think that it works with variable initialization, because on some level, the
compiler treats

Type a = args;

the same as

auto a = Type(args);

e.g.

struct S
{
     int _i;

     this(int i)
     {
         _i = i;
     }
}

void main()
{
     S s = 42;
}

compiles with no alias this at all.

This is my main reason for confusion -- it should work in all cases, not just this one.

As I understand it, the lack of ability to define implicit construction is
part of the attempt to avoid some of the problems with regards to stuff like
function hijacking that come in C++ from allowing all of the implicit
conversions that it allows. It may also be in part to prevent issues related
to being able to define the same implicit conversion multiple ways (e.g. if
type A implictly casts to B, and you can implicitly construct B from A,
which conversion does the compiler use when converting A to B?).

This isn't that hard. You just define an order (obvious choice here is that implicit conversions win over construction).

Ultimately, it's a bit of a double-edged sword in that it prevents certain
classes of bugs but also makes it impossible to do something like have a
function parameter be a wrapper type while the function argument is the type
being wrapped. So, you couldn't do something like use string for IP
addresses everywhere in your code and then change it to a struct later, and
have all of the function calls that passed strings still work without
updating them (which you can do in C++).

I'd be fine with a built-in option type, but we have delegated that to the library. But the library isn't up to the (complete) task. It makes things less pleasant, as it exposes a bit of internal implementation for the caller. While I get annoyed quite a bit with Swift's usage of optionals everywhere, they can make dealing with optional data much more concise and straightforward.

Given how problematic implicit conversions tend to be in generic code, I
often think that we might be better off with no user-defined implicit
conversions in D at all, but Nullable is one case where the fact that we
can't define implicit construction gets annoying.

I agree, they can be annoying. Sometimes you just want to write:

a = b;

and not worry about all the trouble this can cause. Phobos is littered with stuff like hasElaborateCopyConstructor, etc. But it's annoying that we still have to worry about it *and* we can't get all the benefits of having full-blown implicit conversion.

-Steve

Reply via email to