digitalmars.D - Imperfect D (A Rant About Bits)
- Antti =?iso-8859-1?Q?Syk=E4ri?= (94/94) Jun 04 2004 I've just finished reading a hundred-message thread about the boolean
- Matthew (6/100) Jun 04 2004 From here on in I shall try my damndest to refrain from further comment,...
- Ivan Senji (15/109) Jun 05 2004 (1))
- Kevin Bealer (50/144) Jun 05 2004 1. Your example fails to compile, and fails with a reasonable message,
- Sean Kelly (23/38) Jun 05 2004 But what about template code? Say I write a template function that mani...
- J Anderson (4/6) Jun 05 2004 Lots of things. Make an array of enums.
- Kevin Bealer (37/79) Jun 05 2004 If the template does one of the unsupported actions, the instantiation w...
- J Anderson (8/15) Jun 05 2004 For bit arrays its not just a question of speed of compilation, its a
- Arcane Jill (30/32) Jun 05 2004 Much as I would love to agree with you(and I would - I really would, bec...
- Lev Elbert (22/55) Jun 05 2004 Agreed!
- Sean Kelly (7/35) Jun 05 2004 Very clever, but the thought of it makes me cringe. If this is what's r...
- hellcatv hotmail.com (10/43) Jun 05 2004 throwing an exception when taking the address of a bit is unacceptible.
- Benji Smith (8/9) Jun 05 2004 I'd also like to see the bit type completely obliterated. The only
- Kevin Bealer (4/13) Jun 05 2004 I never go into the coffee shop on 23rd street, so lets burn it down.
- Antti =?iso-8859-1?Q?Syk=E4ri?= (54/62) Jun 06 2004 More like points in favor of removing "bit" ;)
- J Anderson (17/21) Jun 07 2004 I don't think this saying is always true. Sure its true for small parts...
- Antti =?iso-8859-1?Q?Syk=E4ri?= (16/38) Jun 06 2004 This is insane. (But insane in a good way.) The other idea was to have
- Arcane Jill (15/21) Jun 07 2004 This has always been the case in C++. In C++, if you do this:
- Arcane Jill (31/61) Jun 07 2004 Well it seems that one insane idea of mine (bit-pointers) cannot work. S...
- Matthew (10/75) Jun 07 2004 and
- Andy Friesen (3/4) Jun 07 2004 Yes.
- Norbert Nemec (2/3) Jun 07 2004 You'll want a struct here, I guess? Besides that, I like what you say.
- Arcane Jill (2/3) Jun 07 2004 You're right. Well spotted.
-
Sean Kelly
(11/36)
Jun 05 2004
These are the exact problems vector
has in the C++ standard librar... - Antti =?iso-8859-1?Q?Syk=E4ri?= (5/16) Jun 06 2004 Whopps, that one should be ==
I've just finished reading a hundred-message thread about the boolean type that brought me to the following conclusion: Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like: void catastrophe1(inout bool y) { if (y == false) y = true; } void catastrophe2(bool* y) { if (*y == false) *y = true; } void main() { bool[16] x; catastrophe1(x[5]); catastrophe2(&x[5]); bool* first_bool = &x[0]; bool* second_bool = &x[1]; assert(second_bool == first_bool + 1); assert(cast(int) second_bool = cast(int) first_bool + bool.size); } If you substitute int in place of bit, this works. But not as it is. This is A Bad Thing, and violates several rules that I hold dear: 1) Keep It Simple, Stupid In current D, bit is not just a normal type for which the basic operations can implemented like for any other type. It is the nightmare of D language implementors. It doesn't leave many language features unaffected. The implementation of pointers and references (as in inout and out parameters) has to be rewritten. Slices cannot be implemented that easily either, and I suspect they never will. A slight exaggeration is in place: the boolean type is to D what export is to C++. 2) Occam's Razor (which happens to be the underlying principle of Rule (1)) To understand bool, you have to understand all of its special cases where it doesn't behave as a normal variable behaves. This means that you cannot explain nor understand bool fully without understanding pointers, parameter passing modes, arrays, bitarrays, integer representation, assembly language, etc. And I didn't even mention all of the thousands of different uses that 'bit' might have in templates, of which we don't even *know* yet. And which *will* be broken once we get there. This is a blatant violation of Occam's Razor, one real-life application of which is in learning: One should not increase, beyond what is necessary, the number of entities required to understand other entities. 3) The Rule of Least Surprise of the Unix philosophy, this rule would be of utmost importance especially for the aspiring novice who first encounters the D language. He creates an integer, and lo, an integer is created. He passes it as inout reference, and rejoices of his success. Then, he proceeds to to create a boolean variable, which is fine also. Confidently and determinedly he tries to pass the variable as inout reference. The result: he is utterly disappointed, abandons the language, and turns to another, more logical languages, such as C++ or Scheme. [I could go on about the same thing between ints/structs and classes but everyone knows Java already so this would probably be in vain] The only argument of having bit.size practically 0.125 is that you can use the array syntax to create arrays of bits. Too bad that it just conflicts with the very foundations of the language. *everything else* is byte-addressable, and this basic type is not, and just because a silly bit array. Admit it, the idea of having a bit-sized boolean type was a bad idea. It might've been a clever-sounding trick when it was conceived but hey, in reality it doesn't provide that much value. So let's move on and define a *real* boolean type, for example one of the same size as integer, or maybe a byte. If I were to implement it, it would probably be implemented as a 32-bit integer. false would be 0 and true anything else. Checking for truth would be easy since processors tend to have these "jump if (not) zero" kind of instructions. And testing for truth value (besides assignment) is the first and foremost use for bool. Occasionally you need to convert it to int, and why not have an implicit conversion from false => 0 and true => 1. As easy as that. But nothing so silly as adding too booleans together or anything like that. Heh, if you wanted a smaller bool (to consume less memory), maybe implement bool8 or even bool16 for that purpose. Wouldn't hurt anyone. Besides, having bitarrays implemented as a language-level primitive is an insult to the D language itself. Is the language really so weak that you can't implement a bitset in the standard? Surely you can! The only reason _not_ to implement things in standard library is speed of compilation, which I don't think is a problem with the current D implementation, and optimization opportunities, which I believe can very well be done after the fact if the need arises. So there. -Antti -- I will not be using Plan 9 in the creation of weapons of mass destruction to be used by nations other than the US.
Jun 04 2004
From here on in I shall try my damndest to refrain from further comment, and if anyone asks my opinion, I shall simply refer them to this post. I bow to your succinct wisdom. Matthew "Antti Sykäri" <jsykari gamma.hut.fi> wrote in message news:slrncc26jr.n9h.jsykari pulu.hut.fi...I've just finished reading a hundred-message thread about the boolean type that brought me to the following conclusion: Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like: void catastrophe1(inout bool y) { if (y == false) y = true; } void catastrophe2(bool* y) { if (*y == false) *y = true; } void main() { bool[16] x; catastrophe1(x[5]); catastrophe2(&x[5]); bool* first_bool = &x[0]; bool* second_bool = &x[1]; assert(second_bool == first_bool + 1); assert(cast(int) second_bool = cast(int) first_bool + bool.size); } If you substitute int in place of bit, this works. But not as it is. This is A Bad Thing, and violates several rules that I hold dear: 1) Keep It Simple, Stupid In current D, bit is not just a normal type for which the basic operations can implemented like for any other type. It is the nightmare of D language implementors. It doesn't leave many language features unaffected. The implementation of pointers and references (as in inout and out parameters) has to be rewritten. Slices cannot be implemented that easily either, and I suspect they never will. A slight exaggeration is in place: the boolean type is to D what export is to C++. 2) Occam's Razor (which happens to be the underlying principle of Rule (1)) To understand bool, you have to understand all of its special cases where it doesn't behave as a normal variable behaves. This means that you cannot explain nor understand bool fully without understanding pointers, parameter passing modes, arrays, bitarrays, integer representation, assembly language, etc. And I didn't even mention all of the thousands of different uses that 'bit' might have in templates, of which we don't even *know* yet. And which *will* be broken once we get there. This is a blatant violation of Occam's Razor, one real-life application of which is in learning: One should not increase, beyond what is necessary, the number of entities required to understand other entities. 3) The Rule of Least Surprise of the Unix philosophy, this rule would be of utmost importance especially for the aspiring novice who first encounters the D language. He creates an integer, and lo, an integer is created. He passes it as inout reference, and rejoices of his success. Then, he proceeds to to create a boolean variable, which is fine also. Confidently and determinedly he tries to pass the variable as inout reference. The result: he is utterly disappointed, abandons the language, and turns to another, more logical languages, such as C++ or Scheme. [I could go on about the same thing between ints/structs and classes but everyone knows Java already so this would probably be in vain] The only argument of having bit.size practically 0.125 is that you can use the array syntax to create arrays of bits. Too bad that it just conflicts with the very foundations of the language. *everything else* is byte-addressable, and this basic type is not, and just because a silly bit array. Admit it, the idea of having a bit-sized boolean type was a bad idea. It might've been a clever-sounding trick when it was conceived but hey, in reality it doesn't provide that much value. So let's move on and define a *real* boolean type, for example one of the same size as integer, or maybe a byte. If I were to implement it, it would probably be implemented as a 32-bit integer. false would be 0 and true anything else. Checking for truth would be easy since processors tend to have these "jump if (not) zero" kind of instructions. And testing for truth value (besides assignment) is the first and foremost use for bool. Occasionally you need to convert it to int, and why not have an implicit conversion from false => 0 and true => 1. As easy as that. But nothing so silly as adding too booleans together or anything like that. Heh, if you wanted a smaller bool (to consume less memory), maybe implement bool8 or even bool16 for that purpose. Wouldn't hurt anyone. Besides, having bitarrays implemented as a language-level primitive is an insult to the D language itself. Is the language really so weak that you can't implement a bitset in the standard? Surely you can! The only reason _not_ to implement things in standard library is speed of compilation, which I don't think is a problem with the current D implementation, and optimization opportunities, which I believe can very well be done after the fact if the need arises. So there. -Antti -- I will not be using Plan 9 in the creation of weapons of mass destruction to be used by nations other than the US.
Jun 04 2004
"Antti Sykäri" <jsykari gamma.hut.fi> wrote in message news:slrncc26jr.n9h.jsykari pulu.hut.fi...I've just finished reading a hundred-message thread about the boolean type that brought me to the following conclusion: Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like: void catastrophe1(inout bool y) { if (y == false) y = true; } void catastrophe2(bool* y) { if (*y == false) *y = true; } void main() { bool[16] x; catastrophe1(x[5]); catastrophe2(&x[5]); bool* first_bool = &x[0]; bool* second_bool = &x[1]; assert(second_bool == first_bool + 1); assert(cast(int) second_bool = cast(int) first_bool + bool.size); } If you substitute int in place of bit, this works. But not as it is. This is A Bad Thing, and violates several rules that I hold dear: 1) Keep It Simple, Stupid In current D, bit is not just a normal type for which the basic operations can implemented like for any other type. It is the nightmare of D language implementors. It doesn't leave many language features unaffected. The implementation of pointers and references (as in inout and out parameters) has to be rewritten. Slices cannot be implemented that easily either, and I suspect they never will. A slight exaggeration is in place: the boolean type is to D what export is to C++. 2) Occam's Razor (which happens to be the underlying principle of Rule(1))To understand bool, you have to understand all of its special cases where it doesn't behave as a normal variable behaves. This means that you cannot explain nor understand bool fully without understanding pointers, parameter passing modes, arrays, bitarrays, integer representation, assembly language, etc. And I didn't even mention all of the thousands of different uses that 'bit' might have in templates, of which we don't even *know* yet. And which *will* be broken once we get there. This is a blatant violation of Occam's Razor, one real-life application of which is in learning: One should not increase, beyond what is necessary, the number of entities required to understand other entities. 3) The Rule of Least Surprise of the Unix philosophy, this rule would be of utmost importance especially for the aspiring novice who first encounters the D language. He creates an integer, and lo, an integer is created. He passes it as inout reference, and rejoices of his success. Then, he proceeds to to create a boolean variable, which is fine also. Confidently and determinedly he tries to pass the variable as inout reference. The result: he is utterly disappointed, abandons the language, and turns to another, more logical languages, such as C++ or Scheme. [I could go on about the same thing between ints/structs and classes but everyone knows Java already so this would probably be in vain] The only argument of having bit.size practically 0.125 is that you can use the array syntax to create arrays of bits. Too bad that it just conflicts with the very foundations of the language. *everything else* is byte-addressable, and this basic type is not, and just because a silly bit array. Admit it, the idea of having a bit-sized boolean type was a bad idea. It might've been a clever-sounding trick when it was conceived but hey, in reality it doesn't provide that much value. So let's move on and define a *real* boolean type, for example one of the same size as integer, or maybe a byte. If I were to implement it, it would probably be implemented as a 32-bit integer. false would be 0 and true anything else. Checking for truth would be easy since processors tend to have these "jump if (not) zero" kind of instructions. And testing for truth value (besides assignment) is the first and foremost use for bool. Occasionally you need to convert it to int, and why not have an implicit conversion from false => 0 and true => 1. As easy as that. But nothing so silly as adding too booleans together or anything like that. Heh, if you wanted a smaller bool (to consume less memory), maybe implement bool8 or even bool16 for that purpose. Wouldn't hurt anyone. Besides, having bitarrays implemented as a language-level primitive is an insult to the D language itself. Is the language really so weak that you can't implement a bitset in the standard? Surely you can! The only reason _not_ to implement things in standard library is speed of compilation, which I don't think is a problem with the current D implementation, and optimization opportunities, which I believe can very well be done after the fact if the need arises. So there.Wow. Well said! I agree with you on most of the points, except about bitarrays. The only problem with them is that the current implementation doesn't work (but it probabbly will soon), and that they are also used as boolean value. The only solution as i see it is to leave bit and bit arrays as they are (only fix them), and add a new trully logical type bool. I think there would be no problem where to use witch one: use bit if you need "bit" as in 1/8 of byte and use bool if you need true/false meaning logical true/false. And then all opEquals == < > || and other operators would return (as they should) a bool, and Walter could implement bool in a way he thinks is best :)-Antti -- I will not be using Plan 9 in the creation of weapons of mass destruction to be used by nations other than the US.
Jun 05 2004
1. Your example fails to compile, and fails with a reasonable message, so there is no language bug there. 2. The bit/bit array objects are a *feature*. All the behaviours that that you and the other anti-bit folks want in a boolean ARE ALREADY AVAILABLE in other types. You can use typedef if you are afraid of automatic conversion. 3. You argue that it is hard to understand. Well tough. 4. You argue that you don't need the bit ARRAY functionality. Well then how can you possibly be upset that the example you give doesn't work the way you expect? Go to a hardware store and buy a spray-bomb can of paint. It's easy to use, and the results are okay for graffiti or stencils. If you want to paint a car, you need a better tool. It costs 400 dollars (USD), has at least a dozen adjustments, screws, filters, and levers. It comes with a manual, and if you misuse it in any of 10 ways it will break permanently. It's a power tool. It's not expected to be easy. It's as easy as they could make it WITHOUT sacrificing performance. Bit arrays aren't needed everywhere. Like C, C++, and the professional paint sprayer, they are a power tool. If you want a simple tool with a different interface, don't use them. But getting this functionality to run fast IS very important for a lot of applications, so it should be in the language, not a library. Between enums, the dozens of integer types, and structures, the functionality you want is available. You just have to accept that for "int" semantics, you want the int type. In any case, functions calls like this: AdjustWindow(100, 220, "window1", true, true, false, true); .. Are considered bad form. Don't use true to mean "yes I want beveled edges", instead have an enumerated type (i_Beveled, i_Squared). In short, Walter gave very good reasons for the current behaviour, and none of the posts in these 101 threads has touched on those, except to say "can't the performance penalty just go away in the compiler" (the answer is, no it can't). I find it particularly telling that the post ends in a vague discussion of "lets define a real type", but then mentions a dozen or so conflicting strategies, including multiple bool types of different sizes. If Occam heard that, he would probably cut himself shaving. Then it suggests adding booleans together is evil, which is done in the example code! The reason posts like this wander from strategy to strategy at the end, is that each strategy has either performance issues, missing functionality issues, requires excessive casting, doesn't require enough casting, etc. You're trying to find a solution to a problem, that everyone has a different "intuitively correct solution" to. But you know that the solution you are proposing is broken (i.e. it can't solve all the problems) so you waffle and leave it open ended. Then like a politician, everyone hears their own solution. I want this discussion to end, because I have this bicycle shed I'm building and I'd like to ask everyone's advice on what color to make it... Kevin PS forgive me if this post was meant to be satire... In article <slrncc26jr.n9h.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says...I've just finished reading a hundred-message thread about the boolean type that brought me to the following conclusion: Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like: void catastrophe1(inout bool y) { if (y == false) y = true; } void catastrophe2(bool* y) { if (*y == false) *y = true; } void main() { bool[16] x; catastrophe1(x[5]); catastrophe2(&x[5]); bool* first_bool = &x[0]; bool* second_bool = &x[1]; assert(second_bool == first_bool + 1); assert(cast(int) second_bool = cast(int) first_bool + bool.size); } If you substitute int in place of bit, this works. But not as it is. This is A Bad Thing, and violates several rules that I hold dear: 1) Keep It Simple, Stupid In current D, bit is not just a normal type for which the basic operations can implemented like for any other type. It is the nightmare of D language implementors. It doesn't leave many language features unaffected. The implementation of pointers and references (as in inout and out parameters) has to be rewritten. Slices cannot be implemented that easily either, and I suspect they never will. A slight exaggeration is in place: the boolean type is to D what export is to C++. 2) Occam's Razor (which happens to be the underlying principle of Rule (1)) To understand bool, you have to understand all of its special cases where it doesn't behave as a normal variable behaves. This means that you cannot explain nor understand bool fully without understanding pointers, parameter passing modes, arrays, bitarrays, integer representation, assembly language, etc. And I didn't even mention all of the thousands of different uses that 'bit' might have in templates, of which we don't even *know* yet. And which *will* be broken once we get there. This is a blatant violation of Occam's Razor, one real-life application of which is in learning: One should not increase, beyond what is necessary, the number of entities required to understand other entities. 3) The Rule of Least Surprise of the Unix philosophy, this rule would be of utmost importance especially for the aspiring novice who first encounters the D language. He creates an integer, and lo, an integer is created. He passes it as inout reference, and rejoices of his success. Then, he proceeds to to create a boolean variable, which is fine also. Confidently and determinedly he tries to pass the variable as inout reference. The result: he is utterly disappointed, abandons the language, and turns to another, more logical languages, such as C++ or Scheme. [I could go on about the same thing between ints/structs and classes but everyone knows Java already so this would probably be in vain] The only argument of having bit.size practically 0.125 is that you can use the array syntax to create arrays of bits. Too bad that it just conflicts with the very foundations of the language. *everything else* is byte-addressable, and this basic type is not, and just because a silly bit array. Admit it, the idea of having a bit-sized boolean type was a bad idea. It might've been a clever-sounding trick when it was conceived but hey, in reality it doesn't provide that much value. So let's move on and define a *real* boolean type, for example one of the same size as integer, or maybe a byte. If I were to implement it, it would probably be implemented as a 32-bit integer. false would be 0 and true anything else. Checking for truth would be easy since processors tend to have these "jump if (not) zero" kind of instructions. And testing for truth value (besides assignment) is the first and foremost use for bool. Occasionally you need to convert it to int, and why not have an implicit conversion from false => 0 and true => 1. As easy as that. But nothing so silly as adding too booleans together or anything like that. Heh, if you wanted a smaller bool (to consume less memory), maybe implement bool8 or even bool16 for that purpose. Wouldn't hurt anyone. Besides, having bitarrays implemented as a language-level primitive is an insult to the D language itself. Is the language really so weak that you can't implement a bitset in the standard? Surely you can! The only reason _not_ to implement things in standard library is speed of compilation, which I don't think is a problem with the current D implementation, and optimization opportunities, which I believe can very well be done after the fact if the need arises. So there. -Antti -- I will not be using Plan 9 in the creation of weapons of mass destruction to be used by nations other than the US.
Jun 05 2004
In article <c9rsm1$f7f$1 digitaldaemon.com>, Kevin Bealer says...1. Your example fails to compile, and fails with a reasonable message, so there is no language bug there. 2. The bit/bit array objects are a *feature*. All the behaviours that that you and the other anti-bit folks want in a boolean ARE ALREADY AVAILABLE in other types. You can use typedef if you are afraid of automatic conversion. 3. You argue that it is hard to understand. Well tough.But what about template code? Say I write a template function that manipulates arrays. Why should bool[] be a special case that the function can't operate on? As I said in another message, this is the exact same issue as the vector<bool> specialization in C++. And because of the contention surrounding vector<bool> I don't expect this to be settled amicably either.Bit arrays aren't needed everywhere. Like C, C++, and the professional paint sprayer, they are a power tool. If you want a simple tool with a different interface, don't use them. But getting this functionality to run fast IS very important for a lot of applications, so it should be in the language, not a library.It shouldn't matter whether a feature is in the language or in its standard library, so long as the reason for the choice makes sense. Adding a feature to the language allows for better error handling and integration, but this is not always necessary nor desirable. You say that bit arrays aren't needed everywhere, but by integrating them into the language you require that they be used everywhere whether you want them or not. What does the person who just wants a plain old vector of boolean values do?Between enums, the dozens of integer types, and structures, the functionality you want is available. You just have to accept that for "int" semantics, you want the int type.So why should bool be different? It's a primitive type that can be assigned to and compared. It can be stored in arrays, etc. But taking the address of a bool when it's in an array is illegal? I should back up and say that I am playing devils' advocate to a degree here. This problem wouldn't affect me either way because I know the language well enough to avoid it. But because of the vector<bool> issue I know that it confuse other people. And while I'm typically inclined to say RTFM, I'm not sure that such a special case should be built into the language rather than provided as a library feature. Sean
Jun 05 2004
Sean Kelly wrote:What does the person who just wants a plain old vector of boolean values do?Lots of things. Make an array of enums. -- -Anderson: http://badmama.com.au/~anderson/
Jun 05 2004
In article <c9sp85$1s1t$1 digitaldaemon.com>, Sean Kelly says...In article <c9rsm1$f7f$1 digitaldaemon.com>, Kevin Bealer says...If the template does one of the unsupported actions, the instantiation will fail to compile with an appropriate error. If you don't do anything forbidden (you avoid passing references to array elements) it will work. If it fails for bit vectors, you need to decide based on the purpose of the code; either: 1. The template writer specializes an internal template interface for bit array (I don't know if this can be done), and provides another solution. 2. The template writer creates a nested struct like: "struct foo { T x; }" and thus wraps the type in a safe manner. 3. The user uses "int" or "byte" for the "yes/no" value. If you want a "packed bit vector", then you must understand that it is not byte addressable so certain things fail. I can sympathize with the template argument, but the value of packed bit arrays to me overrides the "aesthetic" issue that there is more asymmetry.1. Your example fails to compile, and fails with a reasonable message, so there is no language bug there. 2. The bit/bit array objects are a *feature*. All the behaviours that that you and the other anti-bit folks want in a boolean ARE ALREADY AVAILABLE in other types. You can use typedef if you are afraid of automatic conversion. 3. You argue that it is hard to understand. Well tough.But what about template code? Say I write a template function that manipulates arrays. Why should bool[] be a special case that the function can't operate on? As I said in another message, this is the exact same issue as the vector<bool> specialization in C++. And because of the contention surrounding vector<bool> I don't expect this to be settled amicably either.Just use int[] or byte[], according to taste. Yes, I realize that it doesn't self-document as much as if it said "bool". But why have "bit" if it has no special behavior?Bit arrays aren't needed everywhere. Like C, C++, and the professional paint sprayer, they are a power tool. If you want a simple tool with a different interface, don't use them. But getting this functionality to run fast IS very important for a lot of applications, so it should be in the language, not a library.It shouldn't matter whether a feature is in the language or in its standard library, so long as the reason for the choice makes sense. Adding a feature to the language allows for better error handling and integration, but this is not always necessary nor desirable. You say that bit arrays aren't needed everywhere, but by integrating them into the language you require that they be used everywhere whether you want them or not. What does the person who just wants a plain old vector of boolean values do?Because it can probably be done more efficiently, when it comes to bit slicing for example. Although, I don't know the performance details, so maybe it actually makes no difference. Also, int->bit converts with "?:" semantics, not "& 1" semantics, which makes it a special case among the integer types. Most would agree that this is good, assuming they like the ability to convert at all. I guess when someone says "this is hard to learn", I'm inclined to make them reach for it. bit[] and char[] and wchar[] are all special: bit can't take addresses of elements, and char[] and wchar[] have special case conversion to larger unicode char sizes. dchar[] probably converts down, but I'm not sure. And why are hash tables the only associative array type? I'd like an ordered set as well. Why does ".sort" use a qsort/heapsort technique? There are other algorithms, it would be neat to be able to choose one. I could probably go on, if I thought for a minute. All these choices could be second-guessed, but in each case the existing method is at least pretty good. And I'd be happy to second guess at least some of them, and probably will do so over time (although not the examples I gave above). But after 100 messages, I would also be willing to let it die. KevinBetween enums, the dozens of integer types, and structures, the functionality you want is available. You just have to accept that for "int" semantics, you want the int type.So why should bool be different? It's a primitive type that can be assigned to and compared. It can be stored in arrays, etc. But taking the address of a bool when it's in an array is illegal? I should back up and say that I am playing devils' advocate to a degree here. This problem wouldn't affect me either way because I know the language well enough to avoid it. But because of the vector<bool> issue I know that it confuse other people. And while I'm typically inclined to say RTFM, I'm not sure that such a special case should be built into the language rather than provided as a library feature. Sean
Jun 05 2004
Antti Sykäri wrote:The only reason _not_ to implement things in standard library is speed of compilation, which I don't think is a problem with the current D implementation, and optimization opportunities, which I believe can very well be done after the fact if the need arises. So there. -AnttiFor bit arrays its not just a question of speed of compilation, its a question of readability. To make a bit array as efficient as D has the chance to be, you need all sorts of ugly bitwise operations. Obviously it could be implemented into a struct but then you still lose some efficiency and readability. -- -Anderson: http://badmama.com.au/~anderson/
Jun 05 2004
In article <slrncc26jr.n9h.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says...Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like:Much as I would love to agree with you(and I would - I really would, because I want a working bool type as much as anyone), your points are not actually points in favor of making bool=int, they are points in favor of FIXING THE BUGS IN "bit". (Obviously I agree with you on both counts though). If we are going to have a type, bit, which behaves like a primative type, then it must be properly implemented. It must be possible to take the address of a bit. Pointer arithmetic must work. Slicing, both by copy and by reference, must work, even on non-byte boundaries. There is a way that this can be done easily - but I suspect that a lot of people won't like it. The D compiler needs to take these three steps (and they are not trivial). (1) The property bit.sizeof() must return a float or a double, not an int, with value 0.125. (2) Taking the address of a bit must return a new type, a "bit pointer". The simplest way to implement this is as double. Doubles can store a superset of the values that uints can store, and in addition they are capable of handling those 0.125 fractional parts. Example, bit 0 at byte-address 1193046 would have bit-address 1193046.0; bit 1 at the same byte-address would have bit-address 1193046.0125, and so on. (3) Given that currently, slices consist of a struct containing a pointer and a length, so bit-slices must consist of a struct containing a bit-pointer as described above, and a length. Walter may be able to think of other ways of achieving this, as he's a smart guy. But the only reasonable alternative to unambiguously succeeding (when taking the address of a bit), is throwing an exception. Returning a byte-address can only ever lead to undefined behaviour. Same goes for bitslicing on not-necessarily-byte boundaries. Arcane Jill
Jun 05 2004
Agreed! Bit on modern processors is not an addressable object. So it should not be a regular language object. "Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9s72o$1108$1 digitaldaemon.com...In article <slrncc26jr.n9h.jsykari pulu.hut.fi>, Antti=?iso-8859-1?Q?Syk=E4ri?=says...because IBoolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like:Much as I would love to agree with you(and I would - I really would,want a working bool type as much as anyone), your points are not actuallypointsin favor of making bool=int, they are points in favor of FIXING THE BUGSIN"bit". (Obviously I agree with you on both counts though). If we are going to have a type, bit, which behaves like a primative type,thenit must be properly implemented. It must be possible to take the addressof abit. Pointer arithmetic must work. Slicing, both by copy and by reference,mustwork, even on non-byte boundaries. There is a way that this can be done easily - but I suspect that a lot ofpeoplewon't like it. The D compiler needs to take these three steps (and theyare nottrivial). (1) The property bit.sizeof() must return a float or a double, not an int,withvalue 0.125. (2) Taking the address of a bit must return a new type, a "bit pointer".Thesimplest way to implement this is as double. Doubles can store a supersetof thevalues that uints can store, and in addition they are capable of handlingthose0.125 fractional parts. Example, bit 0 at byte-address 1193046 would have bit-address 1193046.0; bit 1 at the same byte-address would havebit-address1193046.0125, and so on. (3) Given that currently, slices consist of a struct containing a pointerand alength, so bit-slices must consist of a struct containing a bit-pointer as described above, and a length. Walter may be able to think of other ways of achieving this, as he's asmartguy. But the only reasonable alternative to unambiguously succeeding (when taking the address of a bit), is throwing an exception. Returning abyte-addresscan only ever lead to undefined behaviour. Same goes for bitslicing on not-necessarily-byte boundaries. Arcane Jill
Jun 05 2004
In article <c9s72o$1108$1 digitaldaemon.com>, Arcane Jill says...In article <slrncc26jr.n9h.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says...Exactly :)Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like:Much as I would love to agree with you(and I would - I really would, because I want a working bool type as much as anyone), your points are not actually points in favor of making bool=int, they are points in favor of FIXING THE BUGS IN "bit". (Obviously I agree with you on both counts though).There is a way that this can be done easily - but I suspect that a lot of people won't like it. The D compiler needs to take these three steps (and they are not trivial). (1) The property bit.sizeof() must return a float or a double, not an int, with value 0.125. (2) Taking the address of a bit must return a new type, a "bit pointer". The simplest way to implement this is as double. Doubles can store a superset of the values that uints can store, and in addition they are capable of handling those 0.125 fractional parts. Example, bit 0 at byte-address 1193046 would have bit-address 1193046.0; bit 1 at the same byte-address would have bit-address 1193046.0125, and so on. (3) Given that currently, slices consist of a struct containing a pointer and a length, so bit-slices must consist of a struct containing a bit-pointer as described above, and a length.Very clever, but the thought of it makes me cringe. If this is what's required then I'd prefer to just leave everything as-is.Walter may be able to think of other ways of achieving this, as he's a smart guy. But the only reasonable alternative to unambiguously succeeding (when taking the address of a bit), is throwing an exception. Returning a byte-address can only ever lead to undefined behaviour. Same goes for bitslicing on not-necessarily-byte boundaries.I'd prefer to issue a compiler error in this case. Exceptions would be a last resort. Sean
Jun 05 2004
throwing an exception when taking the address of a bit is unacceptible. this can be detected at compile time since we know the type info, no? compile time errors folks :-) personally I'm in favor of abolishing bit in the following manner: make bit a temporary alias to bool. make it size 1 (byte) or 4 (int) most things (except bit packing) will still work before it's thrown out... then just axe it and have a pakced_vector!(bool) in the D template lib. I would say also compile time error when trying to bitslice a bit array. In article <c9s72o$1108$1 digitaldaemon.com>, Arcane Jill says...In article <slrncc26jr.n9h.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says...Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like:Much as I would love to agree with you(and I would - I really would, because I want a working bool type as much as anyone), your points are not actually points in favor of making bool=int, they are points in favor of FIXING THE BUGS IN "bit". (Obviously I agree with you on both counts though). If we are going to have a type, bit, which behaves like a primative type, then it must be properly implemented. It must be possible to take the address of a bit. Pointer arithmetic must work. Slicing, both by copy and by reference, must work, even on non-byte boundaries. There is a way that this can be done easily - but I suspect that a lot of people won't like it. The D compiler needs to take these three steps (and they are not trivial). (1) The property bit.sizeof() must return a float or a double, not an int, with value 0.125. (2) Taking the address of a bit must return a new type, a "bit pointer". The simplest way to implement this is as double. Doubles can store a superset of the values that uints can store, and in addition they are capable of handling those 0.125 fractional parts. Example, bit 0 at byte-address 1193046 would have bit-address 1193046.0; bit 1 at the same byte-address would have bit-address 1193046.0125, and so on. (3) Given that currently, slices consist of a struct containing a pointer and a length, so bit-slices must consist of a struct containing a bit-pointer as described above, and a length. Walter may be able to think of other ways of achieving this, as he's a smart guy. But the only reasonable alternative to unambiguously succeeding (when taking the address of a bit), is throwing an exception. Returning a byte-address can only ever lead to undefined behaviour. Same goes for bitslicing on not-necessarily-byte boundaries. Arcane Jill
Jun 05 2004
On Sat, 5 Jun 2004 19:11:33 +0000 (UTC), hellcatv hotmail.com wrote:personally I'm in favor of abolishing bit in the following manner:I'd also like to see the bit type completely obliterated. The only really justifiable use for a bit type (that I'm aware of) is when the bits are packed into an array. So, instead of having an actual bit type, I'd like to see a packedbit type. Of course, just like everyone else here, I'd like to see a real boolean type. I think the combination of boolean and packedbit would solve most people's real-life needs.
Jun 05 2004
In article <cnr4c0debnt9d1ug1e3gjjvmtls5o8qce8 4ax.com>, Benji Smith says...On Sat, 5 Jun 2004 19:11:33 +0000 (UTC), hellcatv hotmail.com wrote:I never go into the coffee shop on 23rd street, so lets burn it down. You don't need it, but how does it hurt you? Kevinpersonally I'm in favor of abolishing bit in the following manner:I'd also like to see the bit type completely obliterated. The only really justifiable use for a bit type (that I'm aware of) is when the bits are packed into an array. So, instead of having an actual bit type, I'd like to see a packedbit type.Of course, just like everyone else here, I'd like to see a real boolean type. I think the combination of boolean and packedbit would solve most people's real-life needs.
Jun 05 2004
Arcane Jill:Much as I would love to agree with you(and I would - I really would, because I want a working bool type as much as anyone), your points are not actually points in favor of making bool=int, they are points in favor of FIXING THE BUGS IN "bit".More like points in favor of removing "bit" ;) Kevin Bealer:I find it particularly telling that the post ends in a vague discussion of "lets define a real type", but then mentions a dozen or so conflicting strategies, including multiple bool types of different sizes. If Occam heard that, he would probably cut himself shaving.I'm not really making any suggestions whether bool should be int, short or byte, and probably it doesn't really matter. All that matters from the language designer point of view is: 1) sane semantics (!= returns bool, if () requires bool, etc.), ability to overload on a boolean argument, ability to treat it as an lvalue like other types (for example by slicing it and taking address of a bool value) and, less importantly, 2) micro-efficiency (issues with the size of the boolean type, and its implementation - which must be ultimately resolved by creating different implementations of bool and actually TESTING them on a big amount of real-world code) Now, we should be thinking mainly about (1). Use a dummy implementation of bool (e.g. enum bool : uint { false = 0, true = 1 }) and GET THE SEMANTICS RIGHT. Premature optimization is... you know damn right. About (1), I'm just saying that it's best that the boolean type isn't "bit" as it currently exists in D. In fact, bit isn't very good basic type in the first place, so it might as well be discarded altogether. On the other hand, if we had a "real" (byte-addressable) boolean type, maybe bit could serve as a special-case type for the special-case need of creating bit arrays (in fact, it would be a fine replacement of C's bitfields.) As for the point (2) -- as a incurable performance-fanatic, I also made some tests which are in no way conclusive. I wrote a little test program to try out the performance of the following types as booleans: - bit - enum { _false, _true } - int (as in 0/!0) - short - ubyte The results show that 0/1 versions -- bit and enum -- seem to be a little faster (3%) because of relative slowness of generating a truth value of the equality of two integers (the expensive !(a-b) operation). This with P4/2.8GHz machine and optimized (but no -inline). I didn't look at the generated assembly because I haven't found a disassembler for windows which could print out the labels of the (template) functions as well. (Suggestions will be gladly taken.) And I think DMD doesn't have an option to print out assembly either. Also, the test was performed completely unscientifically and in no way reflects how things are done in actual code. In actuality, I suspect, much of the boolean information is held in the processor's registers and flags and the optimizer is pretty much free to do anything with them, like mark some register as having a complement of some truth value if it's faster to compute than the actual value. So in fact the performances of the two types of boolean might be much closer to each other. -Antti -- I will not be using Plan 9 in the creation of weapons of mass destruction to be used by nations other than the US.
Jun 06 2004
Antti Sykäri wrote:Arcane Jill: Premature optimization is... you know damn right.I don't think this saying is always true. Sure its true for small parts of code which can easily be changed but its not true for the big picture type code. To have something run efficiency it must be designed right from the start. Since high level design just about always will save the most efficiency. Take a look at something like quake, if the design wasn't thought though from the start it would be dead slow. For instance without for-thought for a good hidden surface removal algorithm (which removes 99% of polygons), which is difficult to add after the engine is built, quake would have ran hundreds of times slower. So I say get the design right in the beginning but worry about the minor optimisations later. In this bit example, it may mean that bit cannot do everything you want because doing so would prevent optimisation in the future. -- -Anderson: http://badmama.com.au/~anderson/
Jun 07 2004
In article <c9s72o$1108$1 digitaldaemon.com>, Arcane Jill wrote:If we are going to have a type, bit, which behaves like a primative type, then it must be properly implemented. It must be possible to take the address of a bit. Pointer arithmetic must work. Slicing, both by copy and by reference, must work, even on non-byte boundaries. There is a way that this can be done easily - but I suspect that a lot of people won't like it. The D compiler needs to take these three steps (and they are not trivial). (1) The property bit.sizeof() must return a float or a double, not an int, with value 0.125. (2) Taking the address of a bit must return a new type, a "bit pointer". The simplest way to implement this is as double. Doubles can store a superset of the values that uints can store, and in addition they are capable of handling those 0.125 fractional parts. Example, bit 0 at byte-address 1193046 would have bit-address 1193046.0; bit 1 at the same byte-address would have bit-address 1193046.0125, and so on. (3) Given that currently, slices consist of a struct containing a pointer and a length, so bit-slices must consist of a struct containing a bit-pointer as described above, and a length.This is insane. (But insane in a good way.) The other idea was to have the pointer to the byte and index of the bit, but I suppose a double solves the problem as well. Only problems being the different sizes of T* and bit* (with pretty much any T), and different sizes of slices-in-general and slices-to-bits. So you couldn't cast bit* to a void* and back without losing information. (Or then void* would have to be a 64-bit number, which probably won't happen.) Oh yeah, and 64-bit architectures. Something reminds me of segment horrors of the 16-bit age. Maybe Walter already has plans for this? -Antti -- I will not be using Plan 9 in the creation of weapons of mass destruction to be used by nations other than the US.
Jun 06 2004
In article <slrncc7c3b.pd5.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says...Only problems being the different sizes of T* and bit* (with pretty much any T), and different sizes of slices-in-general and slices-to-bits. So you couldn't cast bit* to a void* and back without losing information.This has always been the case in C++. In C++, if you do this:// given char * p; int * q = (int *) p; char * r = (char *) q;there is no guarantee that r will equal p. The compiler is free to ensure that, for example, (int *)s are int-aligned, by zeroing the low order bits. While this doesn't happen on Windows or Linux, there do exist architectures for which this behavior would make perfect sense. Maybe D doesn't do this right now. But if D is ever ported onto, say, a Starcore 8102 based architecture, it may have no choice. But none of this matters, for one simple reason. If the code contains an EXPLICIT cast, then the compiler is free to assume that the programmer knows what they are doing, and that they are doing it deliberately. That's what an explicit cast MEANS. In this circumstance, it won't be the compiler's fault if things break, it will be the programmer's. Jill
Jun 07 2004
Well it seems that one insane idea of mine (bit-pointers) cannot work. Such a beast would conflict with the D ABI (nice new document there!) which clearly and permanently lays down the law on the format for dynamic arrays. So you can't have bit-pointers. That means that nothing involving taking the address of a bit can ever work. Nor can passing a bit to a function as an inout parameter. Nor can bitslicing on non-byte boundaries. I didn't seriously expect anyone to implement bit-pointers, but the fact is, without them, the bit type is disfunctional. It can never behave as other types. So maybe, as others have suggested, it might be time to let it go. The bit type was a brilliant concept, and if it could have been made to work that would truly have been a feature and an eighth. But now we've been there, tried it, done that, and bought the T-shirt. Maybe now we should try for something different. No-one disputes that we need a packed bit array - it's just the bit /itself/ which is causing the problem. To be honest, I think that all we really need is something which does this: class BitArray{ this(uint n); // assign the first 32 bits this(ulong n); // assign the first 64 bits this(void* p, uint byteLen); // assign any number of bits uint toUint(); ulong toUlong(); void write(void* p, uint byteLen); bool opIndex(uint i); // whatever bool is aliased to int opIndex(uint i, bool value); int opIndexAssign(uint i, bool value); int opEquals(Object o); BitArray opSlice(uint i, uint j); BitArray opSliceAssign(uint i, uint j, BitArray a); BitArray opCat(BitArray b); BitArray opCatAssign(BitArray b); BitArray opAnd(BitArray b); BitArray opAndAssign(BitArray b); BitArray opOr(BitArray b); BitArray opOrAssign(BitArray b); BitArray opXor(BitArray b); BitArray opXorAssign(BitArray b); BitArray opCom(); BitArray opShl(uint n); BitArray opShlAssign(uint n); BitArray opShr(uint n); BitArray opShrAssign(uint n); uint length(); uint length(uint newLength); BitArray dup(); }(which, incidently, is more functionality that bit[] arrays have at the moment). That's pretty basic, but it'd be pretty easy to write. I could probably do that in a day. Do we need the bit - at all? I mean, given that pointer semantics are never going to work like they do for other types even IF the bugs are fixed. Plus it'd be good for Walter (sort of) - no bits; no complaints. Templates will work equally well for all types. Problem solved. Someone had to try to introduce the bit, and Walter had the guts to do it. I'm proud of him for that. But when things don't work out, sometimes you just have to call it a day. I don't want to start yet ANOTHER round of what a bit/bool should or shouldn't be. Just a simple thought this time ... is it time to ditch the bit now? Is it time for a feature unrequest? I'd like to know the mood of the D users here generally. Arcane Jill
Jun 07 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:ca1mdn$2on9$1 digitaldaemon.com...Well it seems that one insane idea of mine (bit-pointers) cannot work. Such a beast would conflict with the D ABI (nice new document there!) which clearlyandpermanently lays down the law on the format for dynamic arrays. So you can't have bit-pointers. That means that nothing involving taking the address of a bit can ever work. Nor can passing a bit to a function as an inout parameter. Nor can bitslicing on non-byte boundaries. I didn't seriously expect anyone to implement bit-pointers, but the fact is, without them, the bit type is disfunctional. It can never behave as othertypes.So maybe, as others have suggested, it might be time to let it go. The bit type was a brilliant concept, and if it could have been made to work that wouldtrulyhave been a feature and an eighth. But now we've been there, tried it, done that, and bought the T-shirt. Maybe now we should try for something different. No-one disputes that we need a packed bit array - it's just the bit /itself/ which is causing the problem. To be honest, I think that all we really need is something which does this: class BitArraymoment).{ this(uint n); // assign the first 32 bits this(ulong n); // assign the first 64 bits this(void* p, uint byteLen); // assign any number of bits uint toUint(); ulong toUlong(); void write(void* p, uint byteLen); bool opIndex(uint i); // whatever bool is aliased to int opIndex(uint i, bool value); int opIndexAssign(uint i, bool value); int opEquals(Object o); BitArray opSlice(uint i, uint j); BitArray opSliceAssign(uint i, uint j, BitArray a); BitArray opCat(BitArray b); BitArray opCatAssign(BitArray b); BitArray opAnd(BitArray b); BitArray opAndAssign(BitArray b); BitArray opOr(BitArray b); BitArray opOrAssign(BitArray b); BitArray opXor(BitArray b); BitArray opXorAssign(BitArray b); BitArray opCom(); BitArray opShl(uint n); BitArray opShlAssign(uint n); BitArray opShr(uint n); BitArray opShrAssign(uint n); uint length(); uint length(uint newLength); BitArray dup(); }(which, incidently, is more functionality that bit[] arrays have at theThat's pretty basic, but it'd be pretty easy to write. I could probably do that in a day. Do we need the bit - at all? I mean, given that pointer semantics are never going to work like they do for other types even IF the bugs are fixed. Plusit'dbe good for Walter (sort of) - no bits; no complaints. Templates will work equally well for all types. Problem solved. Someone had to try to introduce the bit, and Walter had the guts to do it. I'm proud of him for that. But when things don't work out, sometimes you just have to call it a day. I don't want to start yet ANOTHER round of what a bit/bool should or shouldn't be. Just a simple thought this time ... is it time to ditch the bit now? Is it time for a feature unrequest? I'd like to know the mood of the D users here generally.scalar: bool is a typedef, or alias, for int bit: does not exist vector: BitArray class, maybe as you describe above.
Jun 07 2004
Arcane Jill wrote:[.. smart things ..]Yes. -- andy
Jun 07 2004
Arcane Jill wrote:class BitArrayYou'll want a struct here, I guess? Besides that, I like what you say.
Jun 07 2004
In article <ca3jcp$2onj$2 digitaldaemon.com>, Norbert Nemec says...You'll want a struct here, I guess?You're right. Well spotted.
Jun 07 2004
In article <slrncc26jr.n9h.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says...I've just finished reading a hundred-message thread about the boolean type that brought me to the following conclusion: Boolean types are basic types and should be reasoned about in the same way as any other type. This includes doing things like: void catastrophe1(inout bool y) { if (y == false) y = true; } void catastrophe2(bool* y) { if (*y == false) *y = true; } void main() { bool[16] x; catastrophe1(x[5]); catastrophe2(&x[5]); bool* first_bool = &x[0]; bool* second_bool = &x[1]; assert(second_bool == first_bool + 1); assert(cast(int) second_bool = cast(int) first_bool + bool.size); } If you substitute int in place of bit, this works. But not as it is.These are the exact problems vector<bool> has in the C++ standard library, and something I think should be corrected in both D and in C++. If a method can't be found to provide a hidden proxy value for such things then I'd be willing to lose the automatic space savings and have bool always be one byte or larger. There are certainly times when I do need the space efficiency single bit storage provides, but not always, and not always at the expense of subtly broken code. I'd be quite willing to settle for a special container that does bit packing and leave bool[] as a normal byte array. Sean
Jun 05 2004
In article <slrncc26jr.n9h.jsykari pulu.hut.fi>, Antti Sykäri wrote:void main() { bool[16] x; catastrophe1(x[5]); catastrophe2(&x[5]); bool* first_bool = &x[0]; bool* second_bool = &x[1]; assert(second_bool == first_bool + 1);assert(cast(int) second_bool = cast(int) first_bool + bool.size);Whopps, that one should be == I _do_ test my code before I post it, but this time I only fixed in the real code, not the code in the article :) -A}
Jun 06 2004