Thread overview
Why is Phobos `Flag` so overthought ?
May 06
user1234
May 06
user1234
May 08
cc
May 08
Dukc
May 09
cc
May 11
cc
May 06

I think this just works:

enum Flag : bool
{
    no,
    yes
}

alias AllowVancancy = Flag; // example usage

Also this is completion friendly whereas Phobos version does not permit DCD completion as it's based on opDispatch.

Compare to phobos version:

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;
    }
}

must be a reason but I cant find it RN ;)

May 06

On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote:

>

I think this just works:

enum Flag : bool
{
    no,
    yes
}

alias AllowVancancy = Flag; // example usage
import std.stdio : writeln;

enum Flag : bool { no, yes }
alias Traditional = Flag;
alias Color = Flag;

void hello(Traditional traditional, Color color) {
    if (traditional && color) {
        writeln("\x1b[31;1mhello world\x1b[0m");
    } else if (traditional && !color) {
        writeln("hello world");
    } else if (!traditional && color) {
        writeln("\x1b[31;1mHello, world!\x1b[0m");
    } else {
        writeln("Hello, world!");
    }
}

void main() {
    hello(Color.yes, Traditional.yes); // this is wrong, but accepted
}
May 06

On Monday, 6 May 2024 at 18:06:53 UTC, Julian Fondren wrote:

>

On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote:

>

I think this just works:

enum Flag : bool
{
    no,
    yes
}

alias AllowVancancy = Flag; // example usage
import std.stdio : writeln;

enum Flag : bool { no, yes }
alias Traditional = Flag;
alias Color = Flag;

void hello(Traditional traditional, Color color) {
    if (traditional && color) {
        writeln("\x1b[31;1mhello world\x1b[0m");
    } else if (traditional && !color) {
        writeln("hello world");
    } else if (!traditional && color) {
        writeln("\x1b[31;1mHello, world!\x1b[0m");
    } else {
        writeln("Hello, world!");
    }
}

void main() {
    hello(Color.yes, Traditional.yes); // this is wrong, but accepted
}

Ah yes I see, strongly typed bools.
Thanks 👍.

May 08

On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote:

>

I think this just works:

enum Flag : bool
{
    no,
    yes
}

...
must be a reason but I cant find it RN ;)

In "properly" designed Phobos packages, it's unambiguous. Take for example std.datetime.stopwatch:

import std.typecons : Flag;
alias AutoStart = Flag!"autoStart";
alias MyOtherFlag = Flag!"myOtherFlag";
...
//auto sw = StopWatch(true); // Not allowed
//auto sw = StopWatch(MyOtherFlag.yes); // Not allowed
auto sw = StopWatch(AutoStart.yes);

It doesn't allow a simple boolean to be used as an argument, or any other Flag as they are different instantiations of a template rather than equivalent aliases.
It is however awful, cumbersome, annoying design and needs to be completely phased out now that we have named arguments.

May 08

On Wednesday, 8 May 2024 at 04:27:13 UTC, cc wrote:

>

It doesn't allow a simple boolean to be used as an argument, or any other Flag as they are different instantiations of a template rather than equivalent aliases.
It is however awful, cumbersome, annoying design and needs to be completely phased out now that we have named arguments.

Flag enforces that the argument says what it relates to. true does not say what it relates to. Named arguments are optional, so I don't see how they could make Flag redundant.

May 08
Nick Treleaven kirjoitti 8.5.2024 klo 13.24:
> On Wednesday, 8 May 2024 at 04:27:13 UTC, cc wrote:
>> It doesn't allow a simple boolean to be used as an argument, or any other Flag as they are different instantiations of a template rather than equivalent aliases.
>> It is however awful, cumbersome, annoying design and needs to be completely phased out now that we have named arguments.
> 
> Flag enforces that the argument says what it relates to. `true` does not say what it relates to. Named arguments are optional, so I don't see how they could make Flag redundant.

Well,

```D
private struct Undefinable{}

auto functionTakingFlags
(   int normalArg,
    Undefinable = Undefinable.init,
    bool Flag1,
    Undefinable = Undefinable.init,
    bool Flag2
){  // fun body...
}
```

As I understand it, this forces the client to use named arguments because they would be trying to pass an `Undefinable` otherwise. They probably could pass `Undefinable` if they really wanted and therefore avoid using named args but they wouldn't do that accidentally.

Whether that is any better than the library `Flag` type is up to taste.
May 09

On Wednesday, 8 May 2024 at 10:24:07 UTC, Nick Treleaven wrote:

>

On Wednesday, 8 May 2024 at 04:27:13 UTC, cc wrote:

>

It doesn't allow a simple boolean to be used as an argument, or any other Flag as they are different instantiations of a template rather than equivalent aliases.
It is however awful, cumbersome, annoying design and needs to be completely phased out now that we have named arguments.

Flag enforces that the argument says what it relates to. true does not say what it relates to. Named arguments are optional, so I don't see how they could make Flag redundant.

It's pointless mandatory verbosity. StopWatch ctor only takes one boolean argument. It doesn't need to specify what it relates to. You either already know, or you have to look it up anyway. Flags made sense when you might get the order of multiple bools confused, but if there's only one, or if you can use named arguments to avoid ambiguity, there's no point in demanding every parameter be a unique type. It's easy to remember I can pass a bool to a StopWatch to autostart it. It's less easy to remember that a specific unique type needs to be used, and remembering whether the name/casing of that type was Start, StartNow, StartAuto, Autostart, AutoStart, autostart, autoStart, etc. We have a tool in our box already called true and that solves the problem. If we had to type out the full name of every argument passed to every function ever written we may as well just adopt ObjC Cocoa style and call it StopWatchWithAutoStartBool().

May 09

On Thursday, 9 May 2024 at 13:40:56 UTC, cc wrote:

>

It's pointless mandatory verbosity. StopWatch ctor only takes one boolean argument. It doesn't need to specify what it relates to. You either already know, or you have to look it up anyway. Flags made sense when you might get the order of multiple bools confused, but if there's only one, or if you can use named arguments to avoid ambiguity,

So you have justified Flag.

>

there's no point in demanding every parameter be a unique type. It's easy to remember I can pass a bool to a StopWatch to autostart it.

But perhaps true means manual start? Remembering can also be used to justify dynamic typing outside of hot loops, I'd rather not rely on remembering with a big team of programmers working on a project.

>

It's less easy to remember that a specific unique type needs to be used, and remembering whether the name/casing of that type was Start, StartNow, StartAuto, Autostart, AutoStart, autostart, autoStart, etc.

So just pass it true, and run the compiler. The compiler will tell you what the correct type is.

>

We have a tool in our box already called true and that solves the problem. If we had to type out the full name of every argument passed to every function ever written we may as well just adopt ObjC Cocoa style and call it StopWatchWithAutoStartBool().

Strawman.

May 09

On Wednesday, 8 May 2024 at 10:24:07 UTC, Nick Treleaven wrote:

>

Named arguments are optional, so I don't see how they could make Flag redundant.

Actually, an external tool could detect when a bool is passed as an argument to a function and warn when not done with a named argument. This would free library APIs from having to use Flag when some users don't care about it. The cost would come in a bit more build system complexity/build time, which might mean a lot less enforcement due to inertia. Though maybe a reasonable trade-off.

May 11

On Thursday, 9 May 2024 at 18:48:12 UTC, Nick Treleaven wrote:

> >

We have a tool in our box already called true and that solves the problem. If we had to type out the full name of every argument passed to every function ever written we may as well just adopt ObjC Cocoa style and call it StopWatchWithAutoStartBool().

Strawman.

Not at all. I mean exactly that. Why do you believe this function is so important it needs to have its argument type explicitly stated, when most functions don't? Either that, or you believe all functions should. It's arbitrary and pointless.