www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Implicit enum conversions are a stupid PITA

reply "Nick Sabalausky" <a a.a> writes:
I'm bringing this over here from a couple separate threads over on "D.learn" 
(My "D1: Overloading across modules" and bearophile's "Enum equality test").

Background summary:

bearophile:
 I'm looking for D2 rough edges. I've found that this D2 code
 compiles and doesn't assert at runtime:

 enum Foo { V1 = 10 }
 void main() {
  assert(Foo.V1 == 10);
 }

 But I think enums and integers are not the same type,
 and I don't want to see D code that hard-codes comparisons
 between enum instances and number literals, so I think an
 equal between an enum and an int has to require a cast:

 assert(cast(int)(Foo.V1) == 10); // OK
He goes on to mention C++0x's "enum class" that, smartly, gets rid of that implicit conversion nonsense. To put it simply, I agree with this even on mere principle. I'm convinced that the current D behavior is a blatant violation of strong-typing and smacks way too much of C's so-called "type system". But here's another reason to get rid it that I, quite coincidentally, stumbled upon right about the same time: Me:
 In D1, is there any reason I should be getting an error on this?:

 // module A:
 enum FooA { fooA };
 void bar(FooA x) {}

 // module B:
 import A;
 enum FooB { fooB };
 void bar(FooB x) {}

 bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
In the resulting discussion (which included a really hackish workaround), it was said that this is because of a rule (that I assume exists in D2 as well) that basically goes "two functions from different modules are in conflict if they have the same name." I assume (and very much hope) that the rule also has a qualification "...but only if implicit conversion rules make it possible for one to hijack the other". It was said that this is to prevent a function call from getting hijacked by merely importing a module (or making a change in an imported module). That I can completely agree with. But I couldn't understand why this would cause conflicts involving enums until I thought about implicit enum-to-base-type conversion and came up with this scenario: // Module Foo: enum Foo { foo } // module A: import Foo; void bar(Foo x){} // module B version 1: import Foo; // Note: A is not imported yet void bar(int x){} bar(Foo.foo); // Stupid crap that should never be allowed in the first place // module B version 2: import Foo; import A; // <- This line added void bar(int x){} bar(Foo.foo); // Now that conflict error *cough* "helps". So thanks to the useless and dangerous ability to implicitly convert an enum to its base type, we can't have certain perfectly sensible cross-module overloads. Although, frankly, I *still* don't see why "bar(SomeEnum)" and "bar(SomeOtherEnum)" should ever be in conflict (unless that's only D1, or if implicit base-type-to-enum conversions are allowed (which would make things even worse)).
Mar 23 2010
next sibling parent Marianne Gagnon <auria.mg gmail.com> writes:
Nick Sabalausky Wrote:

 I'm bringing this over here from a couple separate threads over on "D.learn" 
 (My "D1: Overloading across modules" and bearophile's "Enum equality test").
 
 Background summary:
 
 bearophile:
 I'm looking for D2 rough edges. I've found that this D2 code
 compiles and doesn't assert at runtime:

 enum Foo { V1 = 10 }
 void main() {
  assert(Foo.V1 == 10);
 }

 But I think enums and integers are not the same type,
 and I don't want to see D code that hard-codes comparisons
 between enum instances and number literals, so I think an
 equal between an enum and an int has to require a cast:

 assert(cast(int)(Foo.V1) == 10); // OK
He goes on to mention C++0x's "enum class" that, smartly, gets rid of that implicit conversion nonsense. To put it simply, I agree with this even on mere principle. I'm convinced that the current D behavior is a blatant violation of strong-typing and smacks way too much of C's so-called "type system". But here's another reason to get rid it that I, quite coincidentally, stumbled upon right about the same time: Me:
 In D1, is there any reason I should be getting an error on this?:

 // module A:
 enum FooA { fooA };
 void bar(FooA x) {}

 // module B:
 import A;
 enum FooB { fooB };
 void bar(FooB x) {}

 bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
In the resulting discussion (which included a really hackish workaround), it was said that this is because of a rule (that I assume exists in D2 as well) that basically goes "two functions from different modules are in conflict if they have the same name." I assume (and very much hope) that the rule also has a qualification "...but only if implicit conversion rules make it possible for one to hijack the other". It was said that this is to prevent a function call from getting hijacked by merely importing a module (or making a change in an imported module). That I can completely agree with. But I couldn't understand why this would cause conflicts involving enums until I thought about implicit enum-to-base-type conversion and came up with this scenario: // Module Foo: enum Foo { foo } // module A: import Foo; void bar(Foo x){} // module B version 1: import Foo; // Note: A is not imported yet void bar(int x){} bar(Foo.foo); // Stupid crap that should never be allowed in the first place // module B version 2: import Foo; import A; // <- This line added void bar(int x){} bar(Foo.foo); // Now that conflict error *cough* "helps". So thanks to the useless and dangerous ability to implicitly convert an enum to its base type, we can't have certain perfectly sensible cross-module overloads. Although, frankly, I *still* don't see why "bar(SomeEnum)" and "bar(SomeOtherEnum)" should ever be in conflict (unless that's only D1, or if implicit base-type-to-enum conversions are allowed (which would make things even worse)).
Hum... +1 What can I add, you said it all ;)
Mar 23 2010
prev sibling next sibling parent reply yigal chripun <yigal100 gmail.com> writes:
Nick Sabalausky Wrote:

 I'm bringing this over here from a couple separate threads over on "D.learn" 
 (My "D1: Overloading across modules" and bearophile's "Enum equality test").
 
 Background summary:
 
 bearophile:
 I'm looking for D2 rough edges. I've found that this D2 code
 compiles and doesn't assert at runtime:

 enum Foo { V1 = 10 }
 void main() {
  assert(Foo.V1 == 10);
 }

 But I think enums and integers are not the same type,
 and I don't want to see D code that hard-codes comparisons
 between enum instances and number literals, so I think an
 equal between an enum and an int has to require a cast:

 assert(cast(int)(Foo.V1) == 10); // OK
He goes on to mention C++0x's "enum class" that, smartly, gets rid of that implicit conversion nonsense. To put it simply, I agree with this even on mere principle. I'm convinced that the current D behavior is a blatant violation of strong-typing and smacks way too much of C's so-called "type system". But here's another reason to get rid it that I, quite coincidentally, stumbled upon right about the same time: Me:
 In D1, is there any reason I should be getting an error on this?:

 // module A:
 enum FooA { fooA };
 void bar(FooA x) {}

 // module B:
 import A;
 enum FooB { fooB };
 void bar(FooB x) {}

 bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
In the resulting discussion (which included a really hackish workaround), it was said that this is because of a rule (that I assume exists in D2 as well) that basically goes "two functions from different modules are in conflict if they have the same name." I assume (and very much hope) that the rule also has a qualification "...but only if implicit conversion rules make it possible for one to hijack the other". It was said that this is to prevent a function call from getting hijacked by merely importing a module (or making a change in an imported module). That I can completely agree with. But I couldn't understand why this would cause conflicts involving enums until I thought about implicit enum-to-base-type conversion and came up with this scenario: // Module Foo: enum Foo { foo } // module A: import Foo; void bar(Foo x){} // module B version 1: import Foo; // Note: A is not imported yet void bar(int x){} bar(Foo.foo); // Stupid crap that should never be allowed in the first place // module B version 2: import Foo; import A; // <- This line added void bar(int x){} bar(Foo.foo); // Now that conflict error *cough* "helps". So thanks to the useless and dangerous ability to implicitly convert an enum to its base type, we can't have certain perfectly sensible cross-module overloads. Although, frankly, I *still* don't see why "bar(SomeEnum)" and "bar(SomeOtherEnum)" should ever be in conflict (unless that's only D1, or if implicit base-type-to-enum conversions are allowed (which would make things even worse)).
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?! 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.
Mar 23 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
yigal chripun:
 This was brought up many many times in the NG before and based on past
occurences will most likely never change.
If I see some semantic holes I'd like to see them filled/fixed, when possible. Keeping the muzzle doesn't improve the situation :-) Bye, bearophile
Mar 23 2010
parent yigal chripun <yigal100 gmail.com> writes:
bearophile Wrote:

 yigal chripun:
 This was brought up many many times in the NG before and based on past
occurences will most likely never change.
If I see some semantic holes I'd like to see them filled/fixed, when possible. Keeping the muzzle doesn't improve the situation :-) Bye, bearophile
I agree with you about the gaping semantic hole. All I'm saying is that after bringing this so many times to discussion before I lost hope that this design choice will ever be re-considered.
Mar 23 2010
prev sibling next sibling parent yigal chripun <yigal100 gmail.com> writes:
yigal chripun Wrote:

 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.
 
The above isn't accurate. I'll re-phrase: The values assigned to the members of the enums are just properties of the members, they do not define their identity. void bar(int); bar(Color.Red.rgb); // no-problem bar(Color.Red); // compile-error
Mar 23 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"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.
Mar 23 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 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).
Recently D2 has introduced the name "inout", that doesn't seem very linked to its semantic purpose. I think "auto_const", "auto const" or "autoconst" are better. The recently introduced "auto ref" is clear, but I think "auto_ref" or "autoref"are better still. Bye, bearophile
Mar 23 2010
prev sibling parent reply yigal chripun <yigal100 gmail.com> writes:
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?
Mar 24 2010
parent "Nick Sabalausky" <a a.a> writes:
"yigal chripun" <yigal100 gmail.com> wrote in message 
news:hodruh$aif$1 digitalmars.com...
 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?
I see what you mean. Personally I don't care if it's handled as a property or as an underlying type that can only be obtained via an explicit cast, as long as you never get the "associated" value implicitly.
Mar 24 2010
prev sibling next sibling parent reply Regan Heath <regan netmail.co.nz> writes:
Nick Sabalausky wrote:
 So thanks to the useless and dangerous ability to implicitly convert an enum 
 to its base type, we can't have certain perfectly sensible cross-module 
 overloads.
One thing being able to convert enum to it's base type does allow is this: import std.stdio; enum FLAG { READ = 0x1, WRITE = 0x2, OTHER = 0x4 } void foo(FLAG flags) { writeln("Flags = ", flags); } int main(string[] args) { foo(FLAG.READ); foo(FLAG.READ|FLAG.WRITE); return 0; } I find being able to define bit flag values with an enum and combine them using | and |= or negate with &= ~flag etc very useful. Languages without the implicit conversion typically give an error when using |, |= etc forcing you to cast, eg. foo((int)FLAG.READ|(int)FLAG.WRITE); which, in addition, breaks type safety as you're casting to 'int'. Alternately they require you to define |, |= etc for the 'strong' enum type which is a PITA, IMO. Granted, that's probably the most 'correct' way for a strongly typed language to do things, but it just feels un-necessary for someone who is used to the convenience of the implicit conversion. All that said, I also find method/function collision very annoying. True, it is easily solvable with alias, but that's always felt a bit hackish and messy to me. So, imagining we have a strongly typed 'enum' with no implicit conversion. Can we get back the convenience of being able to call numeric operators on them without casts or all the legwork involved? Could the compiler not automatically generate them? The downside is that this would result in multiple copies of what was essentially the same function for int and every enum type. We could make the programmer ask for it with a special base type, eg. enum FLAG : numeric {} but, ideally we want existing code to continue to work. I wonder if the compiler could safely do the (cast) for us without loosing type safety? i.e. case the enum to int, call the int operator, and cast the result back. The result would be that this works: foo(FLAG.READ|FLAG.WRITE); but this would error: foo(FLAG.READ|FLAG.WRITE|5); and enum would appear to be a strong type, and would no longer collide on function resolution but we'd have the convenience of numeric operators - a common usage pattern for enums. Are there other usage patterns this would break? R
Mar 24 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
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 thing, you can use the [Flags] attribute: http://www.codeguru.com/vb/sample_chapter/article.php/c12963 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 (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). Bye, bearophile
Mar 24 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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 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 starting to find in D (or often that we just refuse to see in D).
pluses and minuses, but is definitely not the be-all, end-all of PLs. In
 As

 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
Mar 24 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
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
Mar 24 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:hod5o3$1nhg$1 digitalmars.com...
 On 03/24/2010 08:28 AM, bearophile wrote:
 As

 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.
Mar 24 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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

 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
Mar 24 2010
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"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.
Mar 24 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/24/2010 02:34 PM, Nick Sabalausky wrote:
 "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.
Apology accepted :oD. Andrei
Mar 24 2010
prev sibling parent Bernard Helyer <b.helyer gmail.com> writes:
On 25/03/10 07:22, Andrei Alexandrescu wrote:
 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

 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.
"those who do not understand unix are doomed to reinvent it, poorly."
Mar 24 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 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".
I've written a lot of low-level code, I even programmed Mattel Intellivision cartridges and one of those old 70's hand-held LED games (Mattel Soccer). I've done a lot of embedded 6800 microprocessor work, device drivers, graphics drivers, etc. I've done a lot of bit twiddling code. But I find C bit fields to be generally worthless. One reason is the standard requires them to be right justified after extraction. This kills performance. I muck with with them in-place using biased arithmetic.
Mar 24 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hoepts$2a98$1 digitalmars.com...
 Nick Sabalausky wrote:
 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".
I've written a lot of low-level code, I even programmed Mattel Intellivision cartridges and one of those old 70's hand-held LED games (Mattel Soccer). I've done a lot of embedded 6800 microprocessor work, device drivers, graphics drivers, etc. I've done a lot of bit twiddling code. But I find C bit fields to be generally worthless. One reason is the standard requires them to be right justified after extraction. This kills performance. I muck with with them in-place using biased arithmetic.
Actually, with "bitfields", I've been mostly referring to pretty much just that: doing manual bit-twiddling, typically aided by manifest constants and/or enums, and taking the stance that doing that could use a better (ie, more abstracted and more type-safe) interface (while still keeping the same under-the-hood behavior). Maybe it's all the low-level stuff I've done, but any time I come across the term "bitfield" I instinctively envision those abstract rows of labeled "bit" squares (or differently-sized rectangles) that you see in spec sheets for digital hardware (ie, the abstract concept of a small piece of memory having bit-aligned data), rather than specifically the structs-with-sub-byte-member-alignment that I keep forgetting C has. I can't really comment on that latter kind as I've never really used them (can't remember why not), although I can easily believe that they may be insufficient for the job. Maybe that difference is where the disagreement between me and Andrei arose.
Mar 25 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 Actually, with "bitfields", I've been mostly referring to pretty much just 
 that: doing manual bit-twiddling, typically aided by manifest constants 
 and/or enums, and taking the stance that doing that could use a better (ie, 
 more abstracted and more type-safe) interface (while still keeping the same 
 under-the-hood behavior).
 
 Maybe it's all the low-level stuff I've done, but any time I come across the 
 term "bitfield" I instinctively envision those abstract rows of labeled 
 "bit" squares (or differently-sized rectangles) that you see in spec sheets 
 for digital hardware (ie, the abstract concept of a small piece of memory 
 having bit-aligned data), rather than specifically the 
 structs-with-sub-byte-member-alignment that I keep forgetting C has. I can't 
 really comment on that latter kind as I've never really used them (can't 
 remember why not), although I can easily believe that they may be 
 insufficient for the job. Maybe that difference is where the disagreement 
 between me and Andrei arose.
It does seem we've totally misunderstood each other. Yes, I was referring to (and I'm sure Andrei was as well) the C bitfield language feature.
Mar 25 2010
prev sibling parent reply Regan Heath <regan netmail.co.nz> writes:
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 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 starting to find in D (or often that we just refuse to see in D). As often badly."
"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
Mar 24 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
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:

of this, you can see it from the very low number of features they have added to
Who are "they"?<
Almost everyone that posts on this newsgroup :-) I put myself in the group too, 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 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 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 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
Mar 24 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
Mar 24 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
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
Mar 24 2010
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
bearophile wrote:

 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).
 
I like this idea of implementing a flag type and tried to work something out. Instead of implementing the overloads, it is also possible to generate an enum via CTFE inside a struct and forward with alias this, what do you think? I have tried this syntax, seems to work ok: alias Flags!q{ do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, wash_covers } Todo; It does allow this though, but perhaps that can fixed: Todo todo = Todo.walk_dog; todo |= 4; With such a type, it is easy to add some small convenience features, such as an enumToString, define property .max and implement a range that iterates over all flags set or possible values.
Mar 28 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Lutger:
 alias Flags!q{ do_nothing, 
                walk_dog, 
                cook_breakfast,
                deliver_newspaper,
                visit_miss_kerbopple,
                wash_covers } Todo;
That's better. But you have missed the optional type :-) Bye, bearophile
Mar 28 2010
parent reply Lutger <lutger.blijdestijn gmail.com> writes:
bearophile wrote:

 Lutger:
 alias Flags!q{ do_nothing,
                walk_dog,
                cook_breakfast,
                deliver_newspaper,
                visit_miss_kerbopple,
                wash_covers } Todo;
That's better. But you have missed the optional type :-) Bye, bearophile
Thanks. I omitted the type because I was lazy. :) Assuming uint it is possible to just use std.intrinsic for bit twiddling in the range, since I'm not so good with that. I can brush it up and post the code later if you want, but it's not so pretty.
Mar 28 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Lutger:
I can brush it up and post the code later if you want, but it's not so pretty.<
This syntax is not pretty, but I think it can be acceptable: alias Flags!q{ do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, wash_covers } Todo; With optional type too: alias Flags!q{ int : do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, wash_covers } Todo; Now it's a matter of writing a good amount of CTFE to implement the little parser, to create the methods and attributes, to perform the necessary sanity tests in all inputs, to write documentation, tests, etc :o) I don't need flags often in my code so don't implement it for me. If you have some free time you can write it for other people here. Once the code is good probably Andrei will accept to put it in Phobos2. Bye, bearophile
Mar 28 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/28/2010 03:44 AM, Lutger wrote:
 bearophile wrote:

 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).
I like this idea of implementing a flag type and tried to work something out. Instead of implementing the overloads, it is also possible to generate an enum via CTFE inside a struct and forward with alias this, what do you think? I have tried this syntax, seems to work ok: alias Flags!q{ do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, wash_covers } Todo; It does allow this though, but perhaps that can fixed: Todo todo = Todo.walk_dog; todo |= 4; With such a type, it is easy to add some small convenience features, such as an enumToString, define property .max and implement a range that iterates over all flags set or possible values.
I think it will take some time to settle the competition between "template parses everything" approach and "language parses most" approach. For what it's worth, Walter and I were talking three years ago about a "new alias" feature: template Flags(new alias Names...) { ... } "new alias" means that you may pass to Flags symbols that haven't been defined. With that feature in place, Flags could be used like this: alias Flags!(do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, wash_covers) Todo; No muss, no fuss, no need to stringize anything. Flags could get to the names of the alias parameters by using Names[i].stringof. Well that's not in the language yet :o). Andrei
Mar 28 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 For what it's worth, Walter and I were talking three years ago about a 
 "new alias" feature:
 
 template Flags(new alias Names...) { ... }
 
 "new alias" means that you may pass to Flags symbols that haven't been 
 defined. With that feature in place, Flags could be used like this:
 
   alias Flags!(do_nothing,
                walk_dog,
                cook_breakfast,
                deliver_newspaper,
                visit_miss_kerbopple,
                wash_covers)
       Todo;
 
 No muss, no fuss, no need to stringize anything.
Maybe it's better to go all the way and just add symbols to the language, as in Ruby, Lisps, etc. I don't know. The #walk_dog syntax is not available to represent a symbol "walk_dog", I presume... Bye, bearophile
Mar 28 2010
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Andrei Alexandrescu wrote:

 On 03/28/2010 03:44 AM, Lutger wrote:
(...)
 I like this idea of implementing a flag type and tried to work something
 out. Instead of implementing the overloads, it is also possible to
 generate an enum via CTFE inside a struct and forward with alias this,
 what do you think? I have tried this syntax, seems to work ok:

 alias Flags!q{ do_nothing,
                 walk_dog,
                 cook_breakfast,
                 deliver_newspaper,
                 visit_miss_kerbopple,
                 wash_covers } Todo;

 It does allow this though, but perhaps that can fixed:

 Todo todo = Todo.walk_dog;
 todo |= 4;

 With such a type, it is easy to add some small convenience features, such
 as
 an  enumToString, define property .max and implement a range that iterates
 over all flags set or possible values.
I think it will take some time to settle the competition between "template parses everything" approach and "language parses most" approach. For what it's worth, Walter and I were talking three years ago about a "new alias" feature: template Flags(new alias Names...) { ... } "new alias" means that you may pass to Flags symbols that haven't been defined. With that feature in place, Flags could be used like this: alias Flags!(do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, wash_covers) Todo; No muss, no fuss, no need to stringize anything. Flags could get to the names of the alias parameters by using Names[i].stringof. Well that's not in the language yet :o). Andrei
That would be nice, perhaps it's possible for a backwards-compatible 2.x release to work something out. As bearophile said Ruby has some nice things for metaprogramming that help with this, borrowed from lisp of course. I do think Ruby's strong metaprogramming helped RoR become popular. In the meantime I tried to hack Flags together and got stuck on this thing: auto myTodoList = Todo.do_nothing; Now myTodoList is of type uint (or whatever), not so nice - it's inconsistent with regular named enums. It messed up making a range for iterating over the flags set, which I thought was a nice addition. Anyway, here is my attempt so far, please forgive me it is not so elegant: import std.conv; string genFlags(string names, string type = "uint") { string result = "enum : " ~ type ~ " { "; int bits = 1; size_t pos; // skip leading whitespace while( ++pos < names.length && names[pos] == ' ') { } size_t prev = pos; bool hasInitializer = false; while ( pos < names.length) { if (names[pos] == '=') hasInitializer = true; else if (names[pos] == ',') { result ~= names[prev..pos]; if (!hasInitializer) { result ~= " = " ~ std.conv.to!string(bits); bits <<= 1; } else hasInitializer = false; result ~= ','; //skip whitespace while( ++pos < names.length && names[pos] == ' ') { } prev = pos; } pos++; } // concat the last flag if (hasInitializer) return result ~ names[prev..pos] ~ "}"; return result ~ names[prev..pos] ~ " = " ~ std.conv.to!string(bits) ~ "}"; } struct Flags(string members, T = uint) { static assert( is(T : ulong), "Wrong underlying type of Flags: must be integral not " ~ T.stringof ); mixin( genFlags(members) ); alias typeof(this) FlagsType; T value; alias value this; this(T value) { this.value = value; } void opAssign(T value) { this.value = value; } pure bool opBinaryRight(string op, E)(E lhs) const if ( op == "in" ) { return cast(bool)(lhs & this); } } unittest { alias Flags!q{ do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, morning_task = walk_dog | cook_breakfast, wash_covers } Todo; Todo list1 = Todo.do_nothing; assert( list1 == 1 ); list1 |= Todo.wash_covers | Todo.walk_dog; assert(list1 == Todo.do_nothing | Todo.wash_covers | Todo.walk_dog); assert(Todo.do_nothing in list1); Todo list2 = Todo.cook_breakfast | Todo.wash_covers; assert( list1 & list2 == Todo.do_nothing | Todo.cook_breakfast); list1 = list2; assert(list1 == Todo.do_nothing | Todo.wash_covers | Todo.walk_dog); assert( Todo.morning_task == Todo.walk_dog | Todo.cook_breakfast ); auto list3 = Todo.deliver_newspaper; assert(Todo.deliver_newspaper in list3, "can't infer type properly"); /* bug */ }
Mar 29 2010
next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Lutger wrote:

...

 struct Flags(string members, T = uint)
 {
     static assert( is(T : ulong), "Wrong underlying type of Flags: must be
 integral not " ~ T.stringof );
 
     mixin( genFlags(members) );
I screwed up of course, this must be: mixin( genFlags(members, T.stringof) );
     alias typeof(this) FlagsType;
 
     T value;
     alias value this;
 
     this(T value)
     {
         this.value = value;
     }
 
     void opAssign(T value)
     {
         this.value = value;
     }
 
     pure bool opBinaryRight(string op, E)(E lhs)  const
         if ( op == "in" )
     {
         return cast(bool)(lhs & this);
     }
 }
...
Mar 29 2010
prev sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Lutger wrote:

...
 
 unittest
 {
     alias Flags!q{ do_nothing, walk_dog, cook_breakfast, deliver_newspaper,
         visit_miss_kerbopple, morning_task = walk_dog | cook_breakfast,
         wash_covers } Todo;
 
     Todo list1 = Todo.do_nothing;
     assert( list1 == 1 );
     list1 |= Todo.wash_covers | Todo.walk_dog;
     assert(list1 == Todo.do_nothing | Todo.wash_covers | Todo.walk_dog);
     assert(Todo.do_nothing in list1);
 
     Todo list2 = Todo.cook_breakfast | Todo.wash_covers;
     assert( list1 & list2 == Todo.do_nothing | Todo.cook_breakfast);
     list1 = list2;
     assert(list1 == Todo.do_nothing | Todo.wash_covers | Todo.walk_dog);
 
     assert( Todo.morning_task == Todo.walk_dog | Todo.cook_breakfast );
 
     auto list3 = Todo.deliver_newspaper;
     assert(Todo.deliver_newspaper in list3, "can't infer type properly");
     /*
 bug */
 }
^ oops, this one is totally messed up and needs to go to precedence school. This should be better: unittest { alias Flags!q{ do_nothing, walk_dog, cook_breakfast, deliver_newspaper, visit_miss_kerbopple, morning_task = walk_dog | cook_breakfast, wash_covers } Todo; Todo list1 = Todo.do_nothing; assert( list1 == 1 ); list1 |= Todo.wash_covers | Todo.walk_dog; assert(list1 == (Todo.do_nothing | Todo.wash_covers | Todo.walk_dog) ); assert(Todo.do_nothing in list1); Todo list2 = Todo.cook_breakfast | Todo.wash_covers; assert( (list1 & list2) == Todo.wash_covers ); list1 = list2; assert(list1 == (Todo.cook_breakfast | Todo.wash_covers) ); assert( Todo.morning_task == (Todo.walk_dog | Todo.cook_breakfast) ); auto list3 = Todo.deliver_newspaper; /* bug */ assert(Todo.deliver_newspaper in list3, "can't infer type properly"); }
Mar 29 2010
prev sibling next sibling parent reply yigal chripun <yigal100 gmail.com> writes:
Regan Heath Wrote:

 
 One thing being able to convert enum to it's base type does allow is this:
 
 import std.stdio;
 
 enum FLAG
 {
    READ  = 0x1,
    WRITE = 0x2,
    OTHER = 0x4
 }
 
 void foo(FLAG flags)
 {
    writeln("Flags = ", flags);
 }
 
 int main(string[] args)
 {
    foo(FLAG.READ);
    foo(FLAG.READ|FLAG.WRITE);
    return 0;
 }
 
 
<snip> Here's a Java 5 version with D-like syntax: enum Flag { READ (0x1), WRITE (0x2), OTHER(0x4) const int value; private this (int value) { this.value = value; } } int main(string[] args) { foo(FLAG.READ.value); foo(FLAG.READ.value | FLAG.WRITE.value); return 0; } No conversions required.
Mar 24 2010
parent reply Regan Heath <regan netmail.co.nz> writes:
yigal chripun wrote:
 Here's a Java 5 version with D-like syntax: 
 
 enum Flag {
     READ  (0x1), WRITE (0x2), OTHER(0x4)
     
     const int value;
     private this (int value) {
         this.value = value;
      }
 }
 
  int main(string[] args) {
     foo(FLAG.READ.value);
     foo(FLAG.READ.value | FLAG.WRITE.value);
     return 0;
 }
 
 No conversions required. 
Cool. I wasn't aware of that Java feature/syntax - shows how much Java I do :p But.. what is the definition of 'foo' in the above, specifically does it take an argument of type Flag? or int? If the latter, then all you're doing is shifting the conversion. In my example it was a cast, in the above it's a property called 'value' which converts the "enum" to 'int'. Interestingly you can do something similar in D... import std.stdio; struct Enum { this(int v) { value = v; } int value; } struct Flag { Enum READ = Enum(1); Enum WRITE = Enum(2); Enum OTHER = Enum(4); } static Flag FLAG; void foo(int flag) { writefln("flag = %d", flag); } void main() { foo(FLAG.READ.value); foo(FLAG.READ.value|FLAG.WRITE.value); } What I really want is something more like... import std.stdio; import std.string; struct Enum { int value; this(int v) { value = v; } Enum opBinary(string s:"|")(Enum rhs) { return Enum(value|rhs.value); } const string toString() { return format("%d", value); } } struct Flag { Enum READ = Enum(1); Enum WRITE = Enum(2); Enum OTHER = Enum(4); } static Flag FLAG; void foo(Enum e) { writefln("e = %d", e); } void main() { foo(FLAG.READ); foo(FLAG.READ|FLAG.WRITE); } This is only a partial implementation, to complete it I would have to manually define all the numeric and logical operators in my Enum struct. What I want is for D to do all this with some syntactical sugar, eg. enum FLAG : numeric { READ = 1, WRITE = 2, OTHER = 4 } R
Mar 25 2010
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Regan Heath Wrote:

 yigal chripun wrote:
 Here's a Java 5 version with D-like syntax: 
 
 enum Flag {
     READ  (0x1), WRITE (0x2), OTHER(0x4)
     
     const int value;
     private this (int value) {
         this.value = value;
      }
 }
 
  int main(string[] args) {
     foo(FLAG.READ.value);
     foo(FLAG.READ.value | FLAG.WRITE.value);
     return 0;
 }
 
 No conversions required. 
Cool. I wasn't aware of that Java feature/syntax - shows how much Java I do :p But.. what is the definition of 'foo' in the above, specifically does it take an argument of type Flag? or int?
foo's signature in this case would be something like: void foo(int);
 If the latter, then all you're doing is shifting the conversion.  In my 
 example it was a cast, in the above it's a property called 'value' which 
 converts the "enum" to 'int'.
 
It might do something very similar but it is not the same semantically. by casting the enum member to an int you say something about its identity vs. a value property is just a property. For example, I can define a Color Enum that has two properties, an ordinal value and a hex RGB value.
 Interestingly you can do something similar in D...
 
 import std.stdio;
 
 struct Enum { this(int v) { value = v; } int value; }
 
 struct Flag
 {
    Enum READ  = Enum(1);
    Enum WRITE = Enum(2);
    Enum OTHER = Enum(4);
 }
 
 static Flag FLAG;
 
 void foo(int flag)
 {
    writefln("flag = %d", flag);
 }
 
 void main()
 {
    foo(FLAG.READ.value);
    foo(FLAG.READ.value|FLAG.WRITE.value);
 }
 
 What I really want is something more like...
 
 import std.stdio;
 import std.string;
 
 struct Enum
 {
    int value;
 
    this(int v)
    {
      value = v;
    }
 
    Enum opBinary(string s:"|")(Enum rhs)
    {
      return Enum(value|rhs.value);
    }
 
    const string toString()
    {
      return format("%d", value);
    }
 }
 
 struct Flag
 {
    Enum READ  = Enum(1);
    Enum WRITE = Enum(2);
    Enum OTHER = Enum(4);
 }
 
 static Flag FLAG;
 
 void foo(Enum e)
 {
    writefln("e = %d", e);
 }
 
 void main()
 {
    foo(FLAG.READ);
    foo(FLAG.READ|FLAG.WRITE);
 }
 
 This is only a partial implementation, to complete it I would have to 
 manually define all the numeric and logical operators in my Enum struct.
 
 What I want is for D to do all this with some syntactical sugar, eg.
 
 enum FLAG : numeric
 {
    READ = 1, WRITE = 2, OTHER = 4
 }
 
 R
That's not how it's implemented. the enum members are actually singleton instances of anonymous inner-classes. each member can have it's own methods as well as methods defined for the enum type itself. I can have: enum SolarSystem { Earth(mass, distance_from_sun), ...} SolarSystem.Earth.rotate(); etc... You could implement this in D with structs/classes but it'll take a lot of code. Java does this for you.
Mar 25 2010
next sibling parent Regan Heath <regan netmail.co.nz> writes:
Yigal Chripun wrote:
 You could implement this in D with structs/classes but it'll take a lot of
code. Java does this for you.
My point exactly. R
Mar 25 2010
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Yigal Chripun wrote:
 You could implement this in D with structs/classes but it'll take a lot of
 code. Java does this for you.
That's what templates are for!
Mar 25 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 Nick Sabalausky:
 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.
Nick was right. Sorry for upsetting you, I am sorry. Hugs, bearophile
Mar 24 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/24/2010 07:34 PM, bearophile wrote:
 Andrei:

 Nick Sabalausky:
 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.
Nick was right. Sorry for upsetting you, I am sorry.
I missed this. There's no need for anything close to that. We all could get "upset" regarding a post or a notion, not against the person airing it. As far as the matter at hand of that thread is concerned, you mentioned the possibility: alias Flags!(ubyte, "do_nothing", "walk_dog" "cook_breakfast" "deliver_newspaper" "visit_miss_kerbopple" "wash_covers") Todo; I encourage you to code that up and see how it swims. We need to stop inventing syntax for any single thing that seems useful, and start eating our dogfood. If our mechanism for code generation is not good enough, we should improve it, not generate by hand ever new constructs. That reminds me of my late night conversation with Walter of yesterday. I'm sure he wouldn't mind me posting it. Summarized, it's as follows: A: I'm revising the copyedited manuscript for TDPL. This is the last chance to remove octal literals!!! W: I know everybody hates them, but I like them. A: Use octal!"177" W: Ugh. A (esprit d'escalier): If you don't like the universal notation you invented, who will? Since there's always something useful coming up, we need to figure out how our code generation abilities step up to the plate. I will add octal to Phobos, and if it is problematic then probably we need to adjust template syntax. My opinion in the matter is that there may be at most a handful of octal constants total in anyone's codebase, so having a cleverer syntax for them ain't going to make any difference. Andrei
Mar 25 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

I encourage you to code that up and see how it swims.<
The idea of using that syntax gives me nausea, I can't use that even if I implement that myself.
We need to stop inventing syntax for any single thing that seems useful, and
start eating our dogfood. If our mechanism for code generation is not good
enough, we should improve it, not generate by hand ever new constructs.<
to define something like that fields. This is an example of a general tool proposing to add this to D2, but user-defined attributes can be OK in D3. They can be a partial alternative to macros too).
and if it is problematic then probably we need to adjust template syntax.<
What kind of changes are you thinking of? Regarding octals (and multi-precision integer literals, and unit system suffixes), it seems C++0x has user-defined literals :-) http://en.wikipedia.org/wiki/C++0x#User-defined_literals (I am not asking to solve the D octal problem with them.) Bye, bearophile
Mar 25 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 01:33 PM, bearophile wrote:
 Andrei Alexandrescu:

 I encourage you to code that up and see how it swims.<
The idea of using that syntax gives me nausea, I can't use that even if I implement that myself.
I believe you're exaggerating.
 We need to stop inventing syntax for any single thing that seems
 useful, and start eating our dogfood. If our mechanism for code
 generation is not good enough, we should improve it, not generate
 by hand ever new constructs.<
baseline to compare the D implementation with.
 This is an
 example of a general tool that can be used to meta-program, keeping

 user-defined attributes can be OK in D3. They can be a partial
 alternative to macros too).
Why and how do you believe that whatever mechanism we come up with (possibly following a proposal authored by you) will be a net improvement over mixins?
 and if it is problematic then probably we need to adjust template
 syntax.<
What kind of changes are you thinking of?
Whatever doesn't give you nausea.
 Regarding octals (and multi-precision integer literals, and unit
 system suffixes), it seems C++0x has user-defined literals :-)
 http://en.wikipedia.org/wiki/C++0x#User-defined_literals (I am not
 asking to solve the D octal problem with them.)
auto someVariable = "1234"_Octal; Doesn't look like a day and night to me compared to auto someVariable = octal!"1234"; Are you sure you are saying what you mean to say? Andrei
Mar 25 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:hogc1o$2pm8$1 digitalmars.com...
 On 03/25/2010 01:33 PM, bearophile wrote:
 Andrei Alexandrescu:

 I encourage you to code that up and see how it swims.<
The idea of using that syntax gives me nausea, I can't use that even if I implement that myself.
I believe you're exaggerating.
Of course he is. But using mixins to "solve" every need that comes up is a bit like saying "LISP does everything!" even though LISP gets that flexibity by imposing a butt-ugly syntax ("Lost In Stupid Parenthesis", anyone?) on pretty much everything.
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 02:28 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:hogc1o$2pm8$1 digitalmars.com...
 On 03/25/2010 01:33 PM, bearophile wrote:
 Andrei Alexandrescu:

 I encourage you to code that up and see how it swims.<
The idea of using that syntax gives me nausea, I can't use that even if I implement that myself.
I believe you're exaggerating.
Of course he is. But using mixins to "solve" every need that comes up is a bit like saying "LISP does everything!" even though LISP gets that flexibity by imposing a butt-ugly syntax ("Lost In Stupid Parenthesis", anyone?) on pretty much everything.
I'm not saying to use mixins to solve every need that comes up. I'm saying it's worth trying them to solve a few obscure needs. Andrei
Mar 25 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:hogdpf$2te7$1 digitalmars.com...
 On 03/25/2010 02:28 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:hogc1o$2pm8$1 digitalmars.com...
 On 03/25/2010 01:33 PM, bearophile wrote:
 Andrei Alexandrescu:

 I encourage you to code that up and see how it swims.<
The idea of using that syntax gives me nausea, I can't use that even if I implement that myself.
I believe you're exaggerating.
Of course he is. But using mixins to "solve" every need that comes up is a bit like saying "LISP does everything!" even though LISP gets that flexibity by imposing a butt-ugly syntax ("Lost In Stupid Parenthesis", anyone?) on pretty much everything.
I'm not saying to use mixins to solve every need that comes up. I'm saying it's worth trying them to solve a few obscure needs.
I can agree mixins are a perfectly fine interim solution for anything not already in the language, and for truly obscure needs (I use them all the time for both situations myself). But I'd still hardly consider flags and bitfields (to be clear, I'm talking about the abstract concept of a bitfield in general, not necessarily the C-style struct-with-sub-byte-member-alignment bitfield syntax/semantics) to be an "obscure" need in something that's supposed to be a systems language. I guess we just have a fundamental disagreement on that.
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 02:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:hogdpf$2te7$1 digitalmars.com...
 On 03/25/2010 02:28 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>   wrote in message
 news:hogc1o$2pm8$1 digitalmars.com...
 On 03/25/2010 01:33 PM, bearophile wrote:
 Andrei Alexandrescu:

 I encourage you to code that up and see how it swims.<
The idea of using that syntax gives me nausea, I can't use that even if I implement that myself.
I believe you're exaggerating.
Of course he is. But using mixins to "solve" every need that comes up is a bit like saying "LISP does everything!" even though LISP gets that flexibity by imposing a butt-ugly syntax ("Lost In Stupid Parenthesis", anyone?) on pretty much everything.
I'm not saying to use mixins to solve every need that comes up. I'm saying it's worth trying them to solve a few obscure needs.
I can agree mixins are a perfectly fine interim solution for anything not already in the language, and for truly obscure needs (I use them all the time for both situations myself). But I'd still hardly consider flags and bitfields (to be clear, I'm talking about the abstract concept of a bitfield in general, not necessarily the C-style struct-with-sub-byte-member-alignment bitfield syntax/semantics) to be an "obscure" need in something that's supposed to be a systems language. I guess we just have a fundamental disagreement on that.
In what ways do you find the bitfield interface wanting? Andrei
Mar 25 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:4BABC1F7.6080504 erdani.org...
 On 03/25/2010 02:52 PM, Nick Sabalausky wrote:
 I can agree mixins are a perfectly fine interim solution for anything not
 already in the language, and for truly obscure needs (I use them all the
 time for both situations myself). But I'd still hardly consider flags and
 bitfields (to be clear, I'm talking about the abstract concept of a 
 bitfield
 in general, not necessarily the C-style
 struct-with-sub-byte-member-alignment bitfield syntax/semantics) to be an
 "obscure" need in something that's supposed to be a systems language. I
 guess we just have a fundamental disagreement on that.
In what ways do you find the bitfield interface wanting?
Ignoring frequency-of-usage for the moment, since this is a question of syntax, compare these two syntaxes of creating a struct: mixin(struct!("myStruct" uint, "x", int, "y", uint, "z", bool, "flag")); Versus the current: struct myStruct { uint x; int y; uint z; bool flag; } There's just less syntactical noise, and the syntax is designed around the semantics rather than shoehorning various generic syntaxes to fit the purpose.
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 09:38 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:4BABC1F7.6080504 erdani.org...
 On 03/25/2010 02:52 PM, Nick Sabalausky wrote:
 I can agree mixins are a perfectly fine interim solution for anything not
 already in the language, and for truly obscure needs (I use them all the
 time for both situations myself). But I'd still hardly consider flags and
 bitfields (to be clear, I'm talking about the abstract concept of a
 bitfield
 in general, not necessarily the C-style
 struct-with-sub-byte-member-alignment bitfield syntax/semantics) to be an
 "obscure" need in something that's supposed to be a systems language. I
 guess we just have a fundamental disagreement on that.
In what ways do you find the bitfield interface wanting?
Ignoring frequency-of-usage for the moment, since this is a question of syntax, compare these two syntaxes of creating a struct: mixin(struct!("myStruct" uint, "x", int, "y", uint, "z", bool, "flag")); Versus the current: struct myStruct { uint x; int y; uint z; bool flag; } There's just less syntactical noise, and the syntax is designed around the semantics rather than shoehorning various generic syntaxes to fit the purpose.
But frequency of usage is essential. This is about bitfields, not struct. The former are arguably much less used than the latter. And then, there are many more uses than definitions. Andrei
Mar 25 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:hoh8eb$1kba$1 digitalmars.com...
 On 03/25/2010 09:38 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:4BABC1F7.6080504 erdani.org...
 On 03/25/2010 02:52 PM, Nick Sabalausky wrote:
 I can agree mixins are a perfectly fine interim solution for anything 
 not
 already in the language, and for truly obscure needs (I use them all 
 the
 time for both situations myself). But I'd still hardly consider flags 
 and
 bitfields (to be clear, I'm talking about the abstract concept of a
 bitfield
 in general, not necessarily the C-style
 struct-with-sub-byte-member-alignment bitfield syntax/semantics) to be 
 an
 "obscure" need in something that's supposed to be a systems language. I
 guess we just have a fundamental disagreement on that.
In what ways do you find the bitfield interface wanting?
Ignoring frequency-of-usage for the moment, since this is a question of syntax, compare these two syntaxes of creating a struct: mixin(struct!("myStruct" uint, "x", int, "y", uint, "z", bool, "flag")); Versus the current: struct myStruct { uint x; int y; uint z; bool flag; } There's just less syntactical noise, and the syntax is designed around the semantics rather than shoehorning various generic syntaxes to fit the purpose.
But frequency of usage is essential. This is about bitfields, not struct. The former are arguably much less used than the latter. And then, there are many more uses than definitions.
The question was "In what ways do you find the bitfield interface wanting?" I gave you my answer (syntactical noise and the syntax isn't designed around the feature but rather takes other syntaxes and shoehornes them in to fit the purpose.) That is the fault I find with it. Regardless of how common or uncommon it is, I still find that fault with it. Now certainly, if something is an rare enough need, than I can accept a certain amount of fault in the syntax. But that still doesn't change the syntax's faults. They're still there, they just may or may not be forgivable. If structs were a super-duper rare need, then I could live with the "bad" struct syntax above even though it clearly has faults. Maybe I didn't make this clear before (and I apologize for that), but anytime I've talked about bitfields being a common need, I've been talking about the abstract concept of a bitfield in general, not necessarily std.bitmanip.bitfield. I've been in D1/Tango-land for all of my D development lately, so I have to rely on the docs for my knowledge of std.bitmanip.bitfield. And the docs for std.bitmanip.bitfield don't appear to say anything about them other than just simply the syntax for how to create one (I can see that now that I realize the bitarray documentation is unrelated). So, to be clear: I have no idea whether or not I would find std.bitmanip.bitfield suitable enough for a large enough portion of the general bitfield uses out there (ie, to replace typical uses of manual bit-twiddling with ANDs, ORs, and bitmasks) that I would consider it as common a need as bitfields in general are. Bitfields in general: Very common need for systems programming, just ask Walter how many times he's ANDed or ORed a bitmask in his career. Phobos's 'std.bitmanip.bitfield': I have no idea how common the need.
Mar 25 2010
parent Mike Parker <aldacron gmail.com> writes:
Nick Sabalausky wrote:
 
 Bitfields in general: Very common need for systems programming, just ask 
 Walter how many times he's ANDed or ORed a bitmask in his career. Phobos's 
 
 
 
To make this conversation a little less confusing, I think the term you should be using here is 'bitmasks'.
Mar 26 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Regarding octals (and multi-precision integer literals, and unit system
 suffixes), it seems C++0x has user-defined literals :-) 
 http://en.wikipedia.org/wiki/C++0x#User-defined_literals (I am not asking to
 solve the D octal problem with them.)
The C++0x syntax for them to me appears to be a workaround for the bug that C++ templates cannot accept string literal arguments. As Andrei mentioned, the D version: Suffix!"string" more than adequately replaces it, and has the advantage of not requiring the user to learn a new syntax. Even better, D's user defined literals can be executed and resolved at compile time, while C++0x's are runtime only creations.
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 05:12 PM, Walter Bright wrote:
 bearophile wrote:
 Regarding octals (and multi-precision integer literals, and unit system
 suffixes), it seems C++0x has user-defined literals :-)
 http://en.wikipedia.org/wiki/C++0x#User-defined_literals (I am not
 asking to
 solve the D octal problem with them.)
The C++0x syntax for them to me appears to be a workaround for the bug that C++ templates cannot accept string literal arguments. As Andrei mentioned, the D version: Suffix!"string" more than adequately replaces it, and has the advantage of not requiring the user to learn a new syntax. Even better, D's user defined literals can be executed and resolved at compile time, while C++0x's are runtime only creations.
Then you'll be happy to start using octal as soon as I commit it. Andrei
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 Then you'll be happy to start using octal as soon as I commit it.
Haven't changed my mind about that, nor the reasons!
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 06:11 PM, Walter Bright wrote:
 Andrei Alexandrescu wrote:
 Then you'll be happy to start using octal as soon as I commit it.
Haven't changed my mind about that, nor the reasons!
Haven't seen you posting the results of the grep. As "reason" has the same root as "reasoning", there must be some of it aside from just subjective preference. As such, there must be some way you could respond to this:
 Symbolic constants are the best way to deal with the filesystem.

 It's not at all hard to beat. It would be if octal constants would be
 ubiquitous and ubiquitously useful. To disabuse yourself of that
 fallacious notion, PLEASE grep ALL your code for

 [^0-9A-Za-Z."%_:\]0[0-9]

 and let us know how many instances you find.

 druntime has 152 octal constants for a total of 53130 lines. That's
 one for each 350 lines of code, or less than 0.3%. Ironically, most
 occurrences are used in defining symbolic constants that are good
 style for handling permission bits.

 For Phobos I counted 11 true positives in 93,963 lines, which means
 one per 8542 lines of code or 0.01% of total.
Andrei
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 On 03/25/2010 06:11 PM, Walter Bright wrote:
 Andrei Alexandrescu wrote:
 Then you'll be happy to start using octal as soon as I commit it.
Haven't changed my mind about that, nor the reasons!
Haven't seen you posting the results of the grep. As "reason" has the same root as "reasoning", there must be some of it aside from just subjective preference. As such, there must be some way you could respond to this:
 druntime has 152 octal constants for a total of 53130 lines.
That's a lot more than I expected. And yes, there are reasons to have octal constants, and reasons not to. D will survive with or without them. In the end, it's a subjective call, dare I say a matter of 'taste'? I admit it, I just like octal constants. I like the way they look. I don't feel an urge to kill it with fire. I'd be sad to see them go. I like disco music, too, despite it being definitely out of style. One thing is clear, though. 0177 is never going to be a decimal number in D, because it will silently and disastrously break code translated from C. The only choice is to support 0177 as octal or make it a syntax error. I'd rather support them.
Mar 25 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 I admit it, I just like octal constants. I like the way they look. I don't
feel 
 an urge to kill it with fire. I'd be sad to see them go. I like disco music, 
 too, despite it being definitely out of style.
OK :-) There are other problems to fix :-) Bye, bearophile
Mar 25 2010
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hogsv9$11u7$1 digitalmars.com...
 One thing is clear, though. 0177 is never going to be a decimal number in 
 D, because it will silently and disastrously break code translated from C.
I'm certainly fine with that, since not breaking ported C code is one of D's philosophies.
 The only choice is to support 0177 as octal or make it a syntax error. I'd 
 rather support them.
Supporting it means it will "silently and disastrously break code" from anyone who tries to use a leading zero and *isn't* a C guru, and very few people these days are (I used C for years without being aware of that octal syntax - it's only by dumb luck I didn't try to use a leading zero). Granted, it may not be common for someone to try to use leading zeroes, but it's a landmine I'd rather not have, even if it is down a less-travelled sidestreet, expecially considering it's all for such a trivial benefit (which amounts to what, one person who just thinks it looks pretty?)
Mar 25 2010
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 09:10:09PM -0400, Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code" from 
 anyone who tries to use a leading zero
This is why I'd like them banned. Sometimes I write things like switch(a) { case 143: do something; break; case 642: do something; break; case 011: do something; break; } Using the leading zero just because I want it to line up in pretty columns. It has been a long time since I've actually made this mistake and got bit by it, but it has happened to me before. I'd feel better if it was a compile error just to ensure it never happens again. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
prev sibling next sibling parent Don <nospam nospam.com> writes:
Nick Sabalausky wrote:
 "Walter Bright" <newshound1 digitalmars.com> wrote in message 
 news:hogsv9$11u7$1 digitalmars.com...
 One thing is clear, though. 0177 is never going to be a decimal number in 
 D, because it will silently and disastrously break code translated from C.
I'm certainly fine with that, since not breaking ported C code is one of D's philosophies.
 The only choice is to support 0177 as octal or make it a syntax error. I'd 
 rather support them.
Supporting it means it will "silently and disastrously break code" from anyone who tries to use a leading zero and *isn't* a C guru, and very few people these days are (I used C for years without being aware of that octal syntax - it's only by dumb luck I didn't try to use a leading zero). Granted, it may not be common for someone to try to use leading zeroes, but it's a landmine I'd rather not have, even if it is down a less-travelled sidestreet, expecially considering it's all for such a trivial benefit (which amounts to what, one person who just thinks it looks pretty?)
Yes, it's just one more thing for a newbie to learn.
Mar 25 2010
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 08:10 PM, Nick Sabalausky wrote:
 "Walter Bright"<newshound1 digitalmars.com>  wrote in message
 news:hogsv9$11u7$1 digitalmars.com...
 The only choice is to support 0177 as octal or make it a syntax error. I'd
 rather support them.
Supporting it means it will "silently and disastrously break code" from anyone who tries to use a leading zero and *isn't* a C guru, and very few people these days are (I used C for years without being aware of that octal syntax - it's only by dumb luck I didn't try to use a leading zero). Granted, it may not be common for someone to try to use leading zeroes, but it's a landmine I'd rather not have, even if it is down a less-travelled sidestreet, expecially considering it's all for such a trivial benefit (which amounts to what, one person who just thinks it looks pretty?)
That kind of destroys Walter's argument. Andrei
Mar 25 2010
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code" from 
 anyone who tries to use a leading zero and *isn't* a C guru,
You don't need to be a guru to know that. I was once a C newbie, and never had any trouble with it. It isn't just C, either, the same syntax is used in C++, Objective-C, Groovy, M4, Clojure, Go, Java, Scala, Javascript, PHP, Ruby, bash, Python (2.6 and earlier) and Perl.
Mar 25 2010
parent reply KennyTM~ <kennytm gmail.com> writes:
On Mar 26, 10 11:32, Walter Bright wrote:
 Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code"
 from anyone who tries to use a leading zero and *isn't* a C guru,
You don't need to be a guru to know that. I was once a C newbie, and never had any trouble with it. It isn't just C, either, the same syntax is used in C++, Objective-C, Groovy, M4, Clojure, Go, Java, Scala, Javascript, PHP, Ruby, bash, Python (2.6 and earlier) and Perl.
And removed in ECMAScript 5 (next standard of Javascript).
Mar 26 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
KennyTM~ wrote:
 On Mar 26, 10 11:32, Walter Bright wrote:
 Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code"
 from anyone who tries to use a leading zero and *isn't* a C guru,
You don't need to be a guru to know that. I was once a C newbie, and never had any trouble with it. It isn't just C, either, the same syntax is used in C++, Objective-C, Groovy, M4, Clojure, Go, Java, Scala, Javascript, PHP, Ruby, bash, Python (2.6 and earlier) and Perl.
And removed in ECMAScript 5 (next standard of Javascript).
I didn't know that. But still, it's hard to be a programmer and not use a language that has such literals.
Mar 26 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/26/2010 06:26 PM, Walter Bright wrote:
 KennyTM~ wrote:
 On Mar 26, 10 11:32, Walter Bright wrote:
 Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code"
 from anyone who tries to use a leading zero and *isn't* a C guru,
You don't need to be a guru to know that. I was once a C newbie, and never had any trouble with it. It isn't just C, either, the same syntax is used in C++, Objective-C, Groovy, M4, Clojure, Go, Java, Scala, Javascript, PHP, Ruby, bash, Python (2.6 and earlier) and Perl.
And removed in ECMAScript 5 (next standard of Javascript).
I didn't know that. But still, it's hard to be a programmer and not use a language that has such literals.
http://en.wikipedia.org/wiki/Argumentum_ad_populum Andrei
Mar 26 2010
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 On 03/26/2010 06:26 PM, Walter Bright wrote:
 KennyTM~ wrote:
 On Mar 26, 10 11:32, Walter Bright wrote:
 Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code"
 from anyone who tries to use a leading zero and *isn't* a C guru,
You don't need to be a guru to know that. I was once a C newbie, and never had any trouble with it. It isn't just C, either, the same syntax is used in C++, Objective-C, Groovy, M4, Clojure, Go, Java, Scala, Javascript, PHP, Ruby, bash, Python (2.6 and earlier) and Perl.
And removed in ECMAScript 5 (next standard of Javascript).
I didn't know that. But still, it's hard to be a programmer and not use a language that has such literals.
http://en.wikipedia.org/wiki/Argumentum_ad_populum
I was responding to Nick's argument: ------------------------------ Supporting it means it will "silently and disastrously break code" from anyone who tries to use a leading zero and *isn't* a C guru, and very few people these days are (I used C for years without being aware of that octal syntax - it's only by dumb luck I didn't try to use a leading zero). ------------------------------- where the statement of very few people being exposed to such literals is the issue. I should have left in the fuller quote.
Mar 26 2010
parent "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hojjk3$3ch$1 digitalmars.com...
 Andrei Alexandrescu wrote:
 On 03/26/2010 06:26 PM, Walter Bright wrote:
 KennyTM~ wrote:
 On Mar 26, 10 11:32, Walter Bright wrote:
 Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code"
 from anyone who tries to use a leading zero and *isn't* a C guru,
You don't need to be a guru to know that. I was once a C newbie, and never had any trouble with it. It isn't just C, either, the same syntax is used in C++, Objective-C, Groovy, M4, Clojure, Go, Java, Scala, Javascript, PHP, Ruby, bash, Python (2.6 and earlier) and Perl.
And removed in ECMAScript 5 (next standard of Javascript).
I didn't know that. But still, it's hard to be a programmer and not use a language that has such literals.
http://en.wikipedia.org/wiki/Argumentum_ad_populum
I was responding to Nick's argument: ------------------------------ Supporting it means it will "silently and disastrously break code" from anyone who tries to use a leading zero and *isn't* a C guru, and very few people these days are (I used C for years without being aware of that octal syntax - it's only by dumb luck I didn't try to use a leading zero). ------------------------------- where the statement of very few people being exposed to such literals is the issue. I should have left in the fuller quote.
Using a language that has 0xxx-style octal literals and actually being aware of it are two different things. And I'd say that my assumption it was only C speaks to its obscurity.
Mar 26 2010
prev sibling parent Justin Johansson <no spam.com> writes:
Andrei Alexandrescu Wrote:

 On 03/26/2010 06:26 PM, Walter Bright wrote:
 KennyTM~ wrote:
 On Mar 26, 10 11:32, Walter Bright wrote:
 Nick Sabalausky wrote:
 Supporting it means it will "silently and disastrously break code"
 from anyone who tries to use a leading zero and *isn't* a C guru,
You don't need to be a guru to know that. I was once a C newbie, and never had any trouble with it. It isn't just C, either, the same syntax is used in C++, Objective-C, Groovy, M4, Clojure, Go, Java, Scala, Javascript, PHP, Ruby, bash, Python (2.6 and earlier) and Perl.
And removed in ECMAScript 5 (next standard of Javascript).
I didn't know that. But still, it's hard to be a programmer and not use a language that has such literals.
http://en.wikipedia.org/wiki/Argumentum_ad_populum Andrei
I'll see you and raise you one. http://en.wikipedia.org/wiki/Meme Justin
Mar 27 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 (I used C for years without being aware of that octal 
 syntax - it's only by dumb luck I didn't try to use a leading zero). 
It is on the 3rd page of chapter 2 in K&R (and chapter 2 is the first chapter of the specification). A mitigating factor is who uses leading 0's for integer literals? Another is if you started using leading 0's, very quickly you'd try using the digits 8 or 9, and would get an error. I don't think you'd get very far using leading 0's without discovering the issue.
Mar 25 2010
parent reply Don <nospam nospam.com> writes:
Walter Bright wrote:
 Nick Sabalausky wrote:
 (I used C for years without being aware of that octal syntax - it's 
 only by dumb luck I didn't try to use a leading zero). 
It is on the 3rd page of chapter 2 in K&R (and chapter 2 is the first chapter of the specification). A mitigating factor is who uses leading 0's for integer literals? Another is if you started using leading 0's, very quickly you'd try using the digits 8 or 9, and would get an error. I don't think you'd get very far using leading 0's without discovering the issue.
I've done it with powers of 10: 001, 010, 100 and then wondered why my code was wrong. It's the only time in my life I've ever used an octal literal.
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 I've done it with powers of 10:
 001,
 010,
 100
 
 and then wondered why my code was wrong. It's the only time in my life 
 I've ever used an octal literal.
I see that and it screams BINARY to me, not decimal! I guess I'm not sure why it never was a problem for me. It's just "oh, that's octal, ok" and went on to more interesting things.
Mar 25 2010
parent "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hohhnn$252d$1 digitalmars.com...
 Don wrote:
 I've done it with powers of 10:
 001,
 010,
 100

 and then wondered why my code was wrong. It's the only time in my life 
 I've ever used an octal literal.
I see that and it screams BINARY to me, not decimal!
0b001, 0b010, 0b100 To me, *that* screams binary. ;)
Mar 25 2010
prev sibling parent reply Rainer Deyke <rainerd eldwood.com> writes:
On 3/25/2010 17:52, Walter Bright wrote:
 One thing is clear, though. 0177 is never going to be a decimal number
 in D, because it will silently and disastrously break code translated
 from C. The only choice is to support 0177 as octal or make it a syntax
 error. I'd rather support them.
I don't mind octal literals, but '0177' is a horrible syntax. *Every* *single* *time* that I used that syntax in C or C++, I really meant to use a decimal. -- Rainer Deyke - rainerd eldwood.com
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Rainer Deyke wrote:
 I don't mind octal literals, but '0177' is a horrible syntax.  *Every*
 *single* *time* that I used that syntax in C or C++, I really meant to
 use a decimal.
I'm curious what tempted you to use a leading 0 in the first place.
Mar 25 2010
parent reply Rainer Deyke <rainerd eldwood.com> writes:
On 3/25/2010 23:40, Walter Bright wrote:
 Rainer Deyke wrote:
 I don't mind octal literals, but '0177' is a horrible syntax.  *Every*
 *single* *time* that I used that syntax in C or C++, I really meant to
 use a decimal.
I'm curious what tempted you to use a leading 0 in the first place.
Padding to get an array literal to align properly. Something like this: int a[3][3] = { {001, 002, 003}, {010, 020, 030}, {100, 200, 300}, }; I could have used (and should have used, and eventually did use) spaces instead, but I don't think they look as nice in this instance. -- Rainer Deyke - rainerd eldwood.com
Mar 25 2010
parent Don <nospam nospam.com> writes:
Rainer Deyke wrote:
 On 3/25/2010 23:40, Walter Bright wrote:
 Rainer Deyke wrote:
 I don't mind octal literals, but '0177' is a horrible syntax.  *Every*
 *single* *time* that I used that syntax in C or C++, I really meant to
 use a decimal.
I'm curious what tempted you to use a leading 0 in the first place.
Padding to get an array literal to align properly. Something like this: int a[3][3] = { {001, 002, 003}, {010, 020, 030}, {100, 200, 300}, }; I could have used (and should have used, and eventually did use) spaces instead, but I don't think they look as nice in this instance.
Yes, because spaces have different widths to digits in most mono-spaced fonts.
Mar 26 2010
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 A: Use octal!"177"
 
 W: Ugh.
 
 A (esprit d'escalier): If you don't like the universal notation you 
 invented, who will?
Good point. As I recall, we expended an enormous amount of effort working on template syntax, and I certainly feel that octal!"177" is far better than, say: octal<"177">.value but when I compare it to 0177 that's just hard to beat. A customized syntax is always going to be better than a generic one. The octal syntax is used in several widely popular languages, and is convenient and looks attractive. It's used a lot in dealing with the unix file system.
Mar 25 2010
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 11:45:11AM -0700, Walter Bright wrote:
 Good point. As I recall, we expended an enormous amount of effort working 
 on template syntax, and I certainly feel that
 
     octal!"177"
 
 is far better than, say:
 
     octal<"177">.value
 
 but when I compare it to
 
     0177
What about O!177? The O template would take the integer passed as its argument, convert it to a string, then convert that back into number assuming it is octal. (Or some implementation of that idea.) It just saves the quotes there, but ends up looking very close to the custom syntax. And it frees up leading zeroes for use in base ten where they belong to make pretty tables. Though you might want to ban this for C compatibility anyway. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:
 What about O!177?
See the answer by Andrei: http://d.puremagic.com/issues/show_bug.cgi?id=2656 The answer is essentially: how can you represent very large 64 bit octal values with that syntax? Bye, bearophile
Mar 25 2010
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 03:05:28PM -0400, bearophile wrote:
 The answer is essentially: how can you represent very large 64 bit octal
values with that syntax?
Have the user switch over to the string notation in those rare cases. The argument most often brought up for keeping octal *at all* is unix filesystem permissions. They are only ever as big as four digits (AFAIK). 7777 certainly fits in an integer. Even 8 digits: 77_777_777 is still well within the limits of an integer literal. So, in theory, yeah, the integer can't express all numbers in octal that can fit. But in practice? How often would this come up? Does the language *really* need to address this globally just to avoid the quotes in those specific situations? The one person who has such a use for giant octal literals might complain "gah I have to quote it once it gets to a certain size, this kinda sucks", but I'm ok with that. Another possibility might be having integer literals actually be infinite in size in the compiler, and use a template alias.. or something, to take them unmolested into CTFE for manipulation. This would also be useful for bignum structs. You can just reuse the plain old integer literal when initalizing them. Then, if the literal is too big to fit in the type requested, the compiler throws an error only at the last minute it can possibly check. This would be more generally useful than a special octal literal, but since it means changes to the compiler, the cost is higher too. The nice thing about my O!100 or Andrei's octal!"100" is that they work in D today. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 02:33 PM, Adam D. Ruppe wrote:
 On Thu, Mar 25, 2010 at 03:05:28PM -0400, bearophile wrote:
 The answer is essentially: how can you represent very large 64 bit octal
values with that syntax?
Have the user switch over to the string notation in those rare cases.
I think that's a brilliant idea. Andrei
Mar 25 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 Have the user switch over to the string notation in those rare cases.
OK. But are you sure you want a template named just "O" in the std lib? Oct or Octal can cause less collisions.
 Another possibility might be having integer literals actually be infinite
 in size in the compiler, and use a template alias.. or something, to take
 them unmolested into CTFE for manipulation.
 
 This would also be useful for bignum structs. You can just reuse the plain
 old integer literal when initalizing them.
 
 Then, if the literal is too big to fit in the type requested, the compiler
 throws an error only at the last minute it can possibly check.
If this can work and be safe, then it's a cute idea. Bye, bearophile
Mar 25 2010
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 04:08:26PM -0400, bearophile wrote:
 OK.
 But are you sure you want a template named just "O" in the std lib? Oct or
Octal can cause less collisions.
The name doesn't matter much to me. I said O!777 just because looks as similar on the screen to 0777 as we can without changing the rules of the language. I'm ok with octal too; the name isn't a big deal.
 If this can work and be safe, then it's a cute idea.
Aye. If only implementing it were free :P -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 03:20 PM, Adam D. Ruppe wrote:
 On Thu, Mar 25, 2010 at 04:08:26PM -0400, bearophile wrote:
 OK.
 But are you sure you want a template named just "O" in the std lib? Oct or
Octal can cause less collisions.
The name doesn't matter much to me. I said O!777 just because looks as similar on the screen to 0777 as we can without changing the rules of the language. I'm ok with octal too; the name isn't a big deal.
 If this can work and be safe, then it's a cute idea.
Aye. If only implementing it were free :P
Contest: define "octal" as per the blueprint above and paste it here. Andrei
Mar 25 2010
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 03:37:52PM -0500, Andrei Alexandrescu wrote:
 Contest: define "octal" as per the blueprint above and paste it here.
Trivial. I'll start with the code you posted on the bugzilla. ===== template octal(string s) { static assert(s.length > 0); static assert(s[0] >= '0' && s[0] < '8', "Incorrect character in octal constant: `" ~ s[0] ~ "'"); static if (s.length == 1) { enum uint octal = s[0] - '0'; } else { enum uint octal = 8 * (s[0] - '0') + octal!(s[1 .. $]); } } ====== Then add just this: ==== import std.metastrings; template octal(uint s) { enum uint octal = octal!(toStringNow!(s)); } ===== Take the unittest from bugzilla and add the same using the literal: unittest { static assert(octal!"45" == 37); static assert(octal!"0" == 0); static assert(octal!"7" == 7); static assert(octal!"10" == 8); static assert(octal!45 == 37); static assert(octal!0 == 0); static assert(octal!7 == 7); static assert(octal!10 == 8); } void main() {} Run it. Boom! The tests pass. Change the names to your heart's desire. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 03:57 PM, Adam D. Ruppe wrote:
 On Thu, Mar 25, 2010 at 03:37:52PM -0500, Andrei Alexandrescu wrote:
 Contest: define "octal" as per the blueprint above and paste it here.
Trivial. I'll start with the code you posted on the bugzilla.
Now that's what I'd call fast. bearophile made a good point though: there are many template instantiations, so at best we should use CTFE. What changes would be needed? Thanks, Andrei
Mar 25 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:
 Trivial. I'll start with the code you posted on the bugzilla.
It's better to minimize the number of templates created by the code. I have used CTFE here (not much tested): import std.metastrings: toStringNow; ulong octal_helper(string value) { assert(value.length > 0); ulong result; foreach (digit; value) { assert(digit >= '0' && digit < '8', "Incorrect character in octal constant: '" ~ value[0] ~ "'"); result = result * 8 + (digit - '0'); } return result; } template octal(string s) { enum uint octal = octal_helper(s); } template octal(ulong s) { enum uint octal = octal_helper(toStringNow!(s)); } void main() { //unittest { static assert(octal!"45" == 37); static assert(octal!"0" == 0); static assert(octal!"7" == 7); static assert(octal!"10" == 8); static assert(octal!45 == 37); static assert(octal!0 == 0); static assert(octal!7 == 7); static assert(octal!10 == 8); //static assert(octal!(-2) == 8); } It needs many more unittests, to tests all the bounds, corner cases, etc. They also have to test that the code actually asserts when the inputs are wrong in various ways. This is how I test my D code. Bye, bearophile
Mar 25 2010
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 05:12:07PM -0400, bearophile wrote:
 It needs many more unittests, to tests all the bounds, corner cases, etc. They
also have to test that the code actually asserts when the inputs are wrong in
various ways. This is how I test my D code.
Yeah, you're right on a few counts. The template there actually fails on any string with length > 2. I rewrote it just now to do CTFE too to get around it. I also let underscores into the string in my new version, and switched the uints to ulongs so we can get bigger literals before needing strings. It seems to work well. Here's my new code: === ulong octal(string num)() { static assert(num.length > 0); ulong pow = 1; ulong value = 0; for(int pos = num.length - 1; pos >= 0; pos--) { char s = num[pos]; if(s == '_') continue; assert(s >= '0' && s < '8', "Incorrect character in octal constant: `" ~ s ~ "'"); value += pow * (s - '0'); pow *= 8; } return value; } import std.metastrings; template octal(ulong s) { enum uint octal = octal!(toStringNow!(s)); } unittest { static assert(octal!"45" == 37); static assert(octal!"0" == 0); static assert(octal!"7" == 7); static assert(octal!"10" == 8); static assert(octal!"666" == 438); static assert(octal!45 == 37); static assert(octal!0 == 0); static assert(octal!7 == 7); static assert(octal!10 == 8); static assert(octal!666 == 438); static assert(octal!"66_6" == 438); static assert(octal!2520046213 == 356535435); static assert(octal!"2520046213" == 356535435); } import std.stdio; void main() { int a = octal!254; // just checking implicit conversion of ulong to int; it would suck if this failed writefln("%d", a); } ==== -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 04:32 PM, Adam D. Ruppe wrote:
 On Thu, Mar 25, 2010 at 05:12:07PM -0400, bearophile wrote:
 It needs many more unittests, to tests all the bounds, corner cases, etc. They
also have to test that the code actually asserts when the inputs are wrong in
various ways. This is how I test my D code.
Yeah, you're right on a few counts. The template there actually fails on any string with length> 2. I rewrote it just now to do CTFE too to get around it. I also let underscores into the string in my new version, and switched the uints to ulongs so we can get bigger literals before needing strings. It seems to work well. Here's my new code:
It does work well, but there's one more issue: the type of octal!x is always ulong. To make the code industrial strength, you should observe the usual D rules: * if it fits in an int it has type int, otherwise it has type long * the suffixes U, u, and L should be observed If you make these changes I'll commit your code in std.conv with credit. Andrei
Mar 25 2010
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 04:52:29PM -0500, Andrei Alexandrescu wrote:
 It does work well, but there's one more issue: the type of octal!x is 
 always ulong. To make the code industrial strength, you should observe 
 the usual D rules:
I think I made it work. Also used template constraints to pretty up the error messages a little on bad strings. The line number is still that of the template instead of the instantiation, but maybe it is just because my dmd is a few months old. I seem to recall seeing this improved in the compiler itself, so I'm not worrying about it here. The code is way at the bottom of this message. I'm going to show off a bit first :) Error messages: int w = octal!845; octal.d(106): Error: static assert "845 is not a valid octal literal" int w = octal!"spam"; octal.d(106): Error: static assert "spam is not a valid octal literal" The type magic works pretty well too: int w = octal!"017777777777"; // compiles int w = octal!"020000000000"; // but this doesn't... (this is int.max+1 btw) octal.d(147): Error: cannot implicitly convert expression (octal()) of type long to int int w = octal!"1L"; octal.d(147): Error: cannot implicitly convert expression (octal()) of type long to int int w = octal!"1uL"; octal.d(147): Error: cannot implicitly convert expression (octal()) of type ulong to int This also works with integer literals instead of strings: auto w = octal!1L; pragma(msg, typeof(w)); // prints "long" auto w = octal!1; pragma(msg, typeof(w)); // prints "int" auto w = octal!1u; pragma(msg, typeof(w)); // prints "uint" The only bug I'm seeing is if the integer literal is type long, but once converted to octal it will fit in an int, the template returns a long. Passing a string does the right thing and returns int, but the literal doesn't. I don't see a way to fix this without breaking the octal!1777[...]7L case. (To make the suffixes on literals work, I did typeof an alias for the helper template instead of analyzing the string like I did for the main template. I couldn't think of any other way to make it work; I even tried parsing stringof the alias, but alas. Anyway, aside from that, it works perfectly in my battery of tests. Handles suffixes, embedded underscores, bad strings, types. Pretty cool. Here's the code, with some comments added too: =============================== /* Take a look at int.max and int.max+1 in octal and the logic for this function follows directly. */ template octalFitsInInt(string octalNum) { // note it is important to strip the literal of all non-numbers. kill the suffix and underscores // lest they mess up the number of digits here that we depend on. static if(strippedOctalLiteral(octalNum).length < 11) enum bool octalFitsInInt = true; else static if(strippedOctalLiteral(octalNum).length == 11 && strippedOctalLiteral(octalNum)[0] == '1') enum bool octalFitsInInt = true; else enum bool octalFitsInInt = false; } string strippedOctalLiteral(string original) { string stripped = ""; foreach(c; original) if(c >= '0' && c <= '7') stripped ~= c; return stripped; } template literalIsLong(string num) { static if(num.length > 1) enum literalIsLong = (num[$-1] == 'L' || num[$-2] == 'L'); // can be xxL or xxLu according to spec else enum literalIsLong = false; } template literalIsUnsigned(string num) { static if(num.length > 1) enum literalIsUnsigned = (num[$-1] == 'u' || num[$-2] == 'u') // can be xxL or xxLu according to spec || (num[$-1] == 'U' || num[$-2] == 'U'); // both cases are allowed too else enum literalIsUnsigned = false; } /** These pass out the correctly typed literal based on the specifiers on the end of the string and the size of the literal. If it can fit in an int, it is an int. Otherwise, it is a long. But, if the user specifically asks for a long with the L suffix, always give the long. Give an unsigned iff it is asked for with the U or u suffix. */ int octal(string num)() if((octalFitsInInt!(num) && !literalIsLong!(num)) && !literalIsUnsigned!(num)) { return octal!(int, num); } long octal(string num)() if((!octalFitsInInt!(num) || literalIsLong!(num)) && !literalIsUnsigned!(num)) { return octal!(long, num); } uint octal(string num)() if((octalFitsInInt!(num) && !literalIsLong!(num)) && literalIsUnsigned!(num)) { return octal!(int, num); } ulong octal(string num)() if((!octalFitsInInt!(num) || literalIsLong!(num)) && literalIsUnsigned!(num)) { return octal!(long, num); } /* Returns if the given string is a correctly formatted octal literal. The format is specified in lex.html. The leading zero is allowed, but not required. */ bool isOctalLiteralString(string num) { if(num.length == 0) return false; // must start with a number if(num[0] < '0' || num[0] > '7') return false; foreach(i, c; num) { if((c < '0' || c > '7') && c != '_') // not a legal character if(i < num.length - 2) return false; else { // gotta check for those suffixes if(c != 'U' && c != 'u' && c != 'L') return false; if(i != num.length - 1) { // if we're not the last one, the next one must also be a suffix to be valid char c2 = num[$-1]; if(c2 != 'U' && c2 != 'u' && c2 != 'L') return false; // spam at the end of the string if(c2 == c) return false; // repeats are disallowed } } } return true; } /* Returns true if the given compile time string is an octal literal. */ template isOctalLiteral(string num) { enum bool isOctalLiteral = isOctalLiteralString(num); } /* Takes a string, num, which is an octal literal, and returns its value, in the type T specified. So: int a = octal!(int, "10"); assert(a == 8); */ T octal(T, string num)() { static assert(isOctalLiteral!num, num ~ " is not a valid octal literal"); ulong pow = 1; T value = 0; for(int pos = num.length - 1; pos >= 0; pos--) { char s = num[pos]; if(s < '0' || s > '7') // we only care about digits; skip the rest continue; // safe to skip - this is checked out in the assert so these are just suffixes value += pow * (s - '0'); pow *= 8; } return value; } import std.metastrings: toStringNow; import std.traits: isIntegral; /** Constructs an octal literal from a number, maintaining the type of the original number. For example: octal!10 is exactly the same as integer literal 8. octal!10U is identical to the literal 8U. */ template octal(alias s) if(isIntegral!(typeof(s))) { enum auto octal = octal!(typeof(s), toStringNow!(s)); } unittest { // ensure that you get the right types, even with embedded underscores auto w = octal!"100_000_000_000"; static assert(!is(typeof(w) == int)); auto w2 = octal!"1_000_000_000"; static assert(is(typeof(w2) == int)); static assert(octal!"45" == 37); static assert(octal!"0" == 0); static assert(octal!"7" == 7); static assert(octal!"10" == 8); static assert(octal!"666" == 438); static assert(octal!45 == 37); static assert(octal!0 == 0); static assert(octal!7 == 7); static assert(octal!10 == 8); static assert(octal!666 == 438); static assert(octal!"66_6" == 438); static assert(octal!2520046213 == 356535435); static assert(octal!"2520046213" == 356535435); static assert(octal!17777777777 == int.max); static assert(!__traits(compiles, octal!823)); // static assert(!__traits(compiles, octal!"823")); // for some reason, this line fails, though if you try it in code, it indeed doesn't compile... weird. static assert(!__traits(compiles, octal!"_823")); static assert(!__traits(compiles, octal!"spam")); static assert(!__traits(compiles, octal!"77%")); int a; long b; static assert(__traits(compiles, a = octal!"17777777777")); // biggest value that should fit in an it static assert(!__traits(compiles, a = octal!"20000000000")); // should not fit in the int static assert(__traits(compiles, b = octal!"20000000000")); // ... but should fit in a long static assert(!__traits(compiles, a = octal!"1L")); //static assert(!__traits(compiles, a = octal!1L)); // this should pass, but it doesn't, since the int converter doesn't pass along its suffix to helper templates static assert(__traits(compiles, b = octal!"1L")); static assert(__traits(compiles, b = octal!1L)); } =============================== -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/26/2010 12:47 AM, Adam D. Ruppe wrote:
 On Thu, Mar 25, 2010 at 04:52:29PM -0500, Andrei Alexandrescu wrote:
 It does work well, but there's one more issue: the type of octal!x is
 always ulong. To make the code industrial strength, you should observe
 the usual D rules:
I think I made it work.
http://www.dsource.org/projects/phobos/browser/trunk/phobos/std/conv.d?rev=1469 Andrei
Mar 26 2010
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:
 It seems to work well.
It will need a more testing, and "negative testing" too: for example good tests must assert that this generates an error at compile time: octal!"_" Bye, bearophile
Mar 25 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Every time I write a small number of lines of code in D2, like here, I find
what I think is a bug:
http://d.puremagic.com/issues/show_bug.cgi?id=4005

Bye,
bearophile
Mar 25 2010
prev sibling parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Adam D. Ruppe:
 Trivial. I'll start with the code you posted on the bugzilla.
It's better to minimize the number of templates created by the code. I have used CTFE here (not much tested): import std.metastrings: toStringNow;
Do NOT use toStringNow. std.metastrings is mostly obsolete -- it predates CTFE. CTFE functions are much easier to test than templates, you can use run-time tests and check code coverage, for example. And the code is much easier to read.
Mar 25 2010
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Fri, Mar 26, 2010 at 02:38:53AM +0100, Don wrote:
 Do NOT use toStringNow. std.metastrings is mostly obsolete -- it 
 predates CTFE.
All I wanted there was a quick conversion. At first, I wrote octal!(to!string(my_integer)); but it didn't compile... In any case, redoing it is simple enough, but if you don't want people using the solution in the library, it should at least be marked in the docs. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
parent reply Don <nospam nospam.com> writes:
Adam D. Ruppe wrote:
 On Fri, Mar 26, 2010 at 02:38:53AM +0100, Don wrote:
 Do NOT use toStringNow. std.metastrings is mostly obsolete -- it 
 predates CTFE.
All I wanted there was a quick conversion. At first, I wrote octal!(to!string(my_integer)); but it didn't compile... In any case, redoing it is simple enough, but if you don't want people using the solution in the library, it should at least be marked in the docs.
That reply was to bearophile, who said he was minimizing the number of templates. But since he was using toStringNow, the code created a huge number of templates.
Mar 25 2010
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Fri, Mar 26, 2010 at 02:53:58AM +0100, Don wrote:
 That reply was to bearophile, who said he was minimizing the number of 
 templates. But since he was using toStringNow, the code created a huge 
 number of templates.
Oh sorry, I generalize too hastily! -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 04:57:00PM -0400, Adam D. Ruppe wrote:
 Run it. Boom! The tests pass.
I always post too soon! It fails with larger numbers. The octal!(string) code is to blame; it doesn't raise 8 to the right power on strings with length > 2. And opPow doesn't seem to work here. So I'll do it slightly differently: ==== /* new function */ uint octal(string num)() { static assert(num.length > 0); uint pow = 1; uint value = 0; for(int pos = num.length - 1; pos >= 0; pos--) { char s = num[pos]; assert(s >= '0' && s < '8', "Incorrect character in octal constant: `" ~ s ~ "'"); value += pow * (s - '0'); pow *= 8; } return value; } /* end changes */ import std.metastrings; template octal(uint s) { enum uint octal = octal!(toStringNow!(s)); } unittest { static assert(octal!"45" == 37); static assert(octal!"0" == 0); static assert(octal!"7" == 7); static assert(octal!"10" == 8); static assert(octal!45 == 37); static assert(octal!0 == 0); static assert(octal!7 == 7); static assert(octal!10 == 8); } void main() { // a triple check pragma(msg, octal!666); // prints correctly as it compiles, yay } === And as a final check: pragma(msg, octal!6668); octal.d(9): Error: "Incorrect character in octal constant: `8'" octal.d(22): Error: cannot evaluate octal() at compile time octal.d(22): Error: cannot evaluate octal() at compile time octal.d(43): Error: template instance octal.octal!(6668) error instantiating Good, good. But is it still compile time elsewhere? writeln(octal!6668); Same spewing errors. A bit wordy, but definitely gives error correctly. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Adam D. Ruppe wrote:
 The argument most often brought up for keeping octal *at all* is unix
 filesystem permissions. They are only ever as big as four digits (AFAIK).
There is one other reason: converting C code to D code. This should follow the principle of "if it doesn't give a compiler error, it should produce the same result". Translating: 0177 in C to: 0177 in D will silently produce a very different result (should such a number be decimal).
Mar 25 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:

 Translating:
 
     0177
 
 in C to:
 
     0177
 
 in D will silently produce a very different result
Nope, here I have suggested to turn leading zeros in syntax errors: http://d.puremagic.com/issues/show_bug.cgi?id=3837 Bye, bearophile
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Nope, here I have suggested to turn leading zeros in syntax errors:
 http://d.puremagic.com/issues/show_bug.cgi?id=3837
Right, but that doesn't help those who wish to use leading 0s.
Mar 25 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 06:12 PM, Walter Bright wrote:
 bearophile wrote:
 Nope, here I have suggested to turn leading zeros in syntax errors:
 http://d.puremagic.com/issues/show_bug.cgi?id=3837
Right, but that doesn't help those who wish to use leading 0s.
Why do they wish it, how often do they wish it, and why should we support the wrong style with an abundance of magic numbers? Andrei
Mar 25 2010
prev sibling next sibling parent "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hogqkn$uma$2 digitalmars.com...
 bearophile wrote:
 Nope, here I have suggested to turn leading zeros in syntax errors:
 http://d.puremagic.com/issues/show_bug.cgi?id=3837
Right, but that doesn't help those who wish to use leading 0s.
I don't think anyone cares about being able to use leading zeros for a decimal literal. The primary complaint is that if a leading zero does get used (either by accident, or by someone who doesn't know that D breaks basic grade-school number convention), it results in a silent bug.
Mar 25 2010
prev sibling parent reply BCS <none anon.com> writes:
Hello Walter,

 bearophile wrote:
 
 Nope, here I have suggested to turn leading zeros in syntax errors:
 http://d.puremagic.com/issues/show_bug.cgi?id=3837
 
Right, but that doesn't help those who wish to use leading 0s.
Who wants to do that? -- ... <IXOYE><
Mar 25 2010
parent "Nick Sabalausky" <a a.a> writes:
"BCS" <none anon.com> wrote in message 
news:a6268ff11b928cc9a720a2994a6 news.digitalmars.com...
 Hello Walter,

 bearophile wrote:

 Nope, here I have suggested to turn leading zeros in syntax errors:
 http://d.puremagic.com/issues/show_bug.cgi?id=3837
Right, but that doesn't help those who wish to use leading 0s.
Who wants to do that?
At this point, I see that other people have mentioned in other branches of the thread that they would like to use loeading zeros as an alternate to spaces for visual alignment. But, I think think is one case where I can put words in people's mouths without risk of being wrong: I'm pretty sure even they would much rather leading zeroes be disallowed than have it silently change the literal's value.
Mar 25 2010
prev sibling parent reply Clemens <eriatarka84 gmail.com> writes:
Walter Bright Wrote:

 Adam D. Ruppe wrote:
 The argument most often brought up for keeping octal *at all* is unix
 filesystem permissions. They are only ever as big as four digits (AFAIK).
There is one other reason: converting C code to D code. This should follow the principle of "if it doesn't give a compiler error, it should produce the same result". Translating: 0177 in C to: 0177 in D will silently produce a very different result (should such a number be decimal).
How about a command line argument to DMD which can be used to aid in porting legacy C code? It would cause the compiler to generate a warning (or error if you wish) for every occurrence of an ambiguous construct like this. Once all such cases have been converted to valid D code and the code compiles without warnings, the command line argument can be dropped. This allows D to escape from the C compatibility trap which has encumbered C++ so much while still giving safety against subtle bugs while porting old code.
Mar 25 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Clemens:
a command line argument to DMD which can be used to aid in porting legacy C
code?<
That's a nice idea, thank you for inventing it. Time ago I was vaguely thinking about something similar, but not quite. DMD1 has: -d allow deprecated features So D2 can grow a command line switch as (or another name): -ctest to be used in porting C code to D2. It probably just activates warnings that can help avoid many C porting bugs. For example it can warn the programmer that global floats are not initialized to zero, or fixed-sized arrays are passed by value, etc. In theory this new command line switch this can even allow D to improve the syntax of the switch, avoiding the fall-through :-) Bye, bearophile
Mar 25 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Clemens" <eriatarka84 gmail.com> wrote in message 
news:hogss7$11nb$1 digitalmars.com...
 How about a command line argument to DMD which can be used to aid in 
 porting legacy C code? It would cause the compiler to generate a warning 
 (or error if you wish) for every occurrence of an ambiguous construct like 
 this. Once all such cases have been converted to valid D code and the code 
 compiles without warnings, the command line argument can be dropped.

 This allows D to escape from the C compatibility trap which has encumbered 
 C++ so much while still giving safety against subtle bugs while porting 
 old code.
I fear it's probably too late for that for D, but I do like it very much. If I ever make a C-style langauge myself, I'll definitely consider something like that.
Mar 25 2010
parent reply BCS <none anon.com> writes:
Hello Nick,

 I fear it's probably too late for that for D, but I do like it very
 much.
Why? The proposal is merely a compiler implementation detail rather than a language feature. It could even be done as part of a lint like tool. -- ... <IXOYE><
Mar 25 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <none anon.com> wrote in message 
news:a6268ff11bc38cc9a74b199788a news.digitalmars.com...
 Hello Nick,

 I fear it's probably too late for that for D, but I do like it very
 much.
Why? The proposal is merely a compiler implementation detail rather than a language feature. It could even be done as part of a lint like tool.
A *lot* of D's design has already been based around the idea of C code doing either the same thing or erroring when compiled for D. Plus, Walter loves that strategy, and hates extra warnings. I'd love for it to happen, but I guess I'm just saying "I ain't holdin my breath!"
Mar 25 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:

A *lot* of D's design has already been based around the idea of C code doing
either the same thing or erroring when compiled for D. Plus, Walter loves that
strategy, and hates extra warnings. I'd love for it to happen, but I guess I'm
just saying "I ain't holdin my breath!" <
This is not the same situation. As far as I know Walter doesn't like warnings for D code. But this compiler switch is not designed for D code, it's strictly designed for C code just ported to D, to warn in the porting of some possible traps/bugs, like: - global floats not initialized to 0.0 (this has caused a bug in code of mine translated from C); - fixed sized-arrays passed by value; - etc. Walter doesn't like warnings for example because there are shops that have a zero warning policy, they consider C compiler warnings as errors (and this is silly, I agree with Walter). But those warnings have no purpose for normal D code, they are not designed for D code, they are designed for C code that just looks like D. Bye, bearophile
Mar 26 2010
prev sibling parent BCS <none anon.com> writes:
Hello Adam,

 On Thu, Mar 25, 2010 at 11:45:11AM -0700, Walter Bright wrote:
 
 Good point. As I recall, we expended an enormous amount of effort
 working on template syntax, and I certainly feel that
 
 octal!"177"
 
 is far better than, say:
 
 octal<"177">.value
 
 but when I compare it to
 
 0177
 
What about O!177?
template O(ulong i) { static if(i <= 7) enum O = i; else { static assert(i%10 < 8); enum O = O!(i/10)*8 + i%10; } } OTOH you cant do: O!17777777_7777777_7777777; as that overflows as a base 10 number but not as a octal number. -- ... <IXOYE><
Mar 25 2010
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 01:45 PM, Walter Bright wrote:
 Andrei Alexandrescu wrote:
 A: Use octal!"177"

 W: Ugh.

 A (esprit d'escalier): If you don't like the universal notation you
 invented, who will?
Good point. As I recall, we expended an enormous amount of effort working on template syntax, and I certainly feel that octal!"177" is far better than, say: octal<"177">.value but when I compare it to 0177 that's just hard to beat. A customized syntax is always going to be better than a generic one. The octal syntax is used in several widely popular languages, and is convenient and looks attractive. It's used a lot in dealing with the unix file system.
Symbolic constants are the best way to deal with the filesystem. It's not at all hard to beat. It would be if octal constants would be ubiquitous and ubiquitously useful. To disabuse yourself of that fallacious notion, PLEASE grep ALL your code for [^0-9A-Za-Z."%_:\]0[0-9] and let us know how many instances you find. druntime has 152 octal constants for a total of 53130 lines. That's one for each 350 lines of code, or less than 0.3%. Ironically, most occurrences are used in defining symbolic constants that are good style for handling permission bits. For Phobos I counted 11 true positives in 93,963 lines, which means one per 8542 lines of code or 0.01% of total. Andrei
Mar 25 2010
prev sibling parent "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hogavk$2ll7$1 digitalmars.com...
 Good point. As I recall, we expended an enormous amount of effort working 
 on template syntax, and I certainly feel that

     octal!"177"

 is far better than, say:

     octal<"177">.value

 but when I compare it to

     0177

 that's just hard to beat. A customized syntax is always going to be better 
 than a generic one.
I agree that "A customized syntax is always going to be better than a generic one", all else being equal (hence my distaste for the enum-related mixin stuff in other branches of this thread). But I still very much fail to see how anyone can consider being able to change a number's value simply by adding (or removing) a leading zero to be anywhere remotely near "hard to beat". Though I suppose we've already tread this ground 64 times before (oops, I mean "a hundred").
Mar 25 2010
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 12:18:57PM -0500, Andrei Alexandrescu wrote:
 I missed this. There's no need for anything close to that. We all could 
 get "upset" regarding a post or a notion, not against the person airing it.
 
 As far as the matter at hand of that thread is concerned, you mentioned 
 the possibility:
 
 alias Flags!(ubyte, "do_nothing",
                     "walk_dog"
                     "cook_breakfast"
                     "deliver_newspaper"
                     "visit_miss_kerbopple"
                     "wash_covers") Todo;
 
 I encourage you to code that up and see how it swims.
It just occurred to me that such a thing could work on the use-side exactly like the built in enum too, thanks to opDispatch. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 01:57 PM, Adam D. Ruppe wrote:
 On Thu, Mar 25, 2010 at 12:18:57PM -0500, Andrei Alexandrescu wrote:
 I missed this. There's no need for anything close to that. We all could
 get "upset" regarding a post or a notion, not against the person airing it.

 As far as the matter at hand of that thread is concerned, you mentioned
 the possibility:

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

 I encourage you to code that up and see how it swims.
It just occurred to me that such a thing could work on the use-side exactly like the built in enum too, thanks to opDispatch.
Exactly. Andrei
Mar 25 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:mailman.16.1269543119.2988.digitalmars-d puremagic.com...
 On Thu, Mar 25, 2010 at 12:18:57PM -0500, Andrei Alexandrescu wrote:
 I missed this. There's no need for anything close to that. We all could
 get "upset" regarding a post or a notion, not against the person airing 
 it.

 As far as the matter at hand of that thread is concerned, you mentioned
 the possibility:

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

 I encourage you to code that up and see how it swims.
It just occurred to me that such a thing could work on the use-side exactly like the built in enum too, thanks to opDispatch.
I haven't used opDispatch, and don't remember much from the discussions of it, so pardon a possibly dumb question: Would that prevent you from getting a (meaningful) compile-time error if you mis-typed one of the flags?
Mar 25 2010
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 03:34:06PM -0400, Nick Sabalausky wrote:
 I haven't used opDispatch, and don't remember much from the discussions of 
 it, so pardon a possibly dumb question: Would that prevent you from getting 
 a (meaningful) compile-time error if you mis-typed one of the flags?
A static assert would fire if the flag name given isn't in its internal table. The opDispatch function takes a string. It'd look something like this: ==== import std.stdio; struct Flags(T) { int opDispatch(string name)() { foreach(item; itemList) { if(name == item.name) return item.value; } static assert(0, "No such member: " ~ name); } struct Item { string name; T value; } Item[] itemList; } void main() { Flags!int a; int b = a.what; } === $ dmd -c test.d test.d(10): Error: static assert "No such member: what" The actual implementation of the Flags struct would be different to keep it all compile time (and of course, offer a constructor of sorts), but this show the idea and the error you can get. -- Adam D. Ruppe http://arsdnet.net
Mar 25 2010
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Mar 25, 2010 at 03:57:27PM -0400, Adam D. Ruppe wrote:

Gah, that would always trigger. It would actually need to have a helper
template and a constraint. So more along these lines:

T opDispatch(string name)() if (isValidName!(name)) {

}

Where the isValidName loops through it.

Poo, I make this mistake often. But the bright side is once this template
is written, you needn't rewrite it to get the goods when using it.

-- 
Adam D. Ruppe
http://arsdnet.net
Mar 25 2010
prev sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

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

 I encourage you to code that up and see how it swims. We need to stop  
 inventing syntax for any single thing that seems useful, and start  
 eating our dogfood. If our mechanism for code generation is not good  
 enough, we should improve it, not generate by hand ever new constructs.
template withType( alias F ) { template withType( alias s ) { enum withType = F!( typeof( s ) ); } } mixin template Flags_mixin( T, U, U value, string name, V... ) { // Does not work, due to std.metastrings.toStringNow not supporting ubyte. //mixin( Format!( "enum %s = T( %s );", name, value ) ); mixin( "enum " ~ name ~ " = T( " ~ to!string( value ) ~ " );" ); static if ( V.length > 0 ) { mixin Flags_mixin!( T, U, value + 1, V ); } } struct Flags( T = uint, U... ) if ( allSatisfy!( withType!( isSomeString ), U ) && isIntegral!( T ) ) { T value; mixin Flags_mixin!( typeof( this ), T, T.init, U ); } usage: void foo( ) { alias Flags!( ubyte, "a", "b", "c" ) myFlags; myFlags f = myFlags.a; writeln( f.value ); alias Flags!( "d", "e", "f" ) myOtherFlags; myOtherFlags } It could do with some sanity checking (valid identifier names), but as this was just a proof of concept, I have not written that. btw, I really wish OpenGL headers could use a mechanism like this. Having to look up every single function to see which flags are allowed can be a PITA. -- Simen
Mar 27 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/27/2010 09:02 AM, Simen kjaeraas wrote:
 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

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

 I encourage you to code that up and see how it swims. We need to stop
 inventing syntax for any single thing that seems useful, and start
 eating our dogfood. If our mechanism for code generation is not good
 enough, we should improve it, not generate by hand ever new constructs.
[snip implementation] Looks good, but there are a couple of things I'm worried about. One is that it generates many templates (as opposed to CTFE). But that's an implementation detail. What I think this is lacking is the ability to predefine flags that are a combination of other flags. For example, some file open flags could define DEFAULT_READ as READ|SHARED. I'm not sure how to express that. Andrei
Mar 28 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 What I think this is lacking is the ability to 
 predefine flags that are a combination of other flags. For example, some 
 file open flags could define DEFAULT_READ as READ|SHARED. I'm not sure 
 how to express that.
It's not an enum, it's a struct, that contains a single value (for example an uint). The construct defines at compile-time a property for each given name. Then the assign operator tests that the input can be any of the possible ORs of the flags, otherwise asserts in not release mode. So I think it can be done. But it will come out a good amount of CTFE code. Bye, bearophile
Mar 28 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
The construct defines at compile-time a property for each given name.<
A costant (enum) not a property, sorry. So this: alias Flags!q{ A, B, C } Foo; Becomes equivalent to: struct Foo { enum uint A = 1 << 0; enum uint B = 1 << 1; enum uint C = 1 << 2; private uint _data; // operators defined here, with full input tests: // = == | |= in & &= opBool ... } Foo f = Foo.A | Foo.B; Now f._data contains the or of the two flags... Bye, bearophile
Mar 28 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/28/2010 06:03 PM, bearophile wrote:
 The construct defines at compile-time a property for each given name.<
A costant (enum) not a property, sorry. So this: alias Flags!q{ A, B, C } Foo; Becomes equivalent to: struct Foo { enum uint A = 1<< 0; enum uint B = 1<< 1; enum uint C = 1<< 2; private uint _data; // operators defined here, with full input tests: // = == | |= in& &= opBool ... } Foo f = Foo.A | Foo.B; Now f._data contains the or of the two flags... Bye, bearophile
Yah but let's say A|B is used very often so I want to call it AB. How do I specify in the definition of Flags such a definition? I guess alias Flags!q{ A, B, C, AB = A|B } Foo; which makes parsing rather difficult. Andrei
Mar 28 2010
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 In D1, is there any reason I should be getting an error on this?:

 // module A:
 enum FooA { fooA };
 void bar(FooA x) {}

 // module B:
 import A;
 enum FooB { fooB };
 void bar(FooB x) {}

 bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
------- a.d ------------------- enum FooA { fooA }; void bar(FooA x) {} ------- test.d ---------------- import a; enum FooB { fooB }; void bar(FooB x) {} void test() { bar(FooB.fooB); } ------------------------------ with: dmd test I do not get an error with either D1 or D2. So, if you are getting an error, how is your code different?
Mar 24 2010
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hoepeu$28po$1 digitalmars.com...
 Nick Sabalausky wrote:
 In D1, is there any reason I should be getting an error on this?:

 // module A:
 enum FooA { fooA };
 void bar(FooA x) {}

 // module B:
 import A;
 enum FooB { fooB };
 void bar(FooB x) {}

 bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
------- a.d ------------------- enum FooA { fooA }; void bar(FooA x) {} ------- test.d ---------------- import a; enum FooB { fooB }; void bar(FooB x) {} void test() { bar(FooB.fooB); } ------------------------------ with: dmd test I do not get an error with either D1 or D2. So, if you are getting an error, how is your code different?
Hmm...That's odd...I guess I'll have to dig closer to see what's going on. The discussion on "D.learn" didn't seem to indicate that that above should work, so I hastily ruled out the possibility of something else going on in my code. It's too late for me to think stright ATM, so I'll have to check on that in the morning.
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 Hmm...That's odd...I guess I'll have to dig closer to see what's going on. 
 The discussion on "D.learn" didn't seem to indicate that that above should 
 work, so I hastily ruled out the possibility of something else going on in 
 my code. It's too late for me to think stright ATM, so I'll have to check on 
 that in the morning.
This kind of misunderstanding comes up all the time, it's why having exact reproducible snippets of code is so important! Often the critical detail is something that was omitted because the person thought it was either obvious or irrelevant.
Mar 25 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hofb6v$h5g$1 digitalmars.com...
 This kind of misunderstanding comes up all the time, it's why having exact 
 reproducible snippets of code is so important! Often the critical detail 
 is something that was omitted because the person thought it was either 
 obvious or irrelevant.
Yea, normally I'm in the habit of doing that for that very reason. Figures it would bite me the one time I don't. Anyway, this is what I'm doing, and it's giving me a conflict error on the call to 'bar' in 'main' with DMD 1.056 (fortunately, however, it seems to work fine in 2.042, so I guess the situation's improved in D2): // -------- separateLibrary.d -------- module separateLibrary; string makeFooBar(string name) { return " enum "~name~" { foo } void bar("~name~" e) {} "; } mixin(makeFooBar("FooA")); // -------- appModule.d -------- module appModule; import separateLibrary; mixin(makeFooBar("FooB")); // -------- main.d -------- module main; import separateLibrary; import appModule; void main() { bar(FooB.foo); // Error! 'bar' conflict } Compiled with "rdmd main"
Mar 25 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 Anyway, this is what I'm doing, and it's giving me a conflict error on the 
 call to 'bar' in 'main' with DMD 1.056 (fortunately, however, it seems to 
 work fine in 2.042, so I guess the situation's improved in D2):
The mixins obscure what is going on. The same error is reproduced with the simpler: --- a.d --- enum FooA { foo } void bar(FooA e) { } --- b.d --- enum FooB { foo } void bar(FooB e) { } --- test.d --- import a; import b; void main() { bar(FooB.foo); // Error! 'bar' conflict } -------------- D1 uses the earlier anti-hijacking system which disallows overloading of functions from different imports, unless they are specifically combined using an alias declaration. D2 improves this using Andrei's suggestion that such overloading be allowed if and only if functions from exactly one of those imports are potential matches. This is why the example code works on D2. If we change the declaration of bar in a.d to: --- a.d --- void bar(int e) { } ----------- then the compilation under D2 fails, because both a.bar and b.bar are now candidates, due to implicit conversion rules.
Mar 26 2010
prev sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 03/24/2010 11:40 PM, Walter Bright wrote:
 Nick Sabalausky wrote:
 In D1, is there any reason I should be getting an error on this?:

 // module A:
 enum FooA { fooA };
 void bar(FooA x) {}

 // module B:
 import A;
 enum FooB { fooB };
 void bar(FooB x) {}

 bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
------- a.d ------------------- enum FooA { fooA }; void bar(FooA x) {} ------- test.d ---------------- import a; enum FooB { fooB }; void bar(FooB x) {} void test() { bar(FooB.fooB); } ------------------------------ with: dmd test I do not get an error with either D1 or D2. So, if you are getting an error, how is your code different?
------- a.d ------------------- enum FooA { fooA }; void bar(FooA x) {} ------- test.d ---------------- import a; mixin(` enum FooB { fooB }; void bar(FooB x) {} `); void test() { bar(FooA.fooA); //error bar(FooB.fooB); } ------------------------------ ------- a.d ------------------- enum FooA { fooA }; void bar(FooA x) {} ------- test.d ---------------- import a; alias a.bar bar; mixin(` enum FooB { fooB }; void bar(FooB x) {} `); void test() { bar(FooA.fooA); bar(FooB.fooB); //error } ------------------------------ Somewhat OT: I wish enums had something analogous to struct's tupleof, or some way to enumerate the values of the enum, and maybe their names too. Do they?
Mar 25 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Ellery Newcomer:
 Somewhat OT: I wish enums had something analogous to struct's tupleof, 
 or some way to enumerate the values of the enum, and maybe their names 
 too. Do they?
D2 now gives you the tools to do that, even if it's bad looking code: import std.stdio: writeln; enum Foo { Aa, Bb, Cc } void main() { foreach (name; __traits(allMembers, Foo)) writeln(name, " ", mixin("cast(int)Foo." ~ name)); } Output: Aa 0 Bb 1 Cc 2 Bye, bearophile
Mar 25 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Ellery Newcomer wrote:
 On 03/24/2010 11:40 PM, Walter Bright wrote:
 Nick Sabalausky wrote:
 In D1, is there any reason I should be getting an error on this?:

 // module A:
 enum FooA { fooA };
 void bar(FooA x) {}

 // module B:
 import A;
 enum FooB { fooB };
 void bar(FooB x) {}

 bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
------- a.d ------------------- enum FooA { fooA }; void bar(FooA x) {} ------- test.d ---------------- import a; enum FooB { fooB }; void bar(FooB x) {} void test() { bar(FooB.fooB); } ------------------------------ with: dmd test I do not get an error with either D1 or D2. So, if you are getting an error, how is your code different?
------- a.d ------------------- enum FooA { fooA }; void bar(FooA x) {} ------- test.d ---------------- import a; mixin(` enum FooB { fooB }; void bar(FooB x) {} `); void test() { bar(FooA.fooA); //error bar(FooB.fooB); } ------------------------------
This error is quite correct (and happens with or without the mixin). The idea is if you define a function in a local scope, it *completely hides* functions with the same name in imported scopes. In order to overload local functions with imported ones, an alias is necessary to bring the imported functions into the same scope. This allows the user complete control over which functions get overloaded when they come from diverse, and possibly completely independent, imports.
 ------- a.d -------------------
 enum FooA { fooA };
 void bar(FooA x) {}
 ------- test.d ----------------
 import a;
 alias a.bar bar;
 mixin(`
 enum FooB { fooB };
 void bar(FooB x) {}
 `);
 
 void test()
 {
     bar(FooA.fooA);
     bar(FooB.fooB); //error
 }
 ------------------------------
I'm not sure why this error is happening, it definitely has something to do with the mixin. Let me look into it some more.
Mar 25 2010
next sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 03/25/2010 02:00 PM, Walter Bright wrote:
 ------- a.d -------------------
 enum FooA { fooA };
 void bar(FooA x) {}
 ------- test.d ----------------
 import a;
 mixin(`
 enum FooB { fooB };
 void bar(FooB x) {}
 `);

 void test()
 {
 bar(FooA.fooA); //error
 bar(FooB.fooB);
 }
 ------------------------------
This error is quite correct (and happens with or without the mixin). The idea is if you define a function in a local scope, it *completely hides* functions with the same name in imported scopes. In order to overload local functions with imported ones, an alias is necessary to bring the imported functions into the same scope.
I know. It was my understanding that this entire thread was a complaint of this behavior.
 This allows the user complete control over which functions get
 overloaded when they come from diverse, and possibly completely
 independent, imports.
It's a very explicit form of control. Suppose I have 10 000 enums (I don't have quite that many, but there are a lot), each of which is in a different module because each is logically connected to something else. Because enums in D are too spartan for my tastes, I define a mixin to generate an enum, along with several helper functions, like name, fromInt, toInt, etc. (Note that a way to enumerate an enum's values would obviate all this, and __traits isn't an option in D1) It's my understanding that enums are strongly enough typed that calling such a helper function with an enum (or anything else) not defined for it would generate an error. So there shouldn't be any way to hijack it. But if I have some enum A defined in my current module and I also want to use enums modl2.B, modl3.C, etc, then I have to manually add all those alias modl2.name name; <poke> or else write an IDE tool that automatically generates them for me </poke> I guess what I'm trying to say is it doesn't make sense that I can implicitly import FooA, an external symbol, but not bar(FooA), an external symbol defined on an external symbol which cannot be implicitly converted to a local symbol.
 ------- a.d -------------------
 enum FooA { fooA };
 void bar(FooA x) {}
 ------- test.d ----------------
 import a;
 alias a.bar bar;
 mixin(`
 enum FooB { fooB };
 void bar(FooB x) {}
 `);

 void test()
 {
 bar(FooA.fooA);
 bar(FooB.fooB); //error
 }
 ------------------------------
I'm not sure why this error is happening, it definitely has something to do with the mixin. Let me look into it some more.
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Ellery Newcomer wrote:
 I guess what I'm trying to say is it doesn't make sense that I can 
 implicitly import FooA, an external symbol, but not bar(FooA), an 
 external symbol defined on an external symbol which cannot be implicitly 
 converted to a local symbol.
And I believe it makes perfect sense! Everywhere else in the language, when you define a local name it *overrides* names in other scopes, it doesn't overload them.
Mar 25 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hogmgm$oco$1 digitalmars.com...
 Ellery Newcomer wrote:
 I guess what I'm trying to say is it doesn't make sense that I can 
 implicitly import FooA, an external symbol, but not bar(FooA), an 
 external symbol defined on an external symbol which cannot be implicitly 
 converted to a local symbol.
And I believe it makes perfect sense! Everywhere else in the language, when you define a local name it *overrides* names in other scopes, it doesn't overload them.
Well, the result of that is that I'm forced to make my "genEnum" library utility generate "enum{name of enum}ToString({name of enum} e)" instead of "enumToString({name of enum} e)" or else users won't be able to use it without a bunch of odd alias contortions that I'm not sure I can wave away by including them in the original mixin. (I would have just called it "toString", but at the time, that had been giving me some strange troubles so I changed it to "enumToString" instead. In retrospect, it was probably giving me trouble because of this very same issue.) Of course, I can live with this as long as it's fixed in D2 (as seemed to be the case from the three-module test code I put in another post). But now that you're saying this I'm confused as to why that example I posted suddenly worked when I compiled it with D2.
Mar 25 2010
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 But now 
 that you're saying this I'm confused as to why that example I posted 
 suddenly worked when I compiled it with D2.
I haven't looked at that yet, just discussed the principle.
Mar 25 2010
prev sibling parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 03/25/2010 05:26 PM, Nick Sabalausky wrote:
 "Walter Bright"<newshound1 digitalmars.com>  wrote in message
 news:hogmgm$oco$1 digitalmars.com...
 Ellery Newcomer wrote:
 I guess what I'm trying to say is it doesn't make sense that I can
 implicitly import FooA, an external symbol, but not bar(FooA), an
 external symbol defined on an external symbol which cannot be implicitly
 converted to a local symbol.
And I believe it makes perfect sense! Everywhere else in the language, when you define a local name it *overrides* names in other scopes, it doesn't overload them.
Well, the result of that is that I'm forced to make my "genEnum" library utility generate "enum{name of enum}ToString({name of enum} e)" instead of "enumToString({name of enum} e)" or else users won't be able to use it without a bunch of odd alias contortions that I'm not sure I can wave away by including them in the original mixin. (I would have just called it "toString", but at the time, that had been giving me some strange troubles so I changed it to "enumToString" instead. In retrospect, it was probably giving me trouble because of this very same issue.)
Suggestion: forget about enums. Implement something based on structs or classes a la Java, which gives you e.toString instead of toString(e) From this conversation, I'm getting the idea that enums are more an antifeature than anything. And you're using mixins already anyways.
Mar 25 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Walter Bright wrote:
 I'm not sure why this error is happening, it definitely has something to 
 do with the mixin. Let me look into it some more.
Bug report and fix: http://d.puremagic.com/issues/show_bug.cgi?id=4011
Mar 26 2010
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 03/26/2010 02:01 PM, Walter Bright wrote:
 Walter Bright wrote:
 I'm not sure why this error is happening, it definitely has something
 to do with the mixin. Let me look into it some more.
Bug report and fix: http://d.puremagic.com/issues/show_bug.cgi?id=4011
Awesome!
Mar 26 2010
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Nick Sabalausky wrote:
 To put it simply, I agree with this even on mere principle. I'm convinced 
 that the current D behavior is a blatant violation of strong-typing and 
 smacks way too much of C's so-called "type system".
You're certainly not the first to feel this way about implicit conversions. Niklaus Wirth did the same, and designed Pascal with no implicit conversions. You had to do an explicit cast each time. Man, what a royal pain in the ass that makes coding in Pascal. Straightforward coding, like converting a string of digits to an integer, becomes a mess of casts. Even worse, casts are a blunt instrument that *destroys* type checking (that wasn't so much of a problem with Pascal with its stone age abstract types, but it would be killer for D). Implicit integral conversions are not without problems, but when I found C I threw Pascal under the nearest bus and never wrote a line in it again. The taste was so bad, I refused to even look at Modula II and its failed successors. D has 12 integral types. Disabling implicit integral conversions would make it unbearable to use.
Mar 24 2010
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hoeukp$2kgv$1 digitalmars.com...
 Nick Sabalausky wrote:
 To put it simply, I agree with this even on mere principle. I'm convinced 
 that the current D behavior is a blatant violation of strong-typing and 
 smacks way too much of C's so-called "type system".
You're certainly not the first to feel this way about implicit conversions. Niklaus Wirth did the same, and designed Pascal with no implicit conversions. You had to do an explicit cast each time. Man, what a royal pain in the ass that makes coding in Pascal. Straightforward coding, like converting a string of digits to an integer, becomes a mess of casts. Even worse, casts are a blunt instrument that *destroys* type checking (that wasn't so much of a problem with Pascal with its stone age abstract types, but it would be killer for D). Implicit integral conversions are not without problems, but when I found C I threw Pascal under the nearest bus and never wrote a line in it again. The taste was so bad, I refused to even look at Modula II and its failed successors. D has 12 integral types. Disabling implicit integral conversions would make it unbearable to use.
Oh, I absolutely agree that implicit conversions are good in certain cases. I was only referring to implicit conversions between enums and the enum's base type (regardless of direction).
Mar 25 2010
prev sibling next sibling parent reply yigal chripun <yigal100 gmail.com> writes:
Walter Bright Wrote:

 Nick Sabalausky wrote:
 To put it simply, I agree with this even on mere principle. I'm convinced 
 that the current D behavior is a blatant violation of strong-typing and 
 smacks way too much of C's so-called "type system".
You're certainly not the first to feel this way about implicit conversions. Niklaus Wirth did the same, and designed Pascal with no implicit conversions. You had to do an explicit cast each time. Man, what a royal pain in the ass that makes coding in Pascal. Straightforward coding, like converting a string of digits to an integer, becomes a mess of casts. Even worse, casts are a blunt instrument that *destroys* type checking (that wasn't so much of a problem with Pascal with its stone age abstract types, but it would be killer for D). Implicit integral conversions are not without problems, but when I found C I threw Pascal under the nearest bus and never wrote a line in it again. The taste was so bad, I refused to even look at Modula II and its failed successors. D has 12 integral types. Disabling implicit integral conversions would make it unbearable to use.
here's a simple version without casts: int toString(dchar[] arr) { int temp = 0; for (int i = 0; i < arr.length; i++) { int digit = arr[i].valueOf - 30; // * if (digit < 0 || digit > 9) break; temp += 10^^i * digit; } return temp; } [*] Assume that dchar has a valueOf property that returns the value. where's that mess of casts you mention? Pascal is hardly the only language without excplicit casts. ML is also properly strongly typed and is an awesome language to use. The fact that D has 12 integral types is a bad design, why do we need so many built in types? to me this clearly shows a need to refactor this aspect of D.
Mar 25 2010
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
yigal chripun wrote:
 here's a simple version without casts: int toString(dchar[] arr) { int temp =
 0; for (int i = 0; i < arr.length; i++) { int digit = arr[i].valueOf - 30; //
 * if (digit < 0 || digit > 9) break; temp += 10^^i * digit; } return temp; }
 
 [*] Assume that dchar has a valueOf property that returns the value.
 
 where's that mess of casts you mention?
In Pascal, you'd have type errors all over the place. First off, you cannot do arithmetic on characters. You have to cast them to integers (with the ORD(c) construction).
 Pascal is hardly the only language without excplicit casts.
Pascal has explicit casts. The integer to character one is CHR(i), the character to integer is ORD(c).
 ML is also
 properly strongly typed and is an awesome language to use.
I don't know enough about ML to comment intelligently on it.
 The fact that D has 12 integral types is a bad design, why do we need so many
 built in types? to me this clearly shows a need to refactor this aspect of D.
Which would you get rid of? (13, I forgot bool!) bool byte ubyte short ushort int uint long ulong char wchar dchar enum
Mar 25 2010
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Walter Bright Wrote:

 yigal chripun wrote:
 here's a simple version without casts: int toString(dchar[] arr) { int temp =
 0; for (int i = 0; i < arr.length; i++) { int digit = arr[i].valueOf - 30; //
 * if (digit < 0 || digit > 9) break; temp += 10^^i * digit; } return temp; }
 
 [*] Assume that dchar has a valueOf property that returns the value.
 
 where's that mess of casts you mention?
In Pascal, you'd have type errors all over the place. First off, you cannot do arithmetic on characters. You have to cast them to integers (with the ORD(c) construction).
 Pascal is hardly the only language without excplicit casts.
Pascal has explicit casts. The integer to character one is CHR(i), the character to integer is ORD(c).
I meant implicit, sorry about that. The pascal way is definitely the correct way. what's the semantics in your opinion of ('f' + 3) ? what about ('?' + 4)? making such arithmetic valid is wrong. I'm sure that the first Pascal versions had problems which caused you to ditch that language (they where fixed later). I doubt it though that this had a large impact on Pascal's problems.
 
 ML is also
 properly strongly typed and is an awesome language to use.
I don't know enough about ML to comment intelligently on it.
 The fact that D has 12 integral types is a bad design, why do we need so many
 built in types? to me this clearly shows a need to refactor this aspect of D.
Which would you get rid of? (13, I forgot bool!) bool byte ubyte short ushort int uint long ulong char wchar dchar enum
you forgot the cent and ucent types and what about 256bit types? Here's How I'd want it designed: First of, a Boolean type should not belong to this list at all and shouldn't be treated as a numeric type. Second, there really only few use-cases that are relevant signed types for representing numbers: 1) unlimited integral type - int 2) limited integral type - int!(bits), e.g. int!16, int!8, etc.. 3) user defined range: e.g. [0, infinity) for positive numbers, etc.. unsigned bit-packs: 4) bits!(size), e.g. bits!8, bits!32, etc.. of course you can define useful aliases, e.g. alias bits!8 Byte; alias bits!16 Word; .. or you can define the aliases per the architecture, so that Word above will be defined for the current arch (I don't know what's the native word size on say ARM and other platforms) char and relatives should be for text only per Unicode, (perhaps a better name is code-point). for other encodings use the above bit packs, e.g. alias bits!7 Ascii; alias bits!8 ExtendedAscii; etc.. enum should be an enumeration type. You can find an excellent strongly-typed design in Java 5.0
Mar 25 2010
next sibling parent BCS <none anon.com> writes:
Hello Yigal,

 I meant implicit, sorry about that. The pascal way is definitely the
 correct way. 
Wrong. It is not "definitely" the correct way because there are many smart people who disagree. It might *be* the correct way, but it that has yet to be shown.
 what's the semantics in your opinion of ('f' + 3) ? what
 about ('?' + 4)? making such arithmetic valid is wrong.
The above will depend on the underlying system (because we are talking D, that would be UTF). The first will result in the value three grater than the value used to represent 'f' (in UTF, 'i'). The same happens for the second with suitable substations.
 The fact that D has 12 integral types is a bad design, why do we
 need so many built in types? to me this clearly shows a need to
 refactor this aspect of D.
 
Which would you get rid of? (13, I forgot bool!) bool byte ubyte short ushort int uint long ulong char wchar dchar enum
you forgot the cent and ucent types and what about 256bit types? Here's How I'd want it designed: First of, a Boolean type should not belong to this list at all and shouldn't be treated as a numeric type.
Agree, and it isn't for the most part.
 
 Second, there really only few use-cases that are relevant
 
 signed types for representing numbers:
 1) unlimited integral type - int
Very rare and expensive. This, IMHO, should not be a built in type
 3) user defined range: e.g. [0, infinity) for positive numbers, etc..
Also rare and expensive for most uses. Again, not built in. [reordered a bit]
 2) limited integral type  - int!(bits), e.g. int!16, int!8, etc..
 unsigned bit-packs:
 4) bits!(size), e.g. bits!8, bits!32, etc..
This would make it look like int!13 and int!16 are both valid and similarly costly. If you do make int!13 valid how will it pack in arrays? (Hint: if it doesn't pack, I see no more value in it than in a range type, see comment to item 3) Will you be able to take a pointer to any element? (Hint: the problems with that are why D dropped the bit type.) When you get right down to it, the types supported by hardware are fairly standard (8,16,32,64,... bits signed and unsigned) so why shouldn't the language support them directly? I will grant that there are reasons to do what you are suggesting, but I don't think they are valid reason with regards to the language the D is trying to be.
 of course you can define useful aliases, e.g.
 alias bits!8 Byte;
 alias bits!16 Word;
 ..
 or you can define the aliases per the architecture, so that Word above
 will be defined for the current arch (I don't know what's the native
 word size on say ARM and other platforms)
C more or less has that with int. That D dropped the "what size is int" problem is a good thing in my book.
 char and relatives should be for text only per Unicode, (perhaps a
 better name is code-point). for other encodings use the above bit
 packs, e.g.
 
 alias bits!7 Ascii;
 
 alias bits!8 ExtendedAscii;
 
 etc..
D defines text to be unicode. Unicode is a sequence of numbers. It's all well defined and whatnot so allowing the programmer to handle them as numbers is a must as far as I'm concerned. Finally, none of that part about integers has anything to do with implicit casts. If anything, it would make it harder as you now have even more types, not less.
 
 enum should be an enumeration type. You can find an excellent
 strongly-typed  design in Java 5.0
 
-- ... <IXOYE><
Mar 25 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Yigal Chripun wrote:
 Walter Bright Wrote:
 Pascal has explicit casts. The integer to character one is CHR(i), the
 character to integer is ORD(c).
I meant implicit, sorry about that. The pascal way is definitely the correct way. what's the semantics in your opinion of ('f' + 3) ? what about ('?' + 4)? making such arithmetic valid is wrong.
Yes, that is exactly the opinion of Pascal. As I said, I've programmed in Pascal, suffered as it blasted my kingdom, and I don't wish to do that again. I see no use in pretending '?' does not have a numerical value that is very useful to manipulate.
 I'm sure that the first Pascal
 versions had problems which caused you to ditch that language (they where
 fixed later).
They weren't compiler bugs I was wrestling with. They were fundamental design decisions of the language.
 I doubt it though that this had a large impact on Pascal's
 problems.
I don't agree. Pascal was a useless language as designed. This meant that every vendor added many incompatible extensions. Anyone who used Pascal got locked into a particular vendor. That killed it.
 The fact that D has 12 integral types is a bad design, why do we need so
 many built in types? to me this clearly shows a need to refactor this
 aspect of D.
Which would you get rid of? (13, I forgot bool!) bool byte ubyte short ushort int uint long ulong char wchar dchar enum
you forgot the cent and ucent types and what about 256bit types?
They are reserved, not implemented, so I left them out. In or out, they don't change the point.
 Here's How I'd want it designed: First of, a Boolean type should not belong
 to this list at all and shouldn't be treated as a numeric type. Second, there
 really only few use-cases that are relevant
 
 signed types for representing numbers: 1) unlimited integral type - int 2)
 limited integral type  - int!(bits), e.g. int!16, int!8, etc.. 3) user
 defined range: e.g. [0, infinity) for positive numbers, etc..
 
 unsigned bit-packs: 4) bits!(size), e.g. bits!8, bits!32, etc..
 
 of course you can define useful aliases, e.g. alias bits!8 Byte; alias
 bits!16 Word; .. or you can define the aliases per the architecture, so that
 Word above will be defined for the current arch (I don't know what's the
 native word size on say ARM and other platforms)
People are going to quickly tire of writing: bits!8 b; bits!16 s; and are going to use aliases: alias bits!8 ubyte; alias bits!16 ushort; Naturally, either everyone invents their own aliases (like they do in C with its indeterminate int sizes), or they are standardized, in which case we're back to pretty much exactly the same point we are at now. I don't see where anything was accomplished.
 char and relatives should be for text only per Unicode, (perhaps a better
 name is code-point).
There have been many proposals to try and hide the fact that UTF-8 is really a multibyte encoding, but that makes for some pretty inefficient code in too many cases.
 for other encodings use the above bit packs, e.g. alias
 bits!7 Ascii; alias bits!8 ExtendedAscii; etc..
 
 enum should be an enumeration type. You can find an excellent strongly-typed
 design in Java 5.0
Those enums are far more heavyweight - they are a syntactic sugar around a class type complete with methods, interfaces, constructors, etc. They aren't even compile time constants! If you need those in D, it wouldn't be hard at all to make a library class template that does the same thing.
Mar 25 2010
parent reply yigal chripun <yigal100 gmail.com> writes:
Walter Bright Wrote:

 Yigal Chripun wrote:
 Walter Bright Wrote:
 Pascal has explicit casts. The integer to character one is CHR(i), the
 character to integer is ORD(c).
I meant implicit, sorry about that. The pascal way is definitely the correct way. what's the semantics in your opinion of ('f' + 3) ? what about ('?' + 4)? making such arithmetic valid is wrong.
Yes, that is exactly the opinion of Pascal. As I said, I've programmed in Pascal, suffered as it blasted my kingdom, and I don't wish to do that again. I see no use in pretending '?' does not have a numerical value that is very useful to manipulate.
'?' indeed does *not* have a single numerical value that identiies it in a unique manner. You can map it to different numeric values based on encoding and even within the same encoding this doesn't always hold. See normalization in Unicode for different encodings for the same character.
 I'm sure that the first Pascal
 versions had problems which caused you to ditch that language (they where
 fixed later).
They weren't compiler bugs I was wrestling with. They were fundamental design decisions of the language.
 I doubt it though that this had a large impact on Pascal's
 problems.
I don't agree. Pascal was a useless language as designed. This meant that every vendor added many incompatible extensions. Anyone who used Pascal got locked into a particular vendor. That killed it.
 The fact that D has 12 integral types is a bad design, why do we need so
 many built in types? to me this clearly shows a need to refactor this
 aspect of D.
Which would you get rid of? (13, I forgot bool!) bool byte ubyte short ushort int uint long ulong char wchar dchar enum
you forgot the cent and ucent types and what about 256bit types?
They are reserved, not implemented, so I left them out. In or out, they don't change the point.
 Here's How I'd want it designed: First of, a Boolean type should not belong
 to this list at all and shouldn't be treated as a numeric type. Second, there
 really only few use-cases that are relevant
 
 signed types for representing numbers: 1) unlimited integral type - int 2)
 limited integral type  - int!(bits), e.g. int!16, int!8, etc.. 3) user
 defined range: e.g. [0, infinity) for positive numbers, etc..
 
 unsigned bit-packs: 4) bits!(size), e.g. bits!8, bits!32, etc..
 
 of course you can define useful aliases, e.g. alias bits!8 Byte; alias
 bits!16 Word; .. or you can define the aliases per the architecture, so that
 Word above will be defined for the current arch (I don't know what's the
 native word size on say ARM and other platforms)
People are going to quickly tire of writing: bits!8 b; bits!16 s; and are going to use aliases: alias bits!8 ubyte; alias bits!16 ushort; Naturally, either everyone invents their own aliases (like they do in C with its indeterminate int sizes), or they are standardized, in which case we're back to pretty much exactly the same point we are at now. I don't see where anything was accomplished.
Not true. say I'm using my own proprietary hardware and I want to have bits!24. How would I do that in current D? what if new hardware adds support for larger vector ops and 512bit registers, will we now need to extend the language with another type? On the flip side of this, programmers almost always will need just an int since they need the mathematical notion of an integral type. Iit's prtty rare when programmers want something other than int and in those cases they'll define thir own types anyway since they know what their requirements are.
 
 char and relatives should be for text only per Unicode, (perhaps a better
 name is code-point).
There have been many proposals to try and hide the fact that UTF-8 is really a multibyte encoding, but that makes for some pretty inefficient code in too many cases.
I'm not saying we should hide that, on the contrary, the compiler should enforce unicode and other encodings should use a bits type instead. a [w|d]char must always contain a valid unicode value. calling char[] a string is wrong since it is actually an array of code-points which is not always a valid encoding. a dchar[] is however a valid string since each individual dchar contains a full code-unit.
 
 for other encodings use the above bit packs, e.g. alias
 bits!7 Ascii; alias bits!8 ExtendedAscii; etc..
 
 enum should be an enumeration type. You can find an excellent strongly-typed
 design in Java 5.0
Those enums are far more heavyweight - they are a syntactic sugar around a class type complete with methods, interfaces, constructors, etc. They aren't even compile time constants! If you need those in D, it wouldn't be hard at all to make a library class template that does the same thing.
They aren't that heavy weight. Instead of assigning an int to each symbol you assign a pointer address which is the same size. Regarding the compile time property: for an int type: const int a = 5; //compile time the same should apply to enums as well. The problem with the library solution is that it can't provide the syntax sugar for this.
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
yigal chripun wrote:
 Walter Bright Wrote:
 
 Yigal Chripun wrote:
 Walter Bright Wrote:
 Pascal has explicit casts. The integer to character one is CHR(i), the 
 character to integer is ORD(c).
I meant implicit, sorry about that. The pascal way is definitely the correct way. what's the semantics in your opinion of ('f' + 3) ? what about ('?' + 4)? making such arithmetic valid is wrong.
Yes, that is exactly the opinion of Pascal. As I said, I've programmed in Pascal, suffered as it blasted my kingdom, and I don't wish to do that again. I see no use in pretending '?' does not have a numerical value that is very useful to manipulate.
'?' indeed does *not* have a single numerical value that identiies it in a unique manner. You can map it to different numeric values based on encoding and even within the same encoding this doesn't always hold. See normalization in Unicode for different encodings for the same character.
That's true, '?' can have different encodings, such as for EBCDIC and RADIX50. Those formats are dead, however, and ASCII has won. D is specifically a Unicode language (a superset of ASCII) and '?' has a single defined value for it. Yes, Unicode has some oddities about it, and the poor programmer using those characters will have to deal with it, but that does not change that quoted character literals are always the same numerical value. '?' is not going to change to another one tomorrow or in any conceivable future incarnation of Unicode.
 Naturally, either everyone invents their own aliases (like they do in C
 with its indeterminate int sizes), or they are standardized, in which case
 we're back to pretty much exactly the same point we are at now. I don't see
 where anything was accomplished.
 
Not true. say I'm using my own proprietary hardware and I want to have bits!24. How would I do that in current D?
You'd be on your own with that. I had a discussion recently with a person who defended C's notion of compiler defined integer sizes, pointing out that this enabled compliant C compilers to be written for DSLs with 32 bit bytes. That is pedantically correct, compliant C compilers were written for it. Unfortunately, practically no C applications could be ported to it without extensive modification! For your 24 bit machine, you will be forced to write all your own custom software, even if the D specification supported it.
 what if new hardware adds support
 for larger vector ops and 512bit registers, will we now need to extend the
 language with another type?
D will do something to accommodate it, obviously we don't know what that will be until we see what those types are and what they do. What I don't see is using 512 bit ints for normal use.
 char and relatives should be for text only per Unicode, (perhaps a better
  name is code-point).
There have been many proposals to try and hide the fact that UTF-8 is really a multibyte encoding, but that makes for some pretty inefficient code in too many cases.
I'm not saying we should hide that, on the contrary, the compiler should enforce unicode and other encodings should use a bits type instead. a [w|d]char must always contain a valid unicode value. calling char[] a string is wrong since it is actually an array of code-points which is not always a valid encoding. a dchar[] is however a valid string since each individual dchar contains a full code-unit.
Conceptually, I agree, it's wrong, but it's not practical to force the issue.
 enum should be an enumeration type. You can find an excellent
 strongly-typed design in Java 5.0
Those enums are far more heavyweight - they are a syntactic sugar around a class type complete with methods, interfaces, constructors, etc. They aren't even compile time constants! If you need those in D, it wouldn't be hard at all to make a library class template that does the same thing.
They aren't that heavy weight. Instead of assigning an int to each symbol you assign a pointer address which is the same size.
No, it's not the same. A compile time constant has many advantages over a runtime one. Java creates an inner class for each enum member, not just the enum itself! It's heavyweight.
 Regarding the compile time
 property: for an int type: const int a = 5; //compile time the same should
 apply to enums as well.
Having a runtime pointer to an inner class for each enum value is far from the advantages of a compile time constant.
 The problem with the library solution is that it can't provide the syntax
 sugar for this.
It can get pretty close. Java has poor abstraction facilities, and so building it into the language was the only solution.
Mar 25 2010
parent reply yigal chripun <yigal100 gmail.com> writes:
It seems that on a conceptual level we are in complete agreement. 
the difference seems to be that you want to push some things onto the user
which I think the language should provide.

Walter Bright Wrote:

 yigal chripun wrote:
 Walter Bright Wrote:
 
 Yigal Chripun wrote:
 Walter Bright Wrote:
 Pascal has explicit casts. The integer to character one is CHR(i), the 
 character to integer is ORD(c).
I meant implicit, sorry about that. The pascal way is definitely the correct way. what's the semantics in your opinion of ('f' + 3) ? what about ('?' + 4)? making such arithmetic valid is wrong.
Yes, that is exactly the opinion of Pascal. As I said, I've programmed in Pascal, suffered as it blasted my kingdom, and I don't wish to do that again. I see no use in pretending '?' does not have a numerical value that is very useful to manipulate.
'?' indeed does *not* have a single numerical value that identiies it in a unique manner. You can map it to different numeric values based on encoding and even within the same encoding this doesn't always hold. See normalization in Unicode for different encodings for the same character.
That's true, '?' can have different encodings, such as for EBCDIC and RADIX50. Those formats are dead, however, and ASCII has won. D is specifically a Unicode language (a superset of ASCII) and '?' has a single defined value for it. Yes, Unicode has some oddities about it, and the poor programmer using those characters will have to deal with it, but that does not change that quoted character literals are always the same numerical value. '?' is not going to change to another one tomorrow or in any conceivable future incarnation of Unicode.
while it's true that '?' has one unicode value for it, it's not true for all sorts of diacritics and combine code-points. So your approach is to pass the responsibility for that to the end user which in 99.9999% will not handle this correctlly.
 Naturally, either everyone invents their own aliases (like they do in C
 with its indeterminate int sizes), or they are standardized, in which case
 we're back to pretty much exactly the same point we are at now. I don't see
 where anything was accomplished.
 
Not true. say I'm using my own proprietary hardware and I want to have bits!24. How would I do that in current D?
You'd be on your own with that. I had a discussion recently with a person who defended C's notion of compiler defined integer sizes, pointing out that this enabled compliant C compilers to be written for DSLs with 32 bit bytes. That is pedantically correct, compliant C compilers were written for it. Unfortunately, practically no C applications could be ported to it without extensive modification! For your 24 bit machine, you will be forced to write all your own custom software, even if the D specification supported it.
I completely agree with you that the C notion isn't good for integral types. It would only make sense when you use bits kind of type, where you'd see size_t in D (not common in user code). Of course any software that depends on a specifc size, e.g. bits!32 will need to be extensively modified if it's ported to an arch which requires a different size. But I'm talking about the need to define bits!(T) myself instead of having it in the standard library.
 
 what if new hardware adds support
 for larger vector ops and 512bit registers, will we now need to extend the
 language with another type?
D will do something to accommodate it, obviously we don't know what that will be until we see what those types are and what they do. What I don't see is using 512 bit ints for normal use.
There's another issue here and that's all those types are special cases in the compiler and handled separately from library types. Had the stdlib provided the templeted types it would have allowed to use them in more generic ways instead of special caseing them everywhere.
 
 
 char and relatives should be for text only per Unicode, (perhaps a better
  name is code-point).
There have been many proposals to try and hide the fact that UTF-8 is really a multibyte encoding, but that makes for some pretty inefficient code in too many cases.
I'm not saying we should hide that, on the contrary, the compiler should enforce unicode and other encodings should use a bits type instead. a [w|d]char must always contain a valid unicode value. calling char[] a string is wrong since it is actually an array of code-points which is not always a valid encoding. a dchar[] is however a valid string since each individual dchar contains a full code-unit.
Conceptually, I agree, it's wrong, but it's not practical to force the issue.
 
 
 enum should be an enumeration type. You can find an excellent
 strongly-typed design in Java 5.0
Those enums are far more heavyweight - they are a syntactic sugar around a class type complete with methods, interfaces, constructors, etc. They aren't even compile time constants! If you need those in D, it wouldn't be hard at all to make a library class template that does the same thing.
They aren't that heavy weight. Instead of assigning an int to each symbol you assign a pointer address which is the same size.
No, it's not the same. A compile time constant has many advantages over a runtime one. Java creates an inner class for each enum member, not just the enum itself! It's heavyweight.
 Regarding the compile time
 property: for an int type: const int a = 5; //compile time the same should
 apply to enums as well.
Having a runtime pointer to an inner class for each enum value is far from the advantages of a compile time constant.
I don't understand this point - can't the inner class be put in the data segment? Also, why not use structs instead of classes?
 
 The problem with the library solution is that it can't provide the syntax
 sugar for this.
It can get pretty close. Java has poor abstraction facilities, and so building it into the language was the only solution.
how close can it get? I don't mind having this in the stdlib instead of in the language if it's pleasent enough on the eyes.
Mar 25 2010
parent reply KennyTM~ <kennytm gmail.com> writes:
On Mar 26, 10 05:46, yigal chripun wrote:
 while it's true that '?' has one unicode value for it, it's not true for all
sorts of diacritics and combine code-points. So your approach is to pass the
responsibility for that to the end user which in 99.9999% will not handle this
correctlly.
Non-issue. Since when can a character literal store > 1 code-point?
Mar 25 2010
next sibling parent reply yigal chripun <yigal100 gmail.com> writes:
KennyTM~ Wrote:

 On Mar 26, 10 05:46, yigal chripun wrote:
 while it's true that '?' has one unicode value for it, it's not true for all
sorts of diacritics and combine code-points. So your approach is to pass the
responsibility for that to the end user which in 99.9999% will not handle this
correctlly.
Non-issue. Since when can a character literal store > 1 code-point?
character != code-point D chars are really as you say code-points and not always complete characters. here's a use case for you: you want to write a fully unicode aware search engine. If you just try to match the given sequnce of code-points in the search term, you will miss valid matches since, for instance you do not take into account permutations of the order of combining marks. you can't just assume that the code-point value identifies the character.
Mar 26 2010
parent reply KennyTM~ <kennytm gmail.com> writes:
On Mar 26, 10 18:52, yigal chripun wrote:
 KennyTM~ Wrote:

 On Mar 26, 10 05:46, yigal chripun wrote:
 while it's true that '?' has one unicode value for it, it's not true for all
sorts of diacritics and combine code-points. So your approach is to pass the
responsibility for that to the end user which in 99.9999% will not handle this
correctlly.
Non-issue. Since when can a character literal store> 1 code-point?
character != code-point D chars are really as you say code-points and not always complete characters. here's a use case for you: you want to write a fully unicode aware search engine. If you just try to match the given sequnce of code-points in the search term, you will miss valid matches since, for instance you do not take into account permutations of the order of combining marks. you can't just assume that the code-point value identifies the character.
Stop being off-topic. '?' is of type char, not string. A char always holds an octet of UTF-8 encoded sequence. The numerical content is unique and well-defined*. Therefore adding 4 to '?' also has a meaning. * If you're paranoid you may request the spec to ensure the character is in NFC form.
Mar 26 2010
parent reply Yigal Chripun <yigal100 gmail.com> writes:
KennyTM~ Wrote:

 On Mar 26, 10 18:52, yigal chripun wrote:
 KennyTM~ Wrote:

 On Mar 26, 10 05:46, yigal chripun wrote:
 while it's true that '?' has one unicode value for it, it's not true for all
sorts of diacritics and combine code-points. So your approach is to pass the
responsibility for that to the end user which in 99.9999% will not handle this
correctlly.
Non-issue. Since when can a character literal store> 1 code-point?
character != code-point D chars are really as you say code-points and not always complete characters. here's a use case for you: you want to write a fully unicode aware search engine. If you just try to match the given sequnce of code-points in the search term, you will miss valid matches since, for instance you do not take into account permutations of the order of combining marks. you can't just assume that the code-point value identifies the character.
Stop being off-topic. '?' is of type char, not string. A char always holds an octet of UTF-8 encoded sequence. The numerical content is unique and well-defined*. Therefore adding 4 to '?' also has a meaning. * If you're paranoid you may request the spec to ensure the character is in NFC form.
Huh? You jump in in the middle of conversation and I'm off-topic? Now, to get back to the topic at hand: D's current design is: char/dchar/wchar are integral types that can contain any value/encoding even though D prefers Unicode. This is not enforced. e.g. you can have a valid wchar which you increment by 1 and get an invalid wchar. Instead, Let's have proper well defined semantics in D: Design A: char/wchar/dchar are defined to be Unicode code-points for the respective encodings. These is enforces by the language so if you want to define a different encoding you must use something like bits!8 arithmetic on code-points is defined according to the Unicode standard. Design B: char represents a (perhaps multi-byte) character. Arithmetic on this type is *not* defined. In either case these types should not be treated as plain integral types.
Mar 28 2010
parent KennyTM~ <kennytm gmail.com> writes:
On Mar 28, 10 18:56, Yigal Chripun wrote:
 KennyTM~ Wrote:

 On Mar 26, 10 18:52, yigal chripun wrote:
 KennyTM~ Wrote:

 On Mar 26, 10 05:46, yigal chripun wrote:
 while it's true that '?' has one unicode value for it, it's not true for all
sorts of diacritics and combine code-points. So your approach is to pass the
responsibility for that to the end user which in 99.9999% will not handle this
correctlly.
Non-issue. Since when can a character literal store> 1 code-point?
character != code-point D chars are really as you say code-points and not always complete characters. here's a use case for you: you want to write a fully unicode aware search engine. If you just try to match the given sequnce of code-points in the search term, you will miss valid matches since, for instance you do not take into account permutations of the order of combining marks. you can't just assume that the code-point value identifies the character.
Stop being off-topic. '?' is of type char, not string. A char always holds an octet of UTF-8 encoded sequence. The numerical content is unique and well-defined*. Therefore adding 4 to '?' also has a meaning. * If you're paranoid you may request the spec to ensure the character is in NFC form.
Huh? You jump in in the middle of conversation and I'm off-topic?
Yes. The original discussion is on implicit conversion, which leads to whether ('x' + 1) is semantically correct. How will this be related to search engine? (Technically even this is off-topic. The title said implicit *enum* conversion.)
 Now, to get back to the topic at hand:

 D's current design is:
 char/dchar/wchar are integral types that can contain any value/encoding even
though D prefers Unicode. This is not enforced.
 e.g. you can have a valid wchar which you increment by 1 and get an invalid
wchar.
Wrong. Read the specs: http://digitalmars.com/d/1.0/type.html, http://digitalmars.com/d/2.0/type.html * char = unsigned 8 bit UTF-8 * wchar = unsigned 16 bit UTF-16 * dchar = unsigned 32 bit UTF-32 To contain any encoding, use ubyte.
 Instead, Let's have proper well defined semantics in D:

 Design A:
 char/wchar/dchar are defined to be Unicode code-points for the respective
encodings. These is enforces by the language so if you want to define a
different encoding you must use something like bits!8
 arithmetic on code-points is defined according to the Unicode  standard.

 Design B:
 char represents a (perhaps multi-byte) character.
 Arithmetic on this type is *not* defined.

 In either case these types should not be treated as plain integral types.
Mar 28 2010
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
KennyTM~ <kennytm gmail.com> wrote:

 On Mar 26, 10 05:46, yigal chripun wrote:
 while it's true that '?' has one unicode value for it, it's not true  
 for all sorts of diacritics and combine code-points. So your approach  
 is to pass the responsibility for that to the end user which in  
 99.9999% will not handle this correctlly.
Non-issue. Since when can a character literal store > 1 code-point?
Not only that, but one does not routinely go about adding random numbers to randomly chosen code points. When '?' + 3 is used, it's because it was the best (fastest/easiest/most readable) way to do it. Or somebody was just showing off, but that can be done in more horrible ways. -- Simen
Mar 27 2010
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
yigal chripun:
 The fact that D has 12 integral types is a bad design, why do we need so many
built in types? to me this clearly shows a need to refactor this aspect of D. 
In a system language you need them all, and you need multi-precision integers too. Bye, bearophile
Mar 25 2010
prev sibling next sibling parent reply Don <nospam nospam.com> writes:
Walter Bright wrote:
 Nick Sabalausky wrote:
 To put it simply, I agree with this even on mere principle. I'm 
 convinced that the current D behavior is a blatant violation of 
 strong-typing and smacks way too much of C's so-called "type system".
You're certainly not the first to feel this way about implicit conversions. Niklaus Wirth did the same, and designed Pascal with no implicit conversions. You had to do an explicit cast each time. Man, what a royal pain in the ass that makes coding in Pascal. Straightforward coding, like converting a string of digits to an integer, becomes a mess of casts. Even worse, casts are a blunt instrument that *destroys* type checking (that wasn't so much of a problem with Pascal with its stone age abstract types, but it would be killer for D). Implicit integral conversions are not without problems, but when I found C I threw Pascal under the nearest bus and never wrote a line in it again. The taste was so bad, I refused to even look at Modula II and its failed successors. D has 12 integral types. Disabling implicit integral conversions would make it unbearable to use.
I think there might be some low-hanging fruit, though. Supposed we distinguished enums containing AssignExpressions from those which do not. It seems clear to me that logical operations should always be permitted on enums where every member of the enum has been explicitly assigned a value. enum Enum1 { A = 1, B = 2, C = 4 } ---> A|B makes sense. But if there are no assign expressions at all: enum Enum2 { A, B, C } then I think that performing arithmetic on that enum is almost certainly a bug. The case where only some of the enum members have assign expressions is less clear. Some cases, such as synonyms { A, B, C=B } aren't really any different from the no-assign expression case. But other cases are less clear, so I'll just ignore them all. So I propose a simple rule: Suppose that implicit integral conversions (and arithmetic/logical operations) involving enums were permitted ONLY if the enum has at least one AssignExpression. This would catch some bugs, without (I think) causing much pain for valid code. At the very least, this is something I'd want in a lint tool. (But note that it wouldn't fix the issue in the original post).
Mar 25 2010
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Don <nospam nospam.com> wrote:

 I think there might be some low-hanging fruit, though.
 Supposed we distinguished enums containing AssignExpressions from those  
 which do not.
 It seems clear to me that logical operations should always be permitted  
 on enums where every member of the enum has been explicitly assigned a  
 value.
 enum Enum1 { A = 1, B = 2, C = 4 }
   ---> A|B makes sense.

 But if there are no assign expressions at all:
 enum Enum2 { A, B, C }
 then I think that performing arithmetic on that enum is almost certainly  
 a bug.
I wonder, what if the default base type of an enum was simply 'enum', a type not implicitly convertible to other types. If you want implicit casts, specify the base type: enum foo { A, B, C = B } // No base type, no conversions allowed. enum bar : int { D, E, F = E } // An int in disguise. Allow conversions. That seems to follow D's tenet that the unsafe should be more verbose. -- Simen
Mar 25 2010
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 This would catch some bugs, without (I think) causing much pain for 
 valid code. At the very least, this is something I'd want in a lint 
 tool. (But note that it wouldn't fix the issue in the original post).
Such rules are interesting, but I worry that they are both too clever and too obtuse. Having a lot of such rules may make using D very frustrating because you'll never know when you'll get hit by one of them. I'd rather have a simpler, more orthogonal, and easier to remember rules that may have a downside here and there rather than a complex web of seemingly arbitrary ones.
Mar 25 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 Such rules are interesting, but I worry that they are both too clever and too 
 obtuse. Having a lot of such rules may make using D very frustrating because 
 you'll never know when you'll get hit by one of them.
 
 I'd rather have a simpler, more orthogonal, and easier to remember rules that 
 may have a downside here and there rather than a complex web of seemingly 
 arbitrary ones.
I agree a lot, and I agree Don was wrong here. one: enum Foo {...} // normal enum, no implicit conversions, no operators flags enum Foo {...} // no implicit conversions, boolean operator plus "in". Bye, bearophile
Mar 25 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Don" <nospam nospam.com> wrote in message 
news:hof6fe$6ah$1 digitalmars.com...
 I think there might be some low-hanging fruit, though.
 Supposed we distinguished enums containing AssignExpressions from those 
 which do not.
 It seems clear to me that logical operations should always be permitted on 
 enums where every member of the enum has been explicitly assigned a value.
 enum Enum1 { A = 1, B = 2, C = 4 }
  ---> A|B makes sense.

 But if there are no assign expressions at all:
 enum Enum2 { A, B, C }
 then I think that performing arithmetic on that enum is almost certainly a 
 bug.

 The case where only some of the enum members have assign expressions is 
 less clear. Some cases, such as synonyms { A, B, C=B } aren't really any 
 different from the no-assign expression case. But other cases are less 
 clear, so I'll just ignore them all. So I propose a simple rule:

 Suppose that implicit integral conversions (and arithmetic/logical 
 operations) involving enums were permitted ONLY if the enum has at least 
 one AssignExpression.

 This would catch some bugs, without (I think) causing much pain for valid 
 code. At the very least, this is something I'd want in a lint tool. (But 
 note that it wouldn't fix the issue in the original post).
If I understand that right, I think that side-steps what I see as the important goal: To *have* an associated value with each enum member but just have to be explicit about obtaining it. The above scheme doesn't really bring things significantly closer to that, you have to make a choice between type-safety and being able actually have an underlying value at all. So when you need an associated value but you're not doing bitfields/flags (which is a situation I find to be very common for enums), then that solution provides no improvement over the current state. Here's the low-hanging fruit I see: Step 1: Remove implicit enum->base-type conversions Step 2: Allow '|' (and maybe '&'?) on enums, and consider the result of the operation be the base type. Certainly not ideal, but it provides far more type-safety than we currently have on non-bitfield/non-flag enums, even if you're using associated values, and still allows enums to be used for bitfields/flags without any code breakage or ugly "cast(int)Foo.a | cast(int)Foo.b".
Mar 25 2010
parent reply Regan Heath <regan netmail.co.nz> writes:
Nick Sabalausky wrote:
 Here's the low-hanging fruit I see:
 
 Step 1: Remove implicit enum->base-type conversions
 Step 2: Allow '|' (and maybe '&'?) on enums, and consider the result of the 
 operation be the base type.
I would prefer the result of Step 2 to be the enum type, not the base type(*) The typical case I see for enums as flags is passing a combination of them to a function, where the parameter (for type-safety & self-documentation) will probably be of the enum type. However, it occurs to me we don't actually get full type safety unless we also ensure the enum never has a value outside those defined, or a combination thereof(*) Example: enum Flags { A = 0x1, B = 0x2, C = 0x4, D = 0x8 } // // possible values for a variable of type 'Flags' // 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA // 0xB, 0xC, 0xD, 0xE, 0xF // // values < 0x1 and > 0xF are illegal // // default value of variable of type 'Flags' is 0x1 (A) // <incomplete code snippets..> void foo(Flags f) {} //accepts only legal values for Flags foo(Flags.A|Flags.B); //ok foo(0x10); //error Flags f; //ok, f = 0x1 Flags err = 0x10; //error foo(Flags.A|0x10); //error </incomplete code snippets..> (*) Some operators would return the base type, take ~ for example, it naturally produces a value outside the range of values defined by the enum type. It follows that operators like |[=], &[=] etc would need to accept enum and base types as operands, otherwise some common idioms would be illegal, eg. Flags f = Flags.A|Flags.B|Flags.C; f &= ~Flags.A; // remove Flags.A from 'f' R
Mar 25 2010
parent "Nick Sabalausky" <a a.a> writes:
"Regan Heath" <regan netmail.co.nz> wrote in message 
news:hogaop$2kp2$1 digitalmars.com...
 Nick Sabalausky wrote:
 Here's the low-hanging fruit I see:

 Step 1: Remove implicit enum->base-type conversions
 Step 2: Allow '|' (and maybe '&'?) on enums, and consider the result of 
 the operation be the base type.
I would prefer the result of Step 2 to be the enum type, not the base type(*)
Agreed, but to do that correctly, the compiler would have to be able to distinguish between flag/bitfield-type enums and other enums, because many enums are *not* intended to be combinable and trying to do so should be an error. That's why I suggested the above as a low-hanging-fruit compromise. But yea, if Walter were fine with taking it further and having that proper separation of flag/bitfield enums and non-flag/non-bitfield enums, then all the better.
Mar 25 2010
prev sibling next sibling parent reply grauzone <none example.net> writes:
Walter Bright wrote:
 Nick Sabalausky wrote:
 To put it simply, I agree with this even on mere principle. I'm 
 convinced that the current D behavior is a blatant violation of 
 strong-typing and smacks way too much of C's so-called "type system".
You're certainly not the first to feel this way about implicit conversions. Niklaus Wirth did the same, and designed Pascal with no implicit conversions. You had to do an explicit cast each time. Man, what a royal pain in the ass that makes coding in Pascal. Straightforward coding, like converting a string of digits to an integer, becomes a mess of casts. Even worse, casts are a blunt instrument that *destroys* type checking (that wasn't so much of a problem with Pascal with its stone age abstract types, but it would be killer for D).
That's funny that you're saying this. Casts are totally messed up in D. Some casts do safe operations (casts between objects and interfaces), some are absolutely ridiculous and only useful in low level situations (casting array slices), some are safe whenever the compiler feels like it (array casts of array literals versus array slices), and some fundamentally break other language features, even accidentally (immutable). casts are easily grepable, but you never know what a specific cast actually does. Think about what this means for generic templated code. In summary, I'd say casting rules in D are the worst spawn of hell. I mean, that's ok, it doesn't exactly make D useless. And you can always introduce your own safe (exe bloating, sigh) casting template functions. But I still find it funny that you say this.
 Implicit integral conversions are not without problems, but when I found 
 C I threw Pascal under the nearest bus and never wrote a line in it 
 again. The taste was so bad, I refused to even look at Modula II and its 
 failed successors.
For your information, programming in Delphi (modern Pascal dialect) was quite a joy. It combined the advantages of the low level programming of C (pointers, inline assembler), was safer than C, and included a sane (Yeah, the template fetishists must have been very unhappy with it.) I really don't understand why you're bashing Pascal at large. You must have had only experience with early Pascal dialects... and then never looked at anything that smelled like Pascal... and this as a language designer??
 D has 12 integral types. Disabling implicit integral conversions would 
 make it unbearable to use.
PS: while you guys are talking about new "absolutely necessary" language features, people new to D are despairing to get a working D installation and *trying* to use external libraries from dsource (that kind of struggling really isn't nice to watch), and people "old" to D are desparing over compiler regressions and random bugs that have global effects on middle-sized to large codebases (circular dependency and optlink bugs come to mind). The situation is slowly improving, but too slow and problems *never* get completely eliminated. /rant Well, I'm out of here.
Mar 25 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
grauzone:
 For your information, programming in Delphi (modern Pascal dialect) was 
 quite a joy.
to use.
 You must 
 have had only experience with early Pascal dialects... and then never 
 looked at anything that smelled like Pascal...
From the first Pascals and the currently available FreePascal there's a night-day difference. It has OOP, templates, low level constructs, a standard library, good strings, etc. And your binaries are tiny. You can't judge FreePascal from the ancient Pascals. Bye, bearophile
Mar 25 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
grauzone wrote:
 Walter Bright wrote:
 That's funny that you're saying this. Casts are totally messed up in D. 
 Some casts do safe operations (casts between objects and interfaces), 
 some are absolutely ridiculous and only useful in low level situations 
 (casting array slices), some are safe whenever the compiler feels like 
 it (array casts of array literals versus array slices), and some 
 fundamentally break other language features, even accidentally (immutable).
The unsafe casts are not allowed in safe mode.
 casts are easily grepable, but you never know what a specific cast 
 actually does. Think about what this means for generic templated code.
 
 In summary, I'd say casting rules in D are the worst spawn of hell.
 
 I mean, that's ok, it doesn't exactly make D useless. And you can always 
 introduce your own safe (exe bloating, sigh) casting template functions. 
 But I still find it funny that you say this.
Sure, but I think it misses the point a bit. My point was that one should strive to eliminate casts from your code. A type system that requires a lot of casts is going to be less safe than one that does not.
 Implicit integral conversions are not without problems, but when I 
 found C I threw Pascal under the nearest bus and never wrote a line in 
 it again. The taste was so bad, I refused to even look at Modula II 
 and its failed successors.
For your information, programming in Delphi (modern Pascal dialect) was quite a joy. It combined the advantages of the low level programming of C (pointers, inline assembler), was safer than C, and included a sane
If there's a particular aspect of Delphi you feel would be a good fit for D, they were created by the same person!
 (Yeah, the template fetishists must have been very unhappy with it.)
 
 I really don't understand why you're bashing Pascal at large. You must 
 have had only experience with early Pascal dialects... and then never 
 looked at anything that smelled like Pascal... and this as a language 
 designer??
There are thousands of languages out there. If I did due diligence researching them all, I'd never finish, as new languages get created faster than anyone could ever study them. At some point, you've gotta pick and choose what you're going to look at in depth. Each language family is based on a core set of principles that get carried from one version to the next. Pascal's core set is unbearably restrictive to me. Sure, a lot of people strongly disagree, and that's fair, it is subjective, after all. Furthermore, like I said, anyone can propose features from any language they feel would make a good fit for D. None will be automatically rejected just because it came from a Pascal family language.
 PS: while you guys are talking about new "absolutely necessary" language 
 features, people new to D are despairing to get a working D installation 
 and *trying* to use external libraries from dsource (that kind of 
 struggling really isn't nice to watch), and people "old" to D are 
 desparing over compiler regressions and random bugs that have global 
 effects on middle-sized to large codebases (circular dependency and 
 optlink bugs come to mind). The situation is slowly improving, but too 
 slow and problems *never* get completely eliminated.
I understand the issues, but we have to get the feature set for D2 finalized before it can be made stable. D1 is stable. The optlink problems have been solved months ago. The compiler regressions have been unanticipated effects from fixing long standing problems in bugzilla, and fixing them has been taken care of reasonably quickly. I'd welcome your help in fixing issues you feel are most important. There are a lot of people working hard on them, but we can use more help. After all, there is no corporation pouring billions into D. We're a bunch of volunteers.
Mar 25 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 There are thousands of languages out there. If I did due diligence researching 
 them all, I'd never finish, as new languages get created faster than anyone 
 could ever study them. At some point, you've gotta pick and choose what you're 
 going to look at in depth.
I agree. On the other hand using few days every year, to try in their native environment one or two new languages every year is good, to keep a hold of what why people ask for IDE-related features, or a useful unit-testing, etc.
 There are a 
 lot of people working hard on them, but we can use more help. After all, there 
 is no corporation pouring billions into D. We're a bunch of volunteers.
I think that eventually I will try to fix D bugs myself :-) Regarding base type names I have proposed : byte => sbyte wchar => char16 (or shortchar) dchar => char32 (or intchar) http://d.puremagic.com/issues/show_bug.cgi?id=3850 http://d.puremagic.com/issues/show_bug.cgi?id=3936 Bye, bearophile
Mar 25 2010
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Regarding base type names I have proposed :
 byte => sbyte
 wchar => char16 (or shortchar)
 dchar => char32 (or intchar)
Yes, we can endlessly rename keywords, but in the end, what does that accomplish that would compensate for upending every D program in existence?
Mar 25 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:

Yes, we can endlessly rename keywords, but in the end, what does that
accomplish that would compensate for upending every D program in existence?<
I can list few pro/cons, but then the decision is not mine. I'll close my "bug" report on the base of the answers, because this is only one of the about 15 little breaking changes I have proposed (the disallowing of the octals syntax was another one of them, but after your last answer I consider it a closed problem, the http://d.puremagic.com/issues/show_bug.cgi?id=2656 can be closed). The type names in D have a nice symmetry, and they are not ex-novo, they are diffused in other languages. I have appreciated them. I think of a "byte" as unsigned value. This has produced a small bug in a D program of mine. I think changing the names of the signed/unsigned values can solve this. bytes as unsigned, because they break the symmetry using: - The sbyte type represents signed 8-bit integers with values between -128 and 127. - The byte type represents unsigned 8-bit integers with values between 0 and 255. follow the symmetry and write wrong code again. So I have suggested ot keep the "ubyte", deprecate the "byte", and introduce a "sbyte" (signed byte). Now it's easy to tell apart what's the signed and what's the unsigned. "byte" can later be removed. ----------------- The wchar/dchar are short names, easy to write, but for me and a person I've shown/taught D it doesn't result easy to remember their size in bytes. "w" stands for wide, "d" for double, this is easy to remember. But how wide is wide? That's why I have suggested to adopt more descriptive names for them. A way to invent descriptive names is to use names similar to the byte/shot/int/long integers. Or to use numbers after the "char". I guess now it can be too much late to change type names... Bye, bearophile
Mar 25 2010
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:hoh07b$16km$1 digitalmars.com...
 Walter Bright:

Yes, we can endlessly rename keywords, but in the end, what does that 
accomplish that would compensate for upending every D program in 
existence?<
I can list few pro/cons, but then the decision is not mine. The wchar/dchar are short names, easy to write, but for me and a person I've shown/taught D it doesn't result easy to remember their size in bytes. "w" stands for wide, "d" for double, this is easy to remember. But how wide is wide? That's why I have suggested to adopt more descriptive names for them. A way to invent descriptive names is to use names similar to the byte/shot/int/long integers. Or to use numbers after the "char". I guess now it can be too much late to change type names...
As long as we're bikeshedding on type names, I do find it misleading that "char" represents a code-unit while still calling itself a "character". Don't get me wrong, I don't mind that at the language level D operates on code-units instead of code-points (Tango and Phobos2 have pretty darned good handling of code-points anyway). It's just that ever since learning how Unicode works, it seems rather a misleading misnomer to call a code-unit "char". I can live with it, of course, now that I know, but I don't envy the newbies who may come across it.
Mar 25 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 As long as we're bikeshedding on type names,
"There are only two hard things in Computer Science: cache invalidation and naming things" ^_^
I do find it misleading that "char" represents a code-unit while still calling
itself a "character".<
The development of the BitC language has restarted, it's a system language that looks like Scheme. It's efficient. This is is the start of a small thread about unicode in BitC: http://www.coyotos.org/pipermail/bitc-dev/2010-March/001812.html They agree with me that 32 bit chars can be not really true chars, so I think essentially even UFT32 is an bidirectional Range. Bye, bearophile
Mar 25 2010
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 The wchar/dchar are short names, easy to write, but for me and a person I've
 shown/taught D it doesn't result easy to remember their size in bytes. "w"
 stands for wide, "d" for double, this is easy to remember. But how wide is
 wide? That's why I have suggested to adopt more descriptive names for them.
The wchar and dchar stem from the popular WORD and DWORD sizes on the x86 platforms. wchar_t is of course "wide character" for C, and is often used for UTF-16 at least on Windows platforms. Confusingly, wchar_t on Linux is 32 bits.
Mar 25 2010
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:hoh85i$1kbj$1 digitalmars.com...
 bearophile wrote:
 The wchar/dchar are short names, easy to write, but for me and a person 
 I've
 shown/taught D it doesn't result easy to remember their size in bytes. 
 "w"
 stands for wide, "d" for double, this is easy to remember. But how wide 
 is
 wide? That's why I have suggested to adopt more descriptive names for 
 them.
The wchar and dchar stem from the popular WORD and DWORD sizes on the x86 platforms. wchar_t is of course "wide character" for C, and is often used for UTF-16 at least on Windows platforms.
I think that's why I never had a problem with wchar/dchar. I've dealt with x86 WORD/DWORD. Though I guess that also indicates why other people may find it unintuitive, not everyone has gone low-level like that.
Mar 25 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:

The wchar and dchar stem from the popular WORD and DWORD sizes on the x86
platforms. wchar_t is of course "wide character" for C, and is often used for
UTF-16 at least on Windows platforms. Confusingly, wchar_t on Linux is 32 bits.<
From such comments of yours, and from the lack of interest from Don, Nick and others, I guess that idea of changing char names is closed, even if I don't like those names. I will update the bugzilla with this. The proposal of renaming the byte => sbyte is not closed/resolved yet. It's a little more important, because the current situation is bug-prone. Bye, bearophile
Mar 26 2010
parent bearophile <bearophileHUGS lycos.com> writes:
I can add something to this long thread.

I don't like C octal literals for aesthetic reasons, because in mathematics
leading zeros before the decimal point are not significant. Programming
languages are not forced to follow math notation conventions, but experience
clearly shows me that when possible it's convenient to follow math notation
because it's widely known, by newbie programmers too, and expert programmers to
know it well, sometimes from primary school, so it's well interiorized. That's
why for example the missing operator precedence rules of Smalltalk are bad. So
I think C octal literals are bad-looking small traps that a modern language is
better without. If octal literals are seen as useful, then a better, more
explicit and safer octal literal can be invented. This is what Python3 has
done, and this is what I think D should do. This is what I have asked in bug
report 3837.

On the other hand no octal number has ever caused a bug in my Python2.x or D
programs, and I think it has caused no bugs even in my C code. So despite being
little traps for me they are not so bug-prone.

On the other hand, the name of signed bytes has caused one or more hard-to-find
bugs in my D code. I have never put such bug in Delphi/C programs (but in C the
signedness of chars has caused me few troubles in the past. Thanks Walter D
chars don't come in signed and unsigned versions, avoiding that chars bugs, and
introduces bugs on bytes...). It's not just a matter of bug count: D forces me
to keep some of my attention on the signedness of bytes when I program, this
slows down programming a bit and distracts a small part of my attention away
from the things that truly matter, that is problem solving, the things that the
program has to do, etc. So I think on this D is worse than Delphi/C, and
deserves to be fixed.

My D1 dlibs are something like 80-90 thousand lines of code, and then there is
all the code that uses those dlibs, so I have probably written 250_000 or more
lines of D1 code, this can be more than the D1 code written by Walter. So I am
able to see what things in D1 have caused me bugs or require some undeserved
attention to write bug-free code.

Bye,
bearophile
Mar 27 2010
prev sibling parent Don <nospam nospam.com> writes:
Walter Bright wrote:
 bearophile wrote:
 Regarding base type names I have proposed :
 byte => sbyte
 wchar => char16 (or shortchar)
 dchar => char32 (or intchar)
Yes, we can endlessly rename keywords, but in the end, what does that accomplish that would compensate for upending every D program in existence?
Removing a frequent bug. IMHO, wchar and dchar are fine as is. But byte --> sbyte I support. 'byte' is a really, really awful name. EVERYONE makes the mistake of thinking 'byte' is unsigned. I still do it, really frequently. I believe that almost every existing use of 'byte' is a bug! BTW I don't think that "everyone" is much of an exaggeration. For example, YOU have done it! (The first version of the htod utility used 'byte' where it should have been 'ubyte'). And if even you find it unintuitive, I think the entire planet finds it unintuitive.
Mar 25 2010
prev sibling parent reply "Aelxx" <aelxx yandex.ru> writes:
"bearophile" <bearophileHUGS lycos.com>wrote :
 Regarding base type names I have proposed :
 byte => sbyte
 wchar => char16 (or shortchar)
 dchar => char32 (or intchar)

 http://d.puremagic.com/issues/show_bug.cgi?id=3850
 http://d.puremagic.com/issues/show_bug.cgi?id=3936

 Bye,
 bearophile
In my embedded C projects I always use u8, i8 u16, i16 u32, i32 f32 for floats and they are all defined in user's header file, surely IDE highlights them as keywords :), so no need for language changes =).
Mar 26 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Aelxx:
 In my embedded C projects I always use
 u8, i8
 u16, i16
 u32, i32
 f32 for floats
 and they are all defined in user's header file, surely IDE highlights them 
 as keywords :), so no need for language changes =).
D tries to give sensible defaults, good for most programmers, also to increase code uniformity across different codebases. Python shows that having common style and idioms is very useful to build better a community of shared modules. Bye, bearophile
Mar 26 2010
prev sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 03/25/2010 01:08 PM, Walter Bright wrote:
 There are thousands of languages out there. If I did due diligence
 researching them all, I'd never finish, as new languages get created
 faster than anyone could ever study them. At some point, you've gotta
 pick and choose what you're going to look at in depth. Each language
 family is based on a core set of principles that get carried from one
 version to the next. Pascal's core set is unbearably restrictive to me.
 Sure, a lot of people strongly disagree, and that's fair, it is
 subjective, after all.

 Furthermore, like I said, anyone can propose features from any language
 they feel would make a good fit for D. None will be automatically
 rejected just because it came from a Pascal family language.
What do you think of Erlang's bit syntax if you've looked at it, or could you if you haven't? Beyond the syntax, which is totally incompatible with D, I think it's pretty nifty and would be a sweet thing to have as a library template at the least.
Mar 25 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Ellery Newcomer wrote:
 What do you think of Erlang's bit syntax if you've looked at it, or 
 could you if you haven't?
I know nothing about it.
Mar 25 2010
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 03/25/2010 06:21 PM, Walter Bright wrote:
 Ellery Newcomer wrote:
 What do you think of Erlang's bit syntax if you've looked at it, or
 could you if you haven't?
I know nothing about it.
I suppose you could think of it as sort of a regex-for-generic-data, but you can use it as a pattern matcher or a data constructor. The example Armstrong gives in Programming Erlang is where X is assumedly a byte array or something. the first 11 bits are asserted to be 1, and the remaining bits get associated with the following variables. Yeah, that example isn't much more impressive than bitfields. You could do something like <<N:32, Data:N/binary, _/binary>> = X which would interpret the first four bytes as a length field, bind the next N bytes to Data, and ignore the rest.. The general syntax for them should look something like Bit: << >> << E >> E: E , E1 E1 E1: Value Value : Size Value / TypeSpecList Value : Size / TypeSpecList //integral, fp, or binary (byte arrays, strings, etc) type Value: Expression // integral type Size: Expression TypeSpecList: TypeSpecList - TypeSpec TypeSpec TypeSpec: Endianness Sign Type Unit // default is big Endianness: big little native Sign: signed unsigned Type: integer float binary //Size*Unit is the number of bits that get matched // Unit defaults to 1 for Type = integer or float, 8 for Type = binary Unit: IntegerLiteral
Mar 25 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
Disabling implicit integral conversions would make it unbearable to use.<
Implicit conversion from signed to unsigned is too much unsafe (if you don't have integer overflows). and keeps other of them. Bye, bearophile
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 06:58 AM, bearophile wrote:
 Walter Bright:
 Disabling implicit integral conversions would make it unbearable to use.<
Implicit conversion from signed to unsigned is too much unsafe (if you don't have integer overflows). and keeps other of them.
The problem is it asks you to insert casts all too often. I think the value range propagation is a principled and correct solution to that problem. Andrei
Mar 25 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 The problem is it asks you to insert casts all too often. I think the 
 value range propagation is a principled and correct solution to that 
 problem.
In bugzilla I have asked to disable the implicit conversion enum => base type in an equality test, see: http://d.puremagic.com/issues/show_bug.cgi?id=3999 In bugzilla I have never asked to disable implicit signed => unsigned casts, I am able to see they are two quite different situations. I think the implicit conversions from enum => base types are uncommon enough, so they can't introduce too many casts. If Walter doesn't agree with me (and few other people here) then there's no point in keeping bug 3999 open, it can be closed. Because it's better to fix/change similar things now, when the D2 language is not diffused yet. Later such changes are harder to do. In bugzilla there are few other things that deserve a similar look. Those changes can't be done all at the same time, but the decision can be taken in a short enough time, and it's better to think about them now. Bye and thank you for your attention, bearophile
Mar 25 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 11:17 AM, bearophile wrote:
 Andrei Alexandrescu:
 The problem is it asks you to insert casts all too often. I think the
 value range propagation is a principled and correct solution to that
 problem.
In bugzilla I have asked to disable the implicit conversion enum => base type in an equality test, see: http://d.puremagic.com/issues/show_bug.cgi?id=3999 In bugzilla I have never asked to disable implicit signed => unsigned casts, I am able to see they are two quite different situations. I think the implicit conversions from enum => base types are uncommon enough, so they can't introduce too many casts. If Walter doesn't agree with me (and few other people here) then there's no point in keeping bug 3999 open, it can be closed. Because it's better to fix/change similar things now, when the D2 language is not diffused yet. Later such changes are harder to do. In bugzilla there are few other things that deserve a similar look. Those changes can't be done all at the same time, but the decision can be taken in a short enough time, and it's better to think about them now. Bye and thank you for your attention, bearophile
I think defining a integral() function that gives the value of the enum as an appropriately-typed integral number wouldn't harm. Andrei
Mar 25 2010
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Andrei Alexandrescu wrote:
 On 03/25/2010 11:17 AM, bearophile wrote:
 Andrei Alexandrescu:
 The problem is it asks you to insert casts all too often. I think the
 value range propagation is a principled and correct solution to that
 problem.
In bugzilla I have asked to disable the implicit conversion enum => base type in an equality test, see: http://d.puremagic.com/issues/show_bug.cgi?id=3999 In bugzilla I have never asked to disable implicit signed => unsigned casts, I am able to see they are two quite different situations. I think the implicit conversions from enum => base types are uncommon enough, so they can't introduce too many casts. If Walter doesn't agree with me (and few other people here) then there's no point in keeping bug 3999 open, it can be closed. Because it's better to fix/change similar things now, when the D2 language is not diffused yet. Later such changes are harder to do. In bugzilla there are few other things that deserve a similar look. Those changes can't be done all at the same time, but the decision can be taken in a short enough time, and it's better to think about them now. Bye and thank you for your attention, bearophile
I think defining a integral() function that gives the value of the enum as an appropriately-typed integral number wouldn't harm. Andrei
Why not let to!int() do this? -Lars
Mar 25 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Lars T. Kyllingstad:
 Why not let to!int() do this?
Because if the enum is for example: enum ulong Foo { ... You are casting an ulong to int and you risk losing bits of information. That's why Andrei has suggested a conversion template function, because it can (I don't know how) find the correct base type and cast the enum to it. Andrei is sometimes one step forward. Bye, bearophile
Mar 25 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/25/2010 11:57 AM, Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 On 03/25/2010 11:17 AM, bearophile wrote:
 Andrei Alexandrescu:
 The problem is it asks you to insert casts all too often. I think the
 value range propagation is a principled and correct solution to that
 problem.
In bugzilla I have asked to disable the implicit conversion enum => base type in an equality test, see: http://d.puremagic.com/issues/show_bug.cgi?id=3999 In bugzilla I have never asked to disable implicit signed => unsigned casts, I am able to see they are two quite different situations. I think the implicit conversions from enum => base types are uncommon enough, so they can't introduce too many casts. If Walter doesn't agree with me (and few other people here) then there's no point in keeping bug 3999 open, it can be closed. Because it's better to fix/change similar things now, when the D2 language is not diffused yet. Later such changes are harder to do. In bugzilla there are few other things that deserve a similar look. Those changes can't be done all at the same time, but the decision can be taken in a short enough time, and it's better to think about them now. Bye and thank you for your attention, bearophile
I think defining a integral() function that gives the value of the enum as an appropriately-typed integral number wouldn't harm. Andrei
Why not let to!int() do this? -Lars
Because an enum that uses long as a base will not be converted. integral() would automatically deduce and return the appropriate base type. Andrei
Mar 25 2010
parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Andrei Alexandrescu wrote:
 On 03/25/2010 11:57 AM, Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 On 03/25/2010 11:17 AM, bearophile wrote:
 Andrei Alexandrescu:
 The problem is it asks you to insert casts all too often. I think the
 value range propagation is a principled and correct solution to that
 problem.
In bugzilla I have asked to disable the implicit conversion enum => base type in an equality test, see: http://d.puremagic.com/issues/show_bug.cgi?id=3999 In bugzilla I have never asked to disable implicit signed => unsigned casts, I am able to see they are two quite different situations. I think the implicit conversions from enum => base types are uncommon enough, so they can't introduce too many casts. If Walter doesn't agree with me (and few other people here) then there's no point in keeping bug 3999 open, it can be closed. Because it's better to fix/change similar things now, when the D2 language is not diffused yet. Later such changes are harder to do. In bugzilla there are few other things that deserve a similar look. Those changes can't be done all at the same time, but the decision can be taken in a short enough time, and it's better to think about them now. Bye and thank you for your attention, bearophile
I think defining a integral() function that gives the value of the enum as an appropriately-typed integral number wouldn't harm. Andrei
Why not let to!int() do this? -Lars
Because an enum that uses long as a base will not be converted. integral() would automatically deduce and return the appropriate base type.
Ah, now I understand. I thought you meant a function to convert an enum to a user-specified type, i.e. integral!T(myEnum). -Lars
Mar 25 2010
prev sibling next sibling parent yigal chripun <yigal100 gmail.com> writes:
Walter Bright Wrote:

 
 That's true, '?' can have different encodings, such as for EBCDIC and RADIX50. 
 Those formats are dead, however, and ASCII has won. D is specifically a
Unicode 
 language (a superset of ASCII) and '?' has a single defined value for it.
 
 Yes, Unicode has some oddities about it, and the poor programmer using those 
 characters will have to deal with it, but that does not change that quoted 
 character literals are always the same numerical value. '?' is not going to 
 change to another one tomorrow or in any conceivable future incarnation of
Unicode.
 
another point regarding encodings - While it's true that for English there's a clear winner - Ascii and unicode as a superset of it, it doesn't (yet) apply to other languages. For example, it is still prefered for russian to use another pre-existing encoding over Unicode.
Mar 26 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 I fear it's probably too late for that for D, but I do like it very much. If 
 I ever make a C-style langauge myself, I'll definitely consider something 
 like that.
Adding to dmd a few warnings activated by a compiler switch that help avoid bugs in porting C->D2 is an additive change, it's fully backwards compatible, so it can be added with no problems, if there's desire and time to implement it. Bye, bearophile
Mar 26 2010
parent "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:hoif0r$v8c$1 digitalmars.com...
 Nick Sabalausky:
 I fear it's probably too late for that for D, but I do like it very much. 
 If
 I ever make a C-style langauge myself, I'll definitely consider something
 like that.
Adding to dmd a few warnings activated by a compiler switch that help avoid bugs in porting C->D2 is an additive change, it's fully backwards compatible, so it can be added with no problems, if there's desire and time to implement it.
My understanding of the orignal suggestion was to have those optional warnings for the purpose of freeing the rest of D's design from the "C code must behave the same or error" restriction. I'd love for that to happen, I'm just doubtful that it would, that's all.
Mar 26 2010
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:


 baseline to compare the D implementation with.
machine). I have asked but I am not good enough to do that, sorry. Metaprogramming is not easy in most languages that allow some of it :-)
 Why and how do you believe that whatever mechanism we come up with 
 (possibly following a proposal authored by you) will be a net 
 improvement over mixins?
You are right, I can't know. Note: user-defined attributes and mixins have different purposes. User-defined attributes are much fitter than mixins if you want to add something simple to the type system. the AST/IL: http://www.codeproject.com/KB/cs/attributes.aspx?display=Print
 Are you sure you are saying what you mean to say?
Here D template syntax is better, you are right. Bye, bearophile
Mar 26 2010