www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why is Phobos `Flag` so overthought ?

reply user1234 <user1234 12.de> writes:
I think this just works:

```d
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:

```d
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
next sibling parent reply Julian Fondren <julian.fondren gmail.com> writes:
On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote:
 I think this just works:

 ```d
 enum Flag : bool
 {
     no,
     yes
 }

 alias AllowVancancy = Flag; // example usage
 ```
```d 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
parent user1234 <user1234 12.de> writes:
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:

 ```d
 enum Flag : bool
 {
     no,
     yes
 }

 alias AllowVancancy = Flag; // example usage
 ```
```d 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 06
prev sibling parent reply cc <cc nevernet.com> writes:
On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote:
 I think this just works:

 ```d
 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: ```d 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 07
parent reply Nick Treleaven <nick geany.org> writes:
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
next sibling parent Dukc <ajieskola gmail.com> writes:
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 08
prev sibling next sibling parent reply cc <cc nevernet.com> writes:
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
parent reply Nick Treleaven <nick geany.org> writes:
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
parent cc <cc nevernet.com> writes:
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.
May 11
prev sibling parent Nick Treleaven <nick geany.org> writes:
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 09