March 24, 2010
On 03/24/2010 08:28 AM, bearophile wrote:
> Regan Heath:
>> I find being able to define bit flag values with an enum and
>> combine them using | and |= or negate with&= ~flag etc very
>> useful.
>
> The cause of the problem here is that you are trying to use enums for
> a different purpose, as composable flags. In C# enums and flags are
> not the same thing, you can use the [Flags] attribute:
> http://www.codeguru.com/vb/sample_chapter/article.php/c12963 The
> ridiculous thing of D development is that no one ever takes a look at
> C#, it often already contains a solution to problems we are just
> starting to find in D (or often that we just refuse to see in D).

There are many good things in many languages to look at. C# has its pluses and minuses, but is definitely not the be-all, end-all of PLs. In particular, economy of means does not seem to be one of C#'s strengths.

> As
> they say: "Those who cannot learn from C# are doomed to re-invent it,
> often badly."

Who are "they"?

> (In D you can solve this problem creating a flags struct, using a
> strategy similar to the one used by std.bitmanip.bitfields, but it
> feels hackish).

Why does a mechanism that allows creating bitfields, custom enums, flags, custom-base literals, and more, feel hackish, whereas dumping a wheelbarrow of narrow-usefulness features with every release while still failing to address major problems (concurrency, immutability) feels not?


Andrei
March 24, 2010
bearophile wrote:
> Regan Heath:
>> I find being able to define bit flag values with an enum and
>> combine them using | and |= or negate with &= ~flag etc very
>> useful.
> 
> The cause of the problem here is that you are trying to use enums for
> a different purpose, as composable flags. In C# enums and flags are
> not the same thing, you can use the [Flags] attribute: http://www.codeguru.com/vb/sample_chapter/article.php/c12963 The
> ridiculous thing of D development is that no one ever takes a look at
> C#, it often already contains a solution to problems we are just
> starting to find in D (or often that we just refuse to see in D). As
> they say: "Those who cannot learn from C# are doomed to re-invent it,
> often badly."

Thanks, I haven't used the flags attribute in C# before.  It is like the "numeric base type" suggestion I made, in that it causes an alternate set of behaviour for 'enum'.  I was hoping there was some way to get what we want without extra syntax.

> (In D you can solve this problem creating a flags struct, using a
> strategy similar to the one used by std.bitmanip.bitfields, but it
> feels hackish).

I've not used that (it's been a while since I used D for anything practical) but it seems like it's not quite what we want, we really want a set of compile time constants.

R
March 24, 2010
Regan Heath:
> but it seems like it's not quite what we want, we really want a set of compile time constants.

I meant using the same design strategy. See below.

--------------------

Andrei:

>In particular, economy of means does not seem to be one of C#'s strengths.<

I agree, surely C# is not a compact and orthogonal language. C# devs are aware of this, you can see it from the very low number of features they have added to C#4.


>Who are "they"?<

Almost everyone that posts on this newsgroup :-) I put myself in the group too, because I am not expert of C# and many times in the past I have "invented" things for D that later I have found in C#, sometimes with a design better than mine.


>Why does a mechanism that allows creating bitfields, custom enums, flags, custom-base literals, and more, feel hackish, whereas dumping a wheelbarrow of narrow-usefulness features with every release while still failing to address major problems (concurrency, immutability) feels not?<

I agree with you that too many features turn a language in a ball of mud. On the other hand an excess of abstraction or relying too much on the composition of elementary parts makes writing code like solving a Rubik cube (see Scheme language or your "find" algorithm in Phobos2).

In this case it may be acceptable to use compile-time strings to create a flags-like struct, I'd like to write it :-) But I am not sure it's the best solution. I have to judge when it's done. Maybe in this case the C# solution is the best. The main of my precedent post was that you can't allow arithmetic operations on enums just because you may want to use them as bit flags. They are two different purposes. In this case C# tells the two usages apart in a clear way, instead of mudding them together. If the purpose is clear and well defined, and the usage is safe, I think programmers don't have too much hard time remembering the purpose of fields. That's why I don't think introducing "many" keywords is bad, it's better to use something like "autoconst" than using "inout" to save a keyword, that's unrelated to the its purpose. The lesson given by the success of large languages like C# is that programmers are able to remember and use many things if their purpose is clear and defined in a semantically tidy way. (I think the current design decisions of D enums are not the best ones.)

The code of std.bitmanip.bitfields is hard or impossible to understand, to read, to fix, to modify, to improve. Compile-time strings used as macros are acceptable for one-liners, but your (nicely safe!) bitfields shows that it's not fit when you want to push it to that complexity level.

Bye,
bearophile
March 24, 2010
To invent a software you can first find the best syntax. This seems a nice syntax, very similar to the enum one (that ubyte is optional):

flags ubyte Todo {
    do_nothing,
    walk_dog,
    cook_breakfast,
    deliver_newspaper,
    visit_miss_kerbopple,
    wash_covers
}

Todo todo = Todo.walk_dog | Todo.deliver_newspaper | Todo.wash_covers;
if (todo == (Todo.walk_dog | Todo.deliver_newspaper)) { ...
if ((Todo.walk_dog | Todo.deliver_newspaper) in todo) { ...
if ((Todo.walk_dog | Todo.deliver_newspaper) & todo) { ...
assert((Todo.walk_dog | Todo.walk_dog) == Todo.walk_dog); // OK


A way to implement it with current D2 syntax:


alias Flags!(ubyte, "do_nothing",
                    "walk_dog"
                    "cook_breakfast"
                    "deliver_newspaper"
                    "visit_miss_kerbopple"
                    "wash_covers") Todo;


Where Flags defines a struct, "do_nothing" are compile-time constants. It can overload 8 operators: =   ==   |    |=    in   &   &=  opBool

The operator ! too can be defined, but I think it looks too much like the | so it can be omitted (other operators like ^ and ~ are possible).


Something like this can't work if enums become tidier:

enum ubyte Todo {
    mixin(Flags);
    do_nothing,
    walk_dog,
    cook_breakfast,
    deliver_newspaper,
    visit_miss_kerbopple,
    wash_covers
}



I don't like this:

mixin(Flags("
enum ubyte Todo {
    do_nothing,
    walk_dog,
    cook_breakfast,
    deliver_newspaper,
    visit_miss_kerbopple,
    wash_covers
}
"));




Something like can worl, but it's not nice:

struct Todo {
    mixin(Fields!(ubyte, "do_nothing",
                         "walk_dog"
                         "cook_breakfast"
                         "deliver_newspaper"
                         "visit_miss_kerbopple"
                         "wash_covers");
}



Once the programmer can define attributes, it can be doable this syntax that adds the required methods to the enum, but I am not sure:

@fields enum ubyte Todo {
    do_nothing,
    walk_dog,
    cook_breakfast,
    deliver_newspaper,
    visit_miss_kerbopple,
    wash_covers
}

Bye,
bearophile
March 24, 2010
Another possible syntax that I don't like:

private enum ubyte enum_Todo {
    do_nothing,
    walk_dog,
    cook_breakfast,
    deliver_newspaper,
    visit_miss_kerbopple,
    wash_covers
}

alias Flags!(enum_Todo) Todo;

(Essentially the @flags attribute can do this, and avoid to define the enum).


This doesn't work, you can't pass locally defined anonymous enums to templates:

alias Flags!(enum ubyte { do_nothing,
                          walk_dog,
                          cook_breakfast,
                          deliver_newspaper,
                          visit_miss_kerbopple,
                          wash_covers
                        }) Todo;

Bye,
bearophile
March 24, 2010
Andrei Alexandrescu:

See my other answers, I add just a small comment:

>while still failing to address major problems (concurrency, immutability) feels not?<

I am not yet able to say something meaningful about the concurrency design, so I don't comment about it.

Flags are not so common, so I agree they are of secondary importance.

But integral numbers, floating point values, enums, etc are not minor things. They are more important than concurrency and immutability because you use them all the time in programs, and they must be as well designed as possible, they are the foundation where all other things are written over. The less solid they are the more unstable your higher level things like concurrency will be.

Bye,
bearophile
March 24, 2010
"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:hod5o3$1nhg$1@digitalmars.com...
> On 03/24/2010 08:28 AM, bearophile wrote:
>> As
>> they say: "Those who cannot learn from C# are doomed to re-invent it,
>> often badly."
>
> Who are "they"?
>

He was modifying the common expression "Those who don't learn from the past are doomed to repeat it."

>> (In D you can solve this problem creating a flags struct, using a strategy similar to the one used by std.bitmanip.bitfields, but it feels hackish).
>
> Why does a mechanism that allows creating bitfields, custom enums, flags, custom-base literals, and more, feel hackish,

Because it involves passing everything as parameters to a string-mixin-generating function/template. Powerful as such as thing is, and as much as I like having that ability available, it is a rather blunt instrument and does tend to feel very hackish.

Also, looking at the docs for bitmanip, it looks like "bitfields" creates a "BitArray". But the interface for bitarray doesn't really seem to match the conceptual-level operations performed on bitfields any more than just using an ordinary uint would, and it doesn't seem to solve most of the problems with doing so, either.

> whereas dumping a wheelbarrow of narrow-usefulness features with every release

Custom bitfields are extremely useful for low-level code. Being a self-proclaimed "systems" language, there's no reason D should consider such a thing to be of "narrow-usefulness".

> while still failing to address major problems (concurrency, immutability) feels not?
>

I don't think anyone's suggesting that things like concurrency and immutability should fail to be addressed.


March 24, 2010
On 03/24/2010 12:57 PM, Nick Sabalausky wrote:
> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org>  wrote in message
> news:hod5o3$1nhg$1@digitalmars.com...
>> On 03/24/2010 08:28 AM, bearophile wrote:
>>> As
>>> they say: "Those who cannot learn from C# are doomed to re-invent it,
>>> often badly."
>>
>> Who are "they"?
>>
>
> He was modifying the common expression "Those who don't learn from the past
> are doomed to repeat it."

But paraphrasing ain't "as they say" because they don't say that. Besides, I thought he's paraphrasing "Any sufficiently complicated C or Fortran program contains a buggy implementation of Common Lisp." But I guess that's just me being cranky - I'm sick.

>>> (In D you can solve this problem creating a flags struct, using a
>>> strategy similar to the one used by std.bitmanip.bitfields, but it
>>> feels hackish).
>>
>> Why does a mechanism that allows creating bitfields, custom enums, flags,
>> custom-base literals, and more, feel hackish,
>
> Because it involves passing everything as parameters to a
> string-mixin-generating function/template. Powerful as such as thing is, and
> as much as I like having that ability available, it is a rather blunt
> instrument and does tend to feel very hackish.

Feeling is subjective. To me it doesn't.

> Also, looking at the docs for bitmanip, it looks like "bitfields" creates a
> "BitArray". But the interface for bitarray doesn't really seem to match the
> conceptual-level operations performed on bitfields any more than just using
> an ordinary uint would, and it doesn't seem to solve most of the problems
> with doing so, either.

Nonsense. bitfields does not create a BitArray and does exactly what you'd expect some bit fields to do. To saliently criticize an artifact, it does help to understand it.

>> whereas dumping a wheelbarrow of narrow-usefulness features with every
>> release
>
> Custom bitfields are extremely useful for low-level code. Being a
> self-proclaimed "systems" language, there's no reason D should consider such
> a thing to be of "narrow-usefulness".

First, custom bitfields are taken care of appropriately by bitfield. You may want to try it before replying. Second, this thread is about enums that are bitwise flags, so I take it you replied to disagree with every paragraph I wrote.

>> while still failing to address major problems (concurrency, immutability)
>> feels not?
>>
>
> I don't think anyone's suggesting that things like concurrency and
> immutability should fail to be addressed.

Then stop extolling the virtues of an obscure feature.


Andrei
March 24, 2010
"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:hodla0$2sta$1@digitalmars.com...
> On 03/24/2010 12:57 PM, Nick Sabalausky wrote:
>> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org>  wrote in message news:hod5o3$1nhg$1@digitalmars.com...
>>>
>>>
>>> Who are "they"?
>>>
>> He was modifying the common expression "Those who don't learn from the
>> past
>> are doomed to repeat it."
>
> But paraphrasing ain't "as they say" because they don't say that. Besides, I thought he's paraphrasing "Any sufficiently complicated C or Fortran program contains a buggy implementation of Common Lisp." But I guess that's just me being cranky - I'm sick.
>

Ok, I'm not going to get baited into picking apart minute details of someone's exact choice of wording.


>>> Why does a mechanism that allows creating bitfields, custom enums,
>>> flags,
>>> custom-base literals, and more, feel hackish,
>>
>> Because it involves passing everything as parameters to a
>> string-mixin-generating function/template. Powerful as such as thing is,
>> and
>> as much as I like having that ability available, it is a rather blunt
>> instrument and does tend to feel very hackish.
>
> Feeling is subjective. To me it doesn't.
>

And so what, that proves it isn't hackish? Point is, there are people who do find it hackish, and saying "I don't" hardly addresses the issue.


>> Also, looking at the docs for bitmanip, it looks like "bitfields" creates
>> a
>> "BitArray". But the interface for bitarray doesn't really seem to match
>> the
>> conceptual-level operations performed on bitfields any more than just
>> using
>> an ordinary uint would, and it doesn't seem to solve most of the problems
>> with doing so, either.
>
> Nonsense. bitfields does not create a BitArray and does exactly what you'd expect some bit fields to do. To saliently criticize an artifact, it does help to understand it.
>
> First, custom bitfields are taken care of appropriately by bitfield. You may want to try it before replying. Second, this thread is about enums that are bitwise flags, so I take it you replied to disagree with every paragraph I wrote.
>

"it does help to understand it" <- Which is why I went and double-checked the docs. The docs didn't say anything about what "bitfields" actually created, but it did have a big definition of the "BitArray" type right there, and no other types were mentioned besides FloatRep and DoubleRep (which were clearly mere uses of "bitfields"), so I assumed. Clearly I assumed wrong, big fucking deal. That's no reason to get all pissy about it.


>>> while still failing to address major problems (concurrency,
>>> immutability)
>>> feels not?
>>>
>>
>> I don't think anyone's suggesting that things like concurrency and immutability should fail to be addressed.
>
> Then stop extolling the virtues of an obscure feature.
>

Wow, cranky indeed.



March 24, 2010
Nick Sabalausky Wrote:

> "yigal chripun" <yigal100@gmail.com> wrote in message news:hobg4b$12ej$1@digitalmars.com...
> >
> > This also interacts with the crude hack of "this enum is actually a
> > constant".
> > if you remove the implicit casts than how would you be able to do:
> > void foo(int p);
> > enum { bar = 4 }; // don't remember the exact syntax here
> > foo(bar); // compile-error?!
> >
> 
> AIUI, That style enum is already considered different by the compiler anyway. Specifically, it's doesn't create any new type, whereas the other type of enum creates a new semi-weak type. I don't think it would be too big of a step to go one step further and change "this kind of enum creates a new semi-weak type" to "this kind of enum creates a new strong type". But yea, I absolutely agree that calling a manifest constant an "enum" is absurd. It still bugs the hell out of me even today, but I've largely shut up about it since Walter hasn't wanted to change it even though he seems to be the only one who doesn't feel it's a bad idea (and it's not like it causes practical problems when actually using the language...although I'm sure it must be a big WTF for new and prospective D users).
> 
> 
> > I feel that enum needs to be re-designed. I think that C style "enums are numbers" are *bad*, *wrong* designs that expose internal implementation and the only valid design is that of Java 5.
> >
> > e.g.
> > enum Color {blue, green}
> > Color c = Color.blue;
> > c++; // WTF?  should NOT compile
> >
> > A C style enum with values assigned is *not* an enumeration but rather a set of meaningful integral values and should be represented as such.
> >
> > This was brought up many many times in the NG before and based on past occurences will most likely never change.
> 
> I would hate to see enums lose the concept of *having* a base type and base values because I do find that to be extremely useful (Haxe's enums don't have a base type and, from direct experience with them, I've found that to be a PITA too). But I feel very strongly that conversions both to and from the base type need to be explicit. In fact, that was one of the things that was bugging me about C/C++ even before I came across D. D improves the situation of course, but it's still only half-way.
> 
> 
> 

Regarding the base type notion, I re-phrased my inccurate saying above in a reply to my post. I don't agree that enums should have a base type, enums should be distinct storng types.
The numeric value should be a *property* of an enum member and not define its identity.
Which is how it works in Java 5 where each each member is a singelton class.

you should never do:
void foo(int);
foo(MyEnum.Bar); // this is bad design
instead do:
foo(MyEnum.Bar.value); // value is a regular property.

This is also more flexible, since you could do things like:
// assume I defined a Color enum
foo(Color.Red.ordinal);
bar(Color.Red.rgb);

where foo belongs to an API that defines a a list of colors (red is 5)and bar belongs to a different API that uses the rgb value (red is 0xff0000)

how would you do that with a C style enum?