Optional parameters?
Steven Schveighoffer
schveiguy at yahoo.com
Mon Apr 2 13:02:23 UTC 2018
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
More information about the Digitalmars-d-learn
mailing list