Thread overview
Cannot implicitly convert expression `true` of type `bool` to `Flag`
Oct 15, 2020
Ali Çehreli
Oct 15, 2020
Paul Backus
Oct 15, 2020
Ali Çehreli
Oct 16, 2020
Walter Bright
Oct 16, 2020
Andrej Mitrovic
Oct 16, 2020
Walter Bright
Oct 16, 2020
Ali Çehreli
Oct 16, 2020
rikki cattermole
Oct 16, 2020
Paul Backus
October 15, 2020
std.typecons.Flag and its friends Yes and No are so trivial that I copy them here (and reformat for my liking):

template Flag(string name) {
  enum Flag : bool {
    no = false, yes = true
  }
}

struct Yes {
  template opDispatch(string name) {
    enum opDispatch = Flag!name.yes;
  }
}

struct No {
  template opDispatch(string name) {
    enum opDispatch = Flag!name.no;
  }
}

void main() {
  auto a = Flag!"foo".no;     // Fine
  auto b = No.foo;            // Fine

  // Error: cannot implicitly convert expression `true` of type `bool` to `Flag`:
  auto c = Flag!"foo"(true);
}

I think that is a wrong limitation because clearly I am being "explicit" there with a bool value. (I understand the issue but it exposes a limitation of the implementation.) I have to use the ternary operator e.g. after parsing a bool from program arguments:

  bool someFlag;
  // ...
  foo(someFlag ? Yes.someFlag : No.someFlag);

Spoiler alert: I will show the following function template during my DConf Online presentation as a workaround (or "solution"):

auto asFlag(alias variable)() {
  enum name = variable.stringof;
  enum expr = "return variable ? Yes." ~ name ~ " : No." ~ name ~ ";";
  mixin (expr);
}

That allows the following cleaner and "explicit" syntax:

  bool someFlag;
  // ...
  foo(asFlag!someFlag);

(I actually called it flagFromBool in existing code.)

However:

1) I think the standard library should already have something like that to remove the need for that ternary operator.

2) (This feels like something that must have been requested already.) While we're on the topic of removing unnecessary limitations, it would be nice to be able to use "not necessarily quoted string template arguments" just like opDispatch empowers us with.

void foo(Foo!"myFlag" myFlag) {  // <-- Ugly
}

void foo(Foo!myFlag myFlag) {    // <-- Better
}

Maybe there would be a parsing issue with the syntax but then opDispatch seems to be happy with it. Perhaps we should add opDispatch to templates? (Because I tried but failed to achieve the "better" syntax above with opDispatch inside (a struct inside) a template.)

If it requires a special template parameter syntax we can always abuse 'static' further: :o)

template Flag(static string name) {
  // ...
}

Ali
October 15, 2020
On Thursday, 15 October 2020 at 21:33:32 UTC, Ali Çehreli wrote:
> void main() {
>   auto a = Flag!"foo".no;     // Fine
>   auto b = No.foo;            // Fine
>
>   // Error: cannot implicitly convert expression `true` of type `bool` to `Flag`:
>   auto c = Flag!"foo"(true);
> }
>
> I think that is a wrong limitation because clearly I am being "explicit" there with a bool value. (I understand the issue but it exposes a limitation of the implementation.) I have to use the ternary operator e.g. after parsing a bool from program arguments:
>
>   bool someFlag;
>   // ...
>   foo(someFlag ? Yes.someFlag : No.someFlag);

An easier way is to use a cast:

    bool someFlag;
    // ...
    foo(cast(Flag!"someFlag") someFlag);

std.conv.to also knows how to handle this conversion:

    foo(someFlag.to!(Flag!"someFlag"));
October 15, 2020
On 10/15/20 4:25 PM, Paul Backus wrote:

> On Thursday, 15 October 2020 at 21:33:32 UTC, Ali Çehreli wrote:

>>   bool someFlag;
>>   // ...
>>   foo(someFlag ? Yes.someFlag : No.someFlag);
>
> An easier way is to use a cast:
>
>      bool someFlag;
>      // ...
>      foo(cast(Flag!"someFlag") someFlag);
>
> std.conv.to also knows how to handle this conversion:
>
>      foo(someFlag.to!(Flag!"someFlag"));

I still like the ternary operator more partly because it uses features that are explained in the documentation. :) Both of your methods rely on the fact that the implementation is a bool-based enum. Are the users expected to know that? If yes, then the library can't change the implementation.

Ali


October 15, 2020
On 10/15/2020 2:33 PM, Ali Çehreli wrote:
> [...]

Named parameters takes care of this.
October 16, 2020
On Friday, 16 October 2020 at 06:50:49 UTC, Walter Bright wrote:
> On 10/15/2020 2:33 PM, Ali Çehreli wrote:
>> [...]
>
> Named parameters takes care of this.

Has anyone started to work on an implementation?
October 16, 2020
On 10/15/20 11:50 PM, Walter Bright wrote:
> On 10/15/2020 2:33 PM, Ali Çehreli wrote:
>> [...]
> 
> Named parameters takes care of this.

Maybe for some people, yes. (Assuming calling with named parameters is optional.) But I would still be uncomfortable defining a function with naked bools like this:

void foo(bool shouldDoThis, bool shouldDoThat) {
  // ...
}

The possibility of calling it wrong is still there. Is that purely the caller's fault? What do others think?

Ali

October 17, 2020
On 17/10/2020 4:20 AM, Ali Çehreli wrote:
> The possibility of calling it wrong is still there. Is that purely the caller's fault? What do others think?

I have never been convinced of the arguments against using bool for flags in params.

But I do think that having named parameters rather than named arguments would have removed this as an issue. The name should be required.
October 16, 2020
On Friday, 16 October 2020 at 15:46:54 UTC, rikki cattermole wrote:
> On 17/10/2020 4:20 AM, Ali Çehreli wrote:
>> The possibility of calling it wrong is still there. Is that purely the caller's fault? What do others think?
>
> I have never been convinced of the arguments against using bool for flags in params.
>
> But I do think that having named parameters rather than named arguments would have removed this as an issue. The name should be required.

It's always possible to add named parameters *in addition* to named arguments. The two are not mutually incompatible.
October 16, 2020
On 10/16/2020 2:44 AM, Andrej Mitrovic wrote:
> On Friday, 16 October 2020 at 06:50:49 UTC, Walter Bright wrote:
>> On 10/15/2020 2:33 PM, Ali Çehreli wrote:
>>> [...]
>>
>> Named parameters takes care of this.
> 
> Has anyone started to work on an implementation?

Not myself, anyway. I'm currently buried.