www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - More D newb questions.

reply "Me Here" <p9e883002 sneakemail.com> writes:
Hi all,

I getting error message from the following code that I do not know how to
interpret.
(Please don't critique the code. Its just an exercise :)

char[4] table[65536];

void buildTable() {
    char[] abcd = "abcd";
    
    for( ushort b1 = 0; b1 < 4; b1++ ) {
        for( ushort b2 = 0; b2 < 4; b2++ ) {
            for( ushort b3 = 0; b3 < 4; b3++ ) {
                for( ushort b4 = 0; b4 < 4; b4++ ) {
                    for( ushort b5 = 0; b5 < 4; b5++ ) {
                        for( ushort b6 = 0; b6 < 4; b6++ ) {
                            for( ushort b7 = 0; b7 < 4; b7++ ) {
                                for( ushort b8 = 0; b8 < 4; b8++ ) {
                                    table[ 
                                        ( b1 << 14 ) | ( b2 << 12 ) | 
                                        ( b3 << 10 ) | ( b4 <<  8 ) |
                                        ( b5 <<  6 ) | ( b6 <<  4 ) | 
                                        ( b7 <<  2 ) | b8
/* line 88 */                       ] = abcd[ b1 ] ~ abcd[ b2 ] ~ abcd[ b3 ] ~
abcd[ b4 ]
                                      ~ abcd[ b5 ] ~ abcd[ b6 ] ~ abcd[ b7 ] ~
abcd[ b8 ];
                                   
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

The errors:
c:\dmd\test>dmd -O -inline count2Bit.d
count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)

count2Bit.d(88): Error: cannot assign to static array table[
    cast(uint)( cast(int)b1 << 14 | cast(int)b2 << 12 | cast(int)b3 << 10 |
cast(int)b4 << 8 |
    cast(int)b5 << 6 | cast(int)b6 << 4 | cast(int)b7 << 2 | cast(int)b8)
]

Why does D think I'm trying to concatenate ints, when teh only expressions
involving catenation are
slices of char[] abcd?

Why is D casting my carefully specified ushorts to ints when doing
bit-twiddling?
I am specifically trying to avoid signed operations. Even promotion to uints
would seem
unnecessary, but its?

Finally, is it possible to populate a static lookup table at runtime? 
Or should I just return a ref to the table and assignit to a const pointer in
the caller stack?

Cheers, b.
-- 
May 05 2008
next sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
Me Here wrote:
 Hi all,
 
 I getting error message from the following code that I do not know how to
 interpret.
 (Please don't critique the code. Its just an exercise :)
 
 char[4] table[65536];
 
 void buildTable() {
     char[] abcd = "abcd";
     
     for( ushort b1 = 0; b1 < 4; b1++ ) {
         for( ushort b2 = 0; b2 < 4; b2++ ) {
             for( ushort b3 = 0; b3 < 4; b3++ ) {
                 for( ushort b4 = 0; b4 < 4; b4++ ) {
                     for( ushort b5 = 0; b5 < 4; b5++ ) {
                         for( ushort b6 = 0; b6 < 4; b6++ ) {
                             for( ushort b7 = 0; b7 < 4; b7++ ) {
                                 for( ushort b8 = 0; b8 < 4; b8++ ) {
                                     table[ 
                                         ( b1 << 14 ) | ( b2 << 12 ) | 
                                         ( b3 << 10 ) | ( b4 <<  8 ) |
                                         ( b5 <<  6 ) | ( b6 <<  4 ) | 
                                         ( b7 <<  2 ) | b8
 /* line 88 */                       ] = abcd[ b1 ] ~ abcd[ b2 ] ~ abcd[ b3 ] ~
 abcd[ b4 ]
                                       ~ abcd[ b5 ] ~ abcd[ b6 ] ~ abcd[ b7 ] ~
 abcd[ b8 ];
                                    
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
 }
 
 The errors:
 c:\dmd\test>dmd -O -inline count2Bit.d
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 
 count2Bit.d(88): Error: cannot assign to static array table[
     cast(uint)( cast(int)b1 << 14 | cast(int)b2 << 12 | cast(int)b3 << 10 |
 cast(int)b4 << 8 |
     cast(int)b5 << 6 | cast(int)b6 << 4 | cast(int)b7 << 2 | cast(int)b8)
 ]
 
 Why does D think I'm trying to concatenate ints, when teh only expressions
 involving catenation are
 slices of char[] abcd?
 
 Why is D casting my carefully specified ushorts to ints when doing
 bit-twiddling?
 I am specifically trying to avoid signed operations. Even promotion to uints
 would seem
 unnecessary, but its?
 
 Finally, is it possible to populate a static lookup table at runtime? 
 Or should I just return a ref to the table and assignit to a const pointer in
 the caller stack?
 
 Cheers, b.

Hi Me Here, void main() { char[4] table; table = 'a' ~ 'b'; } main.d(4): Error: Can only concatenate arrays, not (int ~ int) (and other errors) 'a' and 'b' are chars, and you can only concatenate char[]. It seems the compiler is casting 'a' and 'b' to int before concatenating, I don't know why. That's why in your example you get the same error. import std.string; toString('a') ~ toString('b') works, but I wonder... why you can't concatenate primitives and let the compiler concatenate them by automatically calling toString?
May 05 2008
prev sibling next sibling parent reply BCS <BCS pathlink.com> writes:
Me Here wrote:
 /* line 88 */                       ] = abcd[ b1 ] ~ abcd[ b2 ] ~ abcd[ b3 ] ~
 abcd[ b4 ]
                                       ~ abcd[ b5 ] ~ abcd[ b6 ] ~ abcd[ b7 ] ~
 abcd[ b8 ];
 
 The errors:
 c:\dmd\test>dmd -O -inline count2Bit.d
 count2Bit.d(88): Error: Can only concatenate arrays, not (int ~ int)
 
 Why does D think I'm trying to concatenate ints, when teh only expressions
 involving catenation are
 slices of char[] abcd?
 

for one thing "abcd[b1]" is not a slice, if you want a slice use "abcd[b1..b1+1]"
May 05 2008
next sibling parent reply "Me Here" <p9e883002 sneakemail.com> writes:
BCS wrote:


 for one thing "abcd[b1]" is not a slice, if you want a slice use
 "abcd[b1..b1+1]"

Yeah. Its just another tacky inconsistancy. int main( char[][] args ) { char[] a = "x"; char b = 'x'; writefln( a ~ b ); writefln( a ); // writefln( b ~ b ); return 1; } ouputs: xx x So, D knows how to concatenate a single character char[] with a char and produce an intermediate result. Ie. The char[] isn't mutated. But uncomment the line that attempts to concatenate char to char, and you get: junk.d(8): Error: Can only concatenate arrays, not (int ~ int) which is silly. There's no technical reason for not allowing this. And there's no semantic reason either. What elese could 'a' ~ 'b' mean other than char[] tmp = "ab"? Similarly, there's no technical reason for not allowing lvalue slice assignments to grow or shrink the target, or do overlapping copies. Such things are relatively trivial to write and are a part of library. But every programmer having to write their own code to detect whether the source and target of slice assignments are different sizes, or overlap, at each site and decide whether they can use a slice assignment or must revert to calling a library function is a nonsense. D's built-in string handling is rapidly loosing it shine for me :( b. --
May 05 2008
next sibling parent reply BCS <BCS pathlink.com> writes:
Me Here wrote:
 BCS wrote:
 
 
 
for one thing "abcd[b1]" is not a slice, if you want a slice use
"abcd[b1..b1+1]"

Yeah. Its just another tacky inconsistancy.

it's not really inconsistent (see below)
 
 int main( char[][] args ) {
     char[] a = "x";
     char b = 'x';
     writefln( a ~ b );
     writefln( a );
 //    writefln( b ~ b );
     return 1;
 }
 ouputs:
 
 xx
 x
 
 So, D knows how to concatenate a single character char[] with a char 
 and produce an intermediate result. Ie. The char[] isn't mutated.
 
 But uncomment the line that attempts to concatenate char to char, and you get:
 
     junk.d(8): Error: Can only concatenate arrays, not (int ~ int)
 
 which is silly. There's no technical reason for not allowing this. 
 And there's no semantic reason either. 

if Type ~ Type -> Type[] then why would Type[] ~ Type[] -> Type[] based on what you ask for this would be valid char[] a, b; char[][] c = a ~ b; // ok char[] d = a ~ b; // same expression, different type? auto e = a ~ b; // what's the type of this then? but for that to work you would need to look up and down the expression tree just to figure out what something is. That gets just plain nasty.
 What elese could 'a' ~ 'b' mean other than char[] tmp = "ab"?
 
 Similarly, there's no technical reason for not allowing 
 lvalue slice assignments to grow or shrink the target,
 or do overlapping copies. 

I think there is a reason for it. D is a low level language, the semantic you are asking for can be done in a function and, if included in a language, would hide some types of errors. IMHO D should not have any semantics that are not easy for the program to understand how they are working. for example, If I understand you correctly you would like this to work: char[] t = "hello world"; auto u = t; auto v = u[8]; t[5..5] = ","; assert(t == "hello, world"); but this results in all sorts of fun stuff like "non-accessed" data changing: assert(v == u[8]); // it changes but I didn't change it.
 
 Such things are relatively trivial to write and are a part of library.
 But every programmer having to write their own code to detect
 whether the source and target of slice assignments are different
 sizes, or overlap, at each site and decide whether they can use a 
 slice assignment or must revert to calling a library function 
 is a nonsense.

IIRC the reason that overlapping copies are not allow is that the overhead of checking them is non trivial and the code to do the copy is to. D is taking the approach of "most copies are never overlapping and if you need might need it say so" In a higher level language this would be a problem, but for what D is intended for, this isn't a problem.
May 05 2008
parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 05 May 2008 13:58:16 -0700, BCS wrote:


 based on what you ask for this would be valid
 
 char[] a, b;
 char[][] c = a ~ b; // ok
 char[]   d = a ~ b; // same expression, different type?
 auto     e = a ~ b; // what's the type of this then?

It would be 'char[]' of course, because 'a' is char[]. The convention for the determining the 'auto' type based on the first identifier is already an established concept in D.
 but for that to work you would need to look up and down the expression 
 tree just to figure out what something is. That gets just plain nasty.
 
 What elese could 'a' ~ 'b' mean other than char[] tmp = "ab"?
 
 Similarly, there's no technical reason for not allowing 
 lvalue slice assignments to grow or shrink the target,
 or do overlapping copies. 

I think there is a reason for it. D is a low level language, the semantic you are asking for can be done in a function and, if included in a language, would hide some types of errors. IMHO D should not have any semantics that are not easy for the program to understand how they are working. for example, If I understand you correctly you would like this to work: char[] t = "hello world"; auto u = t; auto v = u[8]; t[5..5] = ","; assert(t == "hello, world");

Huh? Why would the length change? t[5..5] = "," should fail because the left and right sides of the assign are different lengths.
 
 IIRC the reason that overlapping copies are not allow is that the 
 overhead of checking them is non trivial and the code to do the copy is 
 to. 

And yet D fails at runtime if you attempt an overlap so it must already be doing such checking.
 D is taking the approach of "most copies are never overlapping and 
 if you need might need it say so" In a higher level language this would 
 be a problem, but for what D is intended for, this isn't a problem.

Is D not trying to also become a multi-paradigm language. Not many people would suggest that a functional language is a 'low-level' language. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 05 2008
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Derek Parnell" <derek psych.ward> wrote in message 
news:1nj8g11o1iuyn.14l4m6ks6524j$.dlg 40tude.net...

 IIRC the reason that overlapping copies are not allow is that the
 overhead of checking them is non trivial and the code to do the copy is
 to.


No, the reason they're not allowed is to allow for more parallel optimizations.
 And yet D fails at runtime if you attempt an overlap so it must already be
 doing such checking.

It does, but only in debug mode.
May 05 2008
prev sibling next sibling parent reply BCS <BCS pathlink.com> writes:
Derek Parnell wrote:
Similarly, there's no technical reason for not allowing 
lvalue slice assignments to grow or shrink the target,
or do overlapping copies. 



[...]
 
 
 Huh? Why would the length change? t[5..5] = "," should fail because the
 left and right sides of the assign are different lengths.
 

I may be miss reading the OP but I think he was suggesting that D allow assigning a slice of one size to a slice of another where this would change the length of the array that was assigned into. If I'm wrong, I'm wrong.
May 05 2008
parent "Me Here" <p9e883002 sneakemail.com> writes:
BCS wrote:

 Derek Parnell wrote:
 Similarly, there's no technical reason for not allowing lvalue slice
 assignments to grow or shrink the target, or do overlapping copies. 



[...]
 
 
 Huh? Why would the length change? t[5..5] = "," should fail because the
 left and right sides of the assign are different lengths.
 

I may be miss reading the OP but I think he was suggesting that D allow assigning a slice of one size to a slice of another where this would change the length of the array that was assigned into. If I'm wrong, I'm wrong.

You're not wrong. That is exactly the expectation I had. Based upon my use of other modern langauges. Sorry to quote the overview again but it was never more relevant. String manipulation is so common, and so clumsy in C and C++, that it needs direct support in the language. Modern languages handle string concatenation, copying, etc., and so does D. Strings are a direct consequence of improved array handling. --
May 05 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Derek Parnell wrote:
 And yet D fails at runtime if you attempt an overlap so it must already be
 doing such checking.

It does for non-release mode.
May 05 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Me Here wrote:
 What elese could 'a' ~ 'b' mean other than char[] tmp = "ab"?

Let's generalize the issue to be what does: T ~ T mean for any type T? Your argument is that the result should be T[]: T ~ T => T[] Ok. So imagine now that T is S[]: S[] ~ S[] => S[][] and we've done away with array concatenation. We could make a special case just for char values (and presumably all basic types), but then we'll find ourselves unable to write generic code. T ~ T[] => T[] T[] ~ T => T[] has no such ambiguity, and so is supported.
May 05 2008
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Walter Bright wrote:
     T ~ T => T[]

I forgot to add that there already is a nice syntax to do that: [T, T] => T[]
May 05 2008
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 05 May 2008 14:16:02 -0700, Walter Bright wrote:

 Me Here wrote:
 What elese could 'a' ~ 'b' mean other than char[] tmp = "ab"?

Let's generalize the issue to be what does: T ~ T mean for any type T? Your argument is that the result should be T[]: T ~ T => T[]

Not quite. Only if T is not an array would this be the expectation.
 Ok. So imagine now that T is S[]:
 
          S[] ~ S[] => S[][]
 
 and we've done away with array concatenation. We could make a special 
 case just for char values (and presumably all basic types), but then 
 we'll find ourselves unable to write generic code.
 
 	T ~ T[] => T[]
 	T[] ~ T => T[]
 
 has no such ambiguity, and so is supported.

And yet people still think in terms of non-array elements being able to be be concatenated to form arrays? Is that actually a weird thing? -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 05 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Derek Parnell wrote:
 On Mon, 05 May 2008 14:16:02 -0700, Walter Bright wrote:
 	T ~ T => T[]


That means that it's an excessive burden on generic code to have to add an extra test to ensure that T is an array type else lest unexpectedly different code gets generated. What do we do when T's a struct? Look inside the struct to see if it overloads opIndex? I propose that that's an excessive complication with little benefit, especially considering there's already unambiguous syntax to create an array out of values: [T, T] => T[] So, we have the unambiguous syntax to create an array out of values, and another unambiguous syntax to concatenate arrays: T ~ T => T and we have an ambiguous syntax to append or prepend values to an array: T ~ T[] => T[] T[] ~ T => T[] I think there is no tern unstoned here.
May 05 2008
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
 Derek Parnell wrote:
 On Mon, 05 May 2008 14:16:02 -0700, Walter Bright wrote:
 T ~ T => T[]


That means that it's an excessive burden on generic code to have to add an extra test to ensure that T is an array type else lest unexpectedly different code gets generated.

Not that I think this needs to be implemented, but your reasoning has gaping holes in it. Currently, if you write a generic function: T catTwoThings(T)(T t1, T t2) { return t1 ~ t2; } Now, if I do: catTwoThings!(char)('c', 'd'); The function fails. If we added the ability to cat chars together like: 'a' ~ 'b' => "ab" Then what happens to our poor generic function? It still doesn't compile, because the return type isn't correct. How is this any different than what we have today? You still can't pass in chars to generic code that expect to use arrays. How does that put an excessive burden on generic code?
 What do we do when T's a struct? Look inside the struct to see if it 
 overloads opIndex? I propose that that's an excessive complication with 
 little benefit, especially considering there's already unambiguous syntax 
 to create an array out of values:

What are you talking about? The same thing exists with structs, the compiler wouldn't do any special inference, it just cares if there is a concatenation operator defined for the type. Why does opIndex have anything to do with it? In a struct you can have: struct MyChar { char c; MyChar[] opCat(MyChar x) { return [*this, x];} } Does this break all generic code?
 [T, T] => T[]

 So, we have the unambiguous syntax to create an array out of values, and 
 another unambiguous syntax to concatenate arrays:

 T ~ T => T

This is the only sound reasoning that you have, but it's not that adding the concat operator for basic types would break things, it's that adding it would be a redundant method of doing [T, T], which makes sense to me.
 and we have an ambiguous syntax to append or prepend values to an array:

 T ~ T[] => T[]
 T[] ~ T => T[]

 I think there is no tern unstoned here.

I think you meant unambiguous :) -Steve
May 06 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 This is the only sound reasoning that you have, but it's not that adding the 
 concat operator for basic types would break things, it's that adding it 
 would be a redundant method of doing [T, T], which makes sense to me.

It breaks things because concatenating two arrays is a very, very different thing than forming a new array with two values in it. The ambiguity comes when the value is an array type: typeof(t1~t2) makePair(T t1, T t2) { return t1 ~ t2; } int[] a; char c; makePair(c,c); // ok, I get an array with two elements, what I want makePair(a,a); // I don't get a pair of arrays at all, big surprise Now, let's consider the struct case. I overload opCat for my containter struct. How do I distinguish wanting a *pair* of those structs from wanting to concatenate the *contents* of the container? Right now, it's very simple. To make a pair: return [t1, t2]; To concatenate the contents: return t1 ~ t2; There is no ambiguity of intent, and if our struct doesn't support concatenation of its contents, you get a nice compiler error. In other words, opCat for a struct means "concatenate the container contents", not concatenate the struct value.
May 06 2008
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
 Steven Schveighoffer wrote:
 This is the only sound reasoning that you have, but it's not that adding 
 the concat operator for basic types would break things, it's that adding 
 it would be a redundant method of doing [T, T], which makes sense to me.

It breaks things because concatenating two arrays is a very, very different thing than forming a new array with two values in it. The ambiguity comes when the value is an array type: typeof(t1~t2) makePair(T t1, T t2) { return t1 ~ t2; } int[] a; char c; makePair(c,c); // ok, I get an array with two elements, what I want makePair(a,a); // I don't get a pair of arrays at all, big surprise

If you didn't want to be surprised, then don't make the return type based on what the concatenation operator returns. It's much easier to write: T makePair(T t1, T t2) or T[] makePair(T t1, T t2) depending on what your intentions are. I still don't see the issue. Why can't the compiler do this: T ~ T => T ~ T[0] ~ T Same thing, no? It seems that it is a natural reduction, one that has no ambiguity or causes issues with generic code.
 In other words, opCat for a struct means "concatenate the container 
 contents", not concatenate the struct value.

You are concatenating the struct contents, into a new array. I don't see the ambiguity or the confusion it would cause. In any case, I'm done debating this, because I don't think it matters anyways :) The current language is sufficient to make arrays out of elements using the [T, T] syntax, so on that point alone, it is sufficient to reject this enhancement. I just think your other points are invalid. -Steve
May 06 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 You are concatenating the struct contents, into a new array.  I don't see 
 the ambiguity or the confusion it would cause.

If S is a container type, there is a huge difference between creating an array of two of those containers, and creating a new container that concatenates the contents of those two containers. There is no way opCat can do both jobs.
May 06 2008
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 because the bottom line is, a container needs to know about its
 elements, but elements do not need to know about their container.
 Allowing ~ to create arrays from primitive types would give built-in
 arrays an unfair advantage over custom arrays, and that alone should
 be enough reason to disallow it.

I missed that one. You're right that it's a sound rebuttal.
May 06 2008
prev sibling next sibling parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Janice Caron wrote:

 But.... Suppose I replace the built in array type with my own custom
 container, Array. Then I can override opCat and opCat_r to give me
 
     MyArray ~ MyArray = MyArray
     MyArray ~ char = MyArray
     char ~ array = MyArray
 
 However, there is no way I can persuade my custom container to give me
 the effect:
 
     char ~ char = MyArray
 
 because the bottom line is, a container needs to know about its
 elements, but elements do not need to know about their container.

It doesn't need to. Think about how this would come about: char a = 'a'; char b = 'b'; MyArray ma = a ~ b; The concatenation happens on the right hand side and forms an intermediate result. If the built-in base types knew how to do that, then so long as you've implemented opAssign taking a char[], then it doesn't need to /do/ anything. It would just work.
 Allowing ~ to create arrays from primitive types would give built-in
 arrays an unfair advantage over custom arrays, and that alone should
 be enough reason to disallow it.

The 'problem' of "unfairness" doesn't arise--as a result of this anyway. Though, the benefits of built-in types having an advantage is (or was), part ofD's mission statement: C++ implements things like resizable arrays and string concatenation as part of the standard library, not as part of the core language. Not being part of the core language has several suboptimal consequences. For my part, I said back there somewhere that my immediate problem is solved. Discussioin beyond that point is about the (perceived) fallacies being offered by way of explanation for the behaviour. [ 'a', 'b', 'c', 'd' ] is neater and more elegant than 'a' ~ 'b' ~ 'c' ~ 'd'; so I'm happy with that. The clumsyness and cost of having to do: s[ i .. i+10 ] = "" ~ toupper( s[ i .. i+10 ] ); is more of a problem. Cheers, b. --
May 06 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Me Here" wrote
 Janice Caron wrote:

 But.... Suppose I replace the built in array type with my own custom
 container, Array. Then I can override opCat and opCat_r to give me

     MyArray ~ MyArray = MyArray
     MyArray ~ char = MyArray
     char ~ array = MyArray

 However, there is no way I can persuade my custom container to give me
 the effect:

     char ~ char = MyArray

 because the bottom line is, a container needs to know about its
 elements, but elements do not need to know about their container.

It doesn't need to. Think about how this would come about: char a = 'a'; char b = 'b'; MyArray ma = a ~ b; The concatenation happens on the right hand side and forms an intermediate result. If the built-in base types knew how to do that, then so long as you've implemented opAssign taking a char[], then it doesn't need to /do/ anything. It would just work.

What about calling a function with the given concatenation? f(MyArray ma); f(a ~ b); // would this work? You would probably get there with opImplicitCast, but it seems rather inefficient to build a temporary array just to build a MyArray structure.
 [ 'a', 'b', 'c', 'd' ] is neater and more elegant than 'a' ~ 'b' ~ 'c' ~ 
 'd';
 so I'm happy with that.

 The clumsyness and cost of having to do:

        s[ i .. i+10 ] = "" ~ toupper( s[ i .. i+10 ] );

 is more of a problem.

First, as has been pointed out in other threads, you can't toupper a char[] array in place because some unicode uppercase characters take up more space than their lowercase versions. But even if that was not true, this is not a deficiency in the language, more a deficiency in the library. Assuming ASCII only characters, a function like: toupperInPlace(s[i..i+10]); Should do exactly what you want. If it existed :) -Steve
May 06 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Steven Schveighoffer wrote:

 "Me Here" wrote
 
 What about calling a function with the given concatenation?
 
 f(MyArray ma);
 
 f(a ~ b); // would this work?

Hm. I'm not sure. Would this work now: f( [ a, b ] ); ?
 
 You would probably get there with opImplicitCast, but it seems rather
 inefficient to build a temporary array just to build a MyArray structure.

Is it so different from this? void f( double d ) { ...} f( 1 + 2 );
 
 toupperInPlace(s[i..i+10]);
 
 Should do exactly what you want.  If it existed :)
 

And, of course, it does: void toUpper( char[] s ) { int l = s.length; for( int i = 0; i < l; s[ i++ ] &= ~0x20 ) {}; } And the rest of my pragmatic.string library is coming along also :)
 -Steve

Cheers, b. --
May 06 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Janice Caron wrote:

 On 06/05/2008, Me Here <p9e883002 sneakemail.com> wrote:
 Hm. I'm not sure. Would this work now: f( [ a, b ] ); ?

That's a red herring: Literal syntax has never been available to custom types. But if you wanted, you could always overload static opIndex(), and then you'd be able instead to do f( MyArray[ a, b ] );

So then, <i>if</i> a ~ b worked, then f( MyArray( a ~ b ) ); would work? (Just a question:) --
May 06 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Janice Caron wrote:

 2008/5/7 Me Here <p9e883002 sneakemail.com>:
  So then, <i>if</i> a ~ b worked

Sorry to be pedantic, but a ~ b does work. It does exactly what it's defined to do. What you mean is, if a ~ b exhibited the bizarre and unexpected behavior suggested in this thread.

Sorry to be pedantic in response, but in what way does it work? import std.stdio; void main() { char a = 'a', b = 'b'; writefln( a ~ b ); } c:\dmd\test>dmd junk3.d junk3.d(5): Error: Can only concatenate arrays, not (int ~ int) By implication from the subject of the entire thread, a and b are chars. b. --
May 07 2008
next sibling parent BCS <ao pathlink.com> writes:
Reply to Me,

 Janice Caron wrote:
 
 2008/5/7 Me Here <p9e883002 sneakemail.com>:
 
 So then, <i>if</i> a ~ b worked
 

defined to do. What you mean is, if a ~ b exhibited the bizarre and unexpected behavior suggested in this thread.


If the type of a and or b is an array... Or if the type of a defines the opCat method for the type of b then this method is called.
May 07 2008
prev sibling next sibling parent Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 8 May 2008 05:11:14 +0100, Janice Caron wrote:

 On 07/05/2008, Me Here <p9e883002 sneakemail.com> wrote:
 Sorry to be pedantic in response, but in what way does it work?

         import std.stdio;

         void main() {
             char a = 'a', b = 'b';
             writefln( a ~ b );
         }
         c:\dmd\test>dmd junk3.d
         junk3.d(5): Error: Can only concatenate arrays, not (int ~ int)

By giving a compile error, of course. That's how it's /supposed/ to work. It's telling you to fix your code,

In order to be helpful to coders, maybe the text of the message could be a bit more accurate ... something like ... junk3.d(5): Error: Can only concatenate arrays, not (char ~ char) Yes, I know about integer promotion rules. The internal machinations of the compiler need not be exposed to the source code writer, however. The coder used 'char' so the message should use 'char'.
  e.g. to
 
         void main() {
             char[] a = ['a'], b = ['b'];
             writefln( a ~ b );
         }

I don't have D availble here so does this below work? void main() { char a = 'a', b = 'b'; writefln( [a] ~ [b] ); } If not, it might be a neat idea. -- Derek (skype: derek.j.parnell) Melbourne, Australia 8/05/2008 4:04:09 PM
May 07 2008
prev sibling parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Janice Caron wrote:

 
 By giving a compile error, of course. That's how it's supposed to
 work. It's telling you to fix your code, e.g. to
 
         void main() {
             char[] a = ['a'], b = ['b'];
             writefln( a ~ b );
         }

That's like saying a car is "working", so long as it displays a red light on the dashboard to tell you that it isn't. If real world situations were always defined in terms of compile time constants life, would be much easier. Indeed, we'd never need to run the program because the compiler would solve it a compile time, and could just print out the 'answer', instead of all that nasty messing with relocatable object files. There are four discussions in this thread: 1. How to solve my original problem - Closed. 2. How to solve my original problem efficiently - Open. 3. Can type systems handle the 'natural' extension of T[] ~ T[] -> T[]; T[] ~ T -> T[]; T ~ T[] -> T[]; T ~ T -> T[]; Closed. (Yes). 4. Can D's type system handle this - Open. I think it could, and if it can't it should, but I don't know enough of the internals to be able to say for sure. 5. Should D allow it. Closed. (The man from D'elmonte, he say: No) b. --
May 08 2008
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Me,

 3. Can type systems handle the 'natural' extension of
 T[] ~ T[] -> T[];
 T[] ~ T   -> T[];
 T   ~ T[] -> T[];
 T   ~ T   -> T[];
 Closed. (Yes).

 4. Can D's type system handle this - Open.

I think that one is closed: yes it can, but as you point out, it wont. Because it causes inconstancies.
May 08 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
BCS wrote:

 Reply to Me,
 
 3. Can type systems handle the 'natural' extension of
T[] ~ T[] -> T[];
T[] ~ T   -> T[];
T   ~ T[] -> T[];
T   ~ T   -> T[];
 Closed. (Yes).
 
 4. Can D's type system handle this - Open.

I think that one is closed: yes it can, but as you point out, it wont. Because it causes inconstancies.

Surely, if it causes inconsistancies, the D's type system *isn't* handling it? (And I promise not to call you Shirly again :) b. --
May 08 2008
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Me,

 BCS wrote:
 
 Reply to Me,
 
 3. Can type systems handle the 'natural' extension of
 T[] ~ T[] -> T[];
 T[] ~ T   -> T[];
 T   ~ T[] -> T[];
 T   ~ T   -> T[];
 Closed. (Yes).
 4. Can D's type system handle this - Open.
 

wont. Because it causes inconstancies.

handling it?

The inconsistency would be from the users perspective and comes from code like this: T[] Foo(T) (T a, T b) {return a ~ b; } This would work if and only if T is not an array type. Foo!(char)('c','b'); //works Foo!(char[])("c","b"); // fails The compiler is constant in how it does things but does not constantly produce what you would expect.
May 08 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
BCS wrote:

 Reply to Me,
 
 BCS wrote:
 
 Reply to Me,
 
 3. Can type systems handle the 'natural' extension of
T[] ~ T[] -> T[];
T[] ~ T   -> T[];
T   ~ T[] -> T[];
T   ~ T   -> T[];
 Closed. (Yes).
 4. Can D's type system handle this - Open.
 

wont. Because it causes inconstancies.

handling it?

The inconsistency would be from the users perspective and comes from code like this: T[] Foo(T) (T a, T b) {return a ~ b; } This would work if and only if T is not an array type. Foo!(char)('c','b'); //works Foo!(char[])("c","b"); // fails The compiler is constant in how it does things but does not constantly produce what you would expect.

That depends upon the order (precedence) the transformation rules are applied. With the ordering shown above, your second example matched the first rule shown, and so is processed before it ever gets to the T ~ T -> T[]. The first example fails to match on the first three rules and is processed according to the 4th and the result is consistant results. b. --
May 08 2008
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Me,


 That depends upon the order (precedence) the transformation rules are
 applied.
 With the ordering shown above, your second example matched the first
 rule
 shown,
 and so is processed before it ever gets to the T ~ T -> T[].
 The first example fails to match on the first three rules and is
 processed
 according to the 4th
 and the result is consistant results.
 b.
 

You have just describe exactly why that code (from the programers's standpoint) is somewhat inconstant "T ~ T" can be of type T or T[] depending on what exactly T is. from the programers standpoint this is inconstant. Template code becomes hard to working with if the type of an expression starts having this type of dependency.
May 08 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
BCS wrote:

 Reply to Me,
 
 
 That depends upon the order (precedence) the transformation rules are
 applied.
 With the ordering shown above, your second example matched the first
 rule
 shown,
and so is processed before it ever gets to the T ~ T -> T[].
 The first example fails to match on the first three rules and is
 processed
 according to the 4th
 and the result is consistant results.
 b.
 

You have just describe exactly why that code (from the programers's standpoint) is somewhat inconstant "T ~ T" can be of type T or T[] depending on what exactly T is. from the programers standpoint this is inconstant. Template code becomes hard to working with if the type of an expression starts having this type of dependency.

Sorry, but I just don't buy that. Programmers are well used to the concept that aggregates are composed of elements. Whether arrays of ints and ints... or list sof a head and a tail. Indeed, Rules 2 & 3 use that very notion. 2) T ~ T[]: char[] prepended = 'a' ~ "some string"; char[] prepended = someChar ~ someCharArray; 3) T[] ~ T creal[] appended = 2+3i ~ [ 1+2i, -5+4i ]; // I hope those compex constants make sense? creal[] appended ~= 2+1i; D already allows these and no one is confused by it. Even kids wouldn't be confused. They pick up two short stacks of Lego bricks and press them together and the get a longer stack of Lego bricks. They pick up another single brick and press it on one one end and the stack gets bigger still. Another single pressed on the other end and same again. They pick up two single Lego bricks and press them together and they have a small stack of Lego bricks. One person waiting at a checkout is just one person. Another joins, you've got a queue. If the till next door closes and its queue joins the back of that two person queue and you get a longer queue. Not a queue of queues. Two playing cards on top of each other and you have the start of a pack. Put to packs together and you have a bigger pack. No one is surprised by any of these. There is nothing inconsistant. b. --
May 08 2008
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Me,

 Sorry, but I just don't buy that. Programmers are well used to the
 concept that aggregates are composed of elements.

[...]
 D already allows these and no one is confused by it.

[...]
 No one is surprised by any of these. There is nothing inconsistant.
 

It's not a matter of surprise or confusion. It's a mater of being able to tell what the type of an expression will be without knowing what the type of the parts are. This is extremely important with template code. e.g, will this compile under your rules? void Fn(T)() { T a, b; auto c = a ~ b; T d = c; } hint: you can't tell and the error message will not be on the line where the error is.
May 08 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
BCS wrote:

 void Fn(T)()
 {
  T a, b;
  auto c = a ~ b;
  T d = c;
 }

Okay. What do you think happens when you try to compile this? import std.stdio; T Fn(T)( T a, T b ) { auto c = a ~ b; T d = c; return d; } int main( char[][] args ) { char[][] a = [ [ 'a', 'b' ], [ 'c', 'd' ] ]; char[][] b = [ [ 'p', 'q' ], [ 'r', 's' ] ]; writefln( Fn!( char[][] )( a, b ) ); return 1; } --
May 09 2008
parent BCS <BCS pathlink.com> writes:
Me Here wrote:
 BCS wrote:
 
 
void Fn(T)()
{
 T a, b;
 auto c = a ~ b;
 T d = c;
}

Okay. What do you think happens when you try to compile this? import std.stdio; T Fn(T)( T a, T b ) { auto c = a ~ b; T d = c; return d; } int main( char[][] args ) { char[][] a = [ [ 'a', 'b' ], [ 'c', 'd' ] ]; char[][] b = [ [ 'p', 'q' ], [ 'r', 's' ] ]; writefln( Fn!( char[][] )( a, b ) ); return 1; }

it works: char[][] ~ char[][] -> char[][] but (still using your rules) this fails: writefln( Fn!( char )( 'a', 'b' ) ); because: char ~ char -> char[] != char so to make the function work you need: typeof(T~T) Fn(T)( T a, T b ) { auto c = a ~ b; T d = c; return d; } or: T Fn(T)( T a, T b ) { static assert(is(T == typeof(a~b), "Fn can only take arrays not "~T.stringof); auto c = a ~ b; T d = c; return d; }
May 09 2008
prev sibling next sibling parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Janice Caron wrote:

 On 08/05/2008, Me Here <p9e883002 sneakemail.com> wrote:
  Even kids wouldn't be
  confused.

Are you sure about that? Try asking a kid who's young enough to be interesting in stacking lego bricks together: What is the difference between a single brick, and a stack of one brick?

That's an interesting question. I will try that out on my grand nephew next time I see him. He's 5, loves Lego and has reashed the point where he is trying to use them to build things that look like real things, not just patterns and whatnot. It might be a little difficult to explain the concept of a stack of 1 to him. I'm pretty sure that his 8 year old sister would have no problem grasping the concept so long as I used her gazilions of penguin or hippo toys instead of Lego. Pursuading programmers that there is little conceptual difference between a single char and a string of one char, and that they should be usable interchangably? Now that could be a real challenge :) b. --
May 09 2008
next sibling parent reply Fawzi Mohamed <fmohamed mac.com> writes:
On 2008-05-09 13:31:55 +0200, "Me Here" <p9e883002 sneakemail.com> said:
 [...]
 Pursuading programmers that there is little conceptual difference between a
 single char and a string of one char, and that they should be usable
 interchangably? Now that could be a real challenge :)

but if [a]==a then what about [[a]] ? In any case you loose the isomorphism of arrays of arrays with the natural numbers... and you would loose the Godel Incompletness theorem on them... you cannot possibly want that... you even speak about the Curry-Howard isomorphism.... On a more serious note there are quite some symmetries that you would loose... you can do it, yes, but I would find then the thing less uniform and with hidden pitfalls. What you seem to want is an implicit cast of an element to an array with the single element. It can be done, and made work, but you would loose some checks, checks that can be useful. Please not that with this I don't want to start a flame war on static vs dynamic typing, as with other choices these have both advantages and drawbacks, but the current choice is definitely consistent and make sense. Fawzi
May 09 2008
parent reply Derek Parnell <derek psych.ward> writes:
On Fri, 9 May 2008 16:01:12 +0200, Fawzi Mohamed wrote:


 What you seem to want is an implicit cast of an element to an array 
 with the single element.

I agree that this will cause more problems that it will solve. However, if we rephrase your statement slightly ... I want to be able to cast a single element to an array. What sort of syntax (change) would that ability need and cost? eg. T a, b; T[] foo = cast(T[])a ~ cast(T[])b; But that is far to 'wordy' to be usable. I'd like something a lot more simple and intuitive. Maybe a new operator so that we don't upset opCat. I hereby propose an opJoin operator. It joins two elements to form an array. T a, b; T[] foo = a ~~ b; T[] bar = foo ~~ a; T[] qwe = b ~~ foo; Is there ANY way that this SORT OF thing could be made to work in D? -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 09 2008
next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Sat, 10 May 2008 05:29:32 +0100, Janice Caron wrote:

 On 09/05/2008, Derek Parnell <derek psych.ward> wrote:
      T a, b;
      T[] foo = a ~~ b;
      T[] bar = foo ~~ a;
      T[] qwe = b ~~ foo;

  Is there ANY way that this SORT OF thing could be made to work in D?

For crying out loud, yes!

Thank you sir, for your kind and thoughtful consideration. I am truely humbled. My only defense, if one can even call it that, was that I thought I was told by somebody more knwledgable than myself, that such a syntax did not work for non-literals. My memory or understanding is obviously faulty. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 10 2008
parent Derek Parnell <derek psych.ward> writes:
On Sat, 10 May 2008 10:56:44 +0100, Janice Caron wrote:

 On 10/05/2008, Derek Parnell <derek psych.ward> wrote:
 Thank you sir,

Don't mention it, madam. But I'm a girl.

It doesn't show ;-) -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 10 2008
prev sibling parent reply Fawzi Mohamed <fmohamed mac.com> writes:
On 2008-05-10 00:56:33 +0200, Derek Parnell <derek psych.ward> said:

 On Fri, 9 May 2008 16:01:12 +0200, Fawzi Mohamed wrote:
 
 
 What you seem to want is an implicit cast of an element to an array
 with the single element.

I agree that this will cause more problems that it will solve. However, if we rephrase your statement slightly ... I want to be able to cast a single element to an array. What sort of syntax (change) would that ability need and cost? eg. T a, b; T[] foo = cast(T[])a ~ cast(T[])b; But that is far to 'wordy' to be usable. I'd like something a lot more simple and intuitive. Maybe a new operator so that we don't upset opCat. I hereby propose an opJoin operator. It joins two elements to form an array. T a, b; T[] foo = a ~~ b; T[] bar = foo ~~ a; T[] qwe = b ~~ foo; Is there ANY way that this SORT OF thing could be made to work in D?

using two test taken from tango.core.Variant template isArray(T) { static if( is( T U : U[] ) ) const isArray = true; else const isArray = false; } template isStaticArray(T) { static if( is( typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T ) ) const isStaticArray = true; else const isStaticArray = false; } template alwaysArrayT(T){ static if (isStaticArray!(T)) alias typeof(T.dup) alwaysArrayT; else static if (isArray!(T)) alias T alwaysArrayT; else alias T[] alwaysArrayT; } alwaysArrayT!(T) alwaysArray(T)(T x){ static if (isStaticArray!(T)) return x.dup; static if (isArray!(T)) return x; else return [x]; } alwaysArray converts any type to a dynamic array, now what you want is alwaysArray(a)~alwaysArray(b) this makes sense in generic code, normally you know wether a in an element or an array and you handle accordingly. If you want with this you can also implement directly your ~~ and it would be more efficient (no temporary array for elements). In D 2.0 it should be nicer to write because the static arrays are more uniform, and you can also use the traits. Note that as noted by Janice alwaysArray has a fixed choice of which array to use when given a scalar, so it cannot coexist with an overloaded version that uses another array. Fawzi
May 10 2008
parent Fawzi Mohamed <fmohamed mac.com> writes:
On 2008-05-10 14:00:16 +0200, Fawzi Mohamed <fmohamed mac.com> said:

 On 2008-05-10 00:56:33 +0200, Derek Parnell <derek psych.ward> said:
 
 On Fri, 9 May 2008 16:01:12 +0200, Fawzi Mohamed wrote:
 
 
 What you seem to want is an implicit cast of an element to an array
 with the single element.

I agree that this will cause more problems that it will solve. However, if we rephrase your statement slightly ... I want to be able to cast a single element to an array. What sort of syntax (change) would that ability need and cost? eg. T a, b; T[] foo = cast(T[])a ~ cast(T[])b; But that is far to 'wordy' to be usable. I'd like something a lot more simple and intuitive. Maybe a new operator so that we don't upset opCat. I hereby propose an opJoin operator. It joins two elements to form an array. T a, b; T[] foo = a ~~ b; T[] bar = foo ~~ a; T[] qwe = b ~~ foo; Is there ANY way that this SORT OF thing could be made to work in D?

using two test taken from tango.core.Variant template isArray(T) { static if( is( T U : U[] ) ) const isArray = true; else const isArray = false; } template isStaticArray(T) { static if( is( typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T ) ) const isStaticArray = true; else const isStaticArray = false; } template alwaysArrayT(T){ static if (isStaticArray!(T)) alias typeof(T.dup) alwaysArrayT; else static if (isArray!(T)) alias T alwaysArrayT; else alias T[] alwaysArrayT; } alwaysArrayT!(T) alwaysArray(T)(T x){ static if (isStaticArray!(T)) return x.dup; static if (isArray!(T)) return x; else return [x]; } alwaysArray converts any type to a dynamic array, now what you want is alwaysArray(a)~alwaysArray(b) this makes sense in generic code, normally you know wether a in an element or an array and you handle accordingly. If you want with this you can also implement directly your ~~ and it would be more efficient (no temporary array for elements). In D 2.0 it should be nicer to write because the static arrays are more uniform, and you can also use the traits. Note that as noted by Janice alwaysArray has a fixed choice of which array to use when given a scalar, so it cannot coexist with an overloaded version that uses another array. Fawzi

mmmh, I noticed that Janice beat me to it, I should get a better newbrowser, I hadn't seen it
May 10 2008
prev sibling next sibling parent BCS <BCS pathlink.com> writes:
Me Here wrote:
 Pursuading programmers that there is little conceptual difference between a
 single char and a string of one char, and that they should be usable
 interchangably? Now that could be a real challenge :)
 
 b.

If you want to read an interesting thread go look for any of the threads here about the difference between null and "", e.i. a null array and an empty array. People around here have come up with many good reasons to maintain that distinction, and I expect, if asked, can come up with just as many good reasons to maintain the distinction between a single element array and a single element.
May 09 2008
prev sibling parent "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Fri, 09 May 2008 12:31:55 +0100, Me Here <p9e883002 sneakemail.com>  
wrote:
 Pursuading programmers that there is little conceptual difference  
 between a
 single char and a string of one char, and that they should be usable
 interchangably? Now that could be a real challenge :)

 b.

There are as other have already pointed out a number of very signficant conceptual differences. If you want to ignore them you should prefer a less strongly typed language. That said is there any reason we couldn't have an implicit (possibly user defined) cast to array when no other implicit casts apply? i.e. T[] opImplicitCast(T a) { return T[](a); } This still wouldn't permit 'a' ~ 'b' so long as there is a valid meaning for int~int but it would be useful in other places. Thinking about it, it could already be built-in I can't honestly remember. void myFunction(foo[] A); myFunction('a') --> myFunction(['a']);
May 09 2008
prev sibling parent "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Thu, 08 May 2008 23:53:13 +0100, Me Here <p9e883002 sneakemail.com>  
wrote:
 One person waiting at a checkout is just one person. Another joins,  
 you've got
 a queue. If the till next door closes and its queue joins the back of  
 that two
 person queue and you get a longer queue. Not a queue of queues.

Likewise an empty queue.
 Two playing cards on top of each other and you have the start of a pack.  
 Put to
 packs together and you have a bigger pack.

 No one is surprised by any of these. There is nothing inconsistant.

 b.

Likewise. A card is a card. A set of cards may be empty or contain one or more cards.
May 09 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 08/05/2008, Me Here <p9e883002 sneakemail.com> wrote:
  Even kids wouldn't be
  confused.

Are you sure about that? Try asking a kid who's young enough to be interesting in stacking lego bricks together: What is the difference between a single brick, and a stack of one brick?
May 08 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/05/2008, Derek Parnell <derek psych.ward> wrote:
 Thank you sir,

Don't mention it, madam. But I'm a girl.
May 10 2008
prev sibling next sibling parent "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Thu, 08 May 2008 19:38:40 +0100, Me Here <p9e883002 sneakemail.com>  
wrote:

 BCS wrote:

 Reply to Me,

 3. Can type systems handle the 'natural' extension of
T[] ~ T[] -> T[];
T[] ~ T   -> T[];
T   ~ T[] -> T[];
T   ~ T   -> T[];
 Closed. (Yes).

 4. Can D's type system handle this - Open.

I think that one is closed: yes it can, but as you point out, it wont. Because it causes inconstancies.

Surely, if it causes inconsistancies, the D's type system *isn't* handling it? (And I promise not to call you Shirly again :) b.

I Invoke Godel. For any sufficiently complex system there will always be inconsistancies. You can please some of the people all of the time...
May 09 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 09/05/2008, Derek Parnell <derek psych.ward> wrote:
      T a, b;
      T[] foo = a ~~ b;
      T[] bar = foo ~~ a;
      T[] qwe = b ~~ foo;

  Is there ANY way that this SORT OF thing could be made to work in D?

For crying out loud, yes! T a,b; T[] foo = [ a, b ]; T[] bar = foo ~ a; T[] qwe = b ~ foo; It's not hard. If you wanted, you could even templatise it: T[] join(T:U[],U)(T array, U element) { return array ~ element; } T[] join(T:U[],U)(U element, T array) { return element ~ array; } T[] join(T:U[],U)(T array1, T array2) { return array1 ~ array2; } T[] join(T)(T element1, T element2) { return [ element1, element2 ]; } T a,b; T[] foo = join(a, b); T[] bar = join(foo, a); T[] qwe = join(b, foo); However, that template won't work with custom collections - only with built in arrays. Overloading a function is a perfectly normal and expected thing to do in D. Redefining an operator, on the other hand, is a BIG DEAL, hence the resistance. As for introducing a new operator, well, what's the point?
May 09 2008
prev sibling parent "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Thu, 08 May 2008 10:39:15 +0100, Me Here <p9e883002 sneakemail.com>  =

wrote:

 Janice Caron wrote:

 By giving a compile error, of course. That's how it's supposed to
 work. It's telling you to fix your code, e.g. to

         void main() {
             char[] a =3D ['a'], b =3D ['b'];
             writefln( a ~ b );
         }

That's like saying a car is "working", so long as it displays a red =

 light on
 the dashboard to tell you that it isn't. If real world situations were=

 always
 defined in terms of compile time constants life, would be much easier.=

Perhaps its worth pointing out that part of the spec for a car to pass road worthiness tests is for there to be clear indications of certain errors on the dashboard. There must be an oil light. There must be a fue= l gauge. etc.
May 09 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 07/05/2008, Me Here <p9e883002 sneakemail.com> wrote:
 Sorry to be pedantic in response, but in what way does it work?

         import std.stdio;

         void main() {
             char a = 'a', b = 'b';
             writefln( a ~ b );
         }
         c:\dmd\test>dmd junk3.d
         junk3.d(5): Error: Can only concatenate arrays, not (int ~ int)

By giving a compile error, of course. That's how it's /supposed/ to work. It's telling you to fix your code, e.g. to void main() { char[] a = ['a'], b = ['b']; writefln( a ~ b ); }
May 07 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
2008/5/7 Me Here <p9e883002 sneakemail.com>:
  So then, <i>if</i> a ~ b worked

Sorry to be pedantic, but a ~ b does work. It does exactly what it's defined to do. What you mean is, if a ~ b exhibited the bizarre and unexpected behavior suggested in this thread.
, then
         f( MyArray( a ~ b ) );

  would work? (Just a question:)

Not by default, but it could be /made/ to work. Assuming MyArray was a struct, then the expression MyArray(n) would create a MyArray on the stack and assign its first and only element with n. If that turns out not to possible, it's an error. To make it work, you'd have to overload static opCall(char[]) for MyArray. Of course, you might want to do that anyway - but even so, there'd still be a wasteful temporary allocated on the heap.
May 07 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 06/05/2008, Me Here <p9e883002 sneakemail.com> wrote:
 Hm. I'm not sure. Would this work now: f( [ a, b ] ); ?

That's a red herring: Literal syntax has never been available to custom types. But if you wanted, you could always overload static opIndex(), and then you'd be able instead to do f( MyArray[ a, b ] );
May 06 2008
prev sibling parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Walter Bright wrote:

 Me Here wrote:
 What elese could 'a' ~ 'b' mean other than char[] tmp = "ab"?

Let's generalize the issue to be what does: T ~ T mean for any type T? Your argument is that the result should be T[]: T ~ T => T[] Ok. So imagine now that T is S[]: S[] ~ S[] => S[][] and we've done away with array concatenation. We could make a special case just for char values (and presumably all basic types), but then we'll find ourselves unable to write generic code. T ~ T[] => T[] T[] ~ T => T[] has no such ambiguity, and so is supported.

Sorry, but this is silly. When the compiler attempts to resolve T[] ~ T[] it succeeds because opCat is defined for T[]. Likewise for T[] ~ T. For T ~ T[] opCat_r is defined for T[], so it resolves. All I'm suggesting is that if opCat is defined for T, then T ~ T can resolve also. That doesn't imply the current opCat defined for T[] would suddenly change to T[] ~ T[] -> T[][]. Why would it? It's nonsensical, and it isn't going to change unless someone changes it. What you are suggesting is that if I define opMul for MyClass to do MyClass * MyClass -> MyClass[], then T * T would have to render T[] for *all* types. But it doesn't work that way. Int * Int isn't suddenly going to stop performing multiplication and start rendering an array of Ints. Nor is Real * Real. unless someone goes in an changes the definition of opMul for those other types. Overloading a arithmetic operator to perform non-arithmetic operations is generally frowned upon, but is still quite common with, for example matrix manipulations. And doing so doesn't suddenly change the * works for any other type or class. So why would defining opCat for the basic types, suddenly cause (or require) that opCat's defined for composites to behave differently? Had someone pointed out earlier that my immediate problem could be solved by using: table[ b1 << 14 | b2 << 12 | b3 << 10 | b4 << 8 | b5 << 6 | b6 << 4 | b7 << 2 | b8 ][] = [ abcd[ b1 ], abcd[ b2 ], abcd[ b3 ], abcd[ b4 ], abcd[ b5 ], abcd[ b6 ], abcd[ b7 ], abcd[ b8 ] ]; (**) We probably wouldn't be having this conversation. But that doesn't persuade me that catenation of basic types wouldn't a) answer peoples expectations; b) or break generics. That said, I'm not at all sure that string handling /should/ be dealt with using generic array type manipulations. Insertions, deletions and in-place mutations are very common operations on char[]s, but far less so on int[] real[], creal[] etc. And for most object aggregations for which insert/delete or slice operations would make sense, you'd probably use linked lists. The overhead of (at least) a 32/64 bit pointer per char would be a nonsense, so maybe strings should be a special case and not template generated generalisation of array type. If feel about this the same way I feel about what think I should be able to do with lvalue slices, It something that I will have to accept because you're calling the shots, but your reasoning escapes me. For unequal sized or overlapping slice assignment, the detection code is a little messy, and the implementation for the non-trivial case, non-trivial. But that's exactly why it should be written once, got right by the expert(s), and just used by everyone else. Moving the code out of the core into a library may seem to satisfy that requirement, but it still means the Joe Mortal programmer is left with having to write their own code to detect whether they can use a slice assignment or must call std.string.replaceSlice()*. The doc examples on opSliceAssignment aren't marvelously clear as they only deal with the case of assigning a single value to a single element slice. For a muli-element slice assignment, you need source reference, pos1, length1 & destination ref, pos2, length2. Are the checks for the simple case really so onorous? if( length1 == length2 and ( src != dst or ( pos2 + length2 < pos1 ) or ( pos1 + length1 < pos2 ) ) { // do the simple case } else { What does that equate to, maybe 8 or 10 opcodes? And half of those would be register loads you'd have to execute to set up the REP MOVS instruction. The extra instructions would be a couple of ADDs, TESTs and Jxx before falling through to the REP MOVS. Half a dozen cycles penalty per conforming slice assignment? There's an old saying something about spoiling the barrel for a ha'peth of tar. Again I apologise. I didn't set out to critique this stuff (again), just to solve my immedaite problem--which I now have. One good thing (for me) that's arisen from my attempting to understand your and BCS' responses are that it has forced me to look much deeper into the overloading facilties. And (at least in theory) I realise that with these, plus a struct definition and a little in-line assembler I should be able to define my own 'string' type that works the way I want it to... Cheers, b. (*BTW. Why does char[] replaceSlice(char[] string, char[] slice, char[] replacement) require both the target string and target slice of that string?) (**Shame about the need to repeat the abcd[ ] bit so much. Perl#s array slices accept multiple individual indexes (as well as ranges). So the equivalent of the above would be: table[ ... ] = abcd[ b1, b2, b3, b4, b5, b5, b7, n8 ]; which is a lot nicer to read. ) --
May 05 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Me Here wrote:
 So why would defining opCat for the basic types, suddenly cause (or require)
 that opCat's defined for composites to behave differently?

First of all, what if you wanted T ~ T => T[] for *all* types in generic code? You've got an obvious problem, because it behaves very inconsistently for different types. Secondly, what about structs? Should structs behave like basic types, or like arrays here? (I discussed this conundrum further in another post in this thread.)
 Had someone pointed out earlier that my immediate problem could be solved by
 using:
 
 	table[ 
 	    b1 << 14 | b2 << 12 | b3 << 10 | b4 <<  8 | 
 	    b5 <<  6 | b6 <<  4 | b7 <<  2 | b8 
 	][] = [ 
 	    abcd[ b1 ], abcd[ b2 ], abcd[ b3 ], abcd[ b4 ], 
 	    abcd[ b5 ], abcd[ b6 ], abcd[ b7 ], abcd[ b8 ]
 	]; (**)
 
 We probably wouldn't be having this conversation. But that doesn't persuade me
 that catenation of basic types wouldn't a) answer peoples expectations; b) or
 break generics. That said, I'm not at all sure that string handling /should/ be
 dealt with using generic array type manipulations.

I don't know of any reason why it shouldn't be (since arrays are a fundamental data type), or why having 'c'~'d' is so advantageous we should preclude generic code from manipulating arrays.
 Insertions, deletions and
 in-place mutations are very common operations on char[]s, but far less so on
 int[] real[], creal[] etc.

That doesn't justify treating them inconsistently. Remember, this started out with the complaint about an inconsistency. I don't agree that it's an inconsistency, but assuming that it is, at least one gets a reasonable error message for it, rather than silently doing something surprising.
 What does that equate to, maybe 8 or 10 opcodes?

That's a lot when you're faced with a "D sucks because array ops are slow" benchmark. It can double the time in the loop.
 (*BTW. Why does char[] replaceSlice(char[] string, char[] slice, char[]
 replacement) require both the target string and target slice of that string?)

Because all three parameters are needed to give sufficient information.
May 05 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Walter Bright wrote:

 First of all, what if you wanted
 	T ~ T => T[]
 for all types in generic code? You've got an obvious problem, because it
 behaves very inconsistently for different types. 

This is exactly why Haskell and other Category Theory based type-inferencing languages dispatch on type signatures that combine both the parameters *and* the return type. See http://en.wikibooks.org/wiki/Haskell/Category_theory A category is, in essence, a simple collection. It has three components: - A collection of objects. ... - A collection of morphisms, each of which ties two objects (a source object and a target object) together. ... - A notion of composition of these morphisms. ... Trying to do type inferenceing without taking return type into account during method resolution is doomed to fail. There's also the concept os substitutability. T and T[...1...] (meaning any one element of t[]), should be substitutable. In D, they aren't
Secondly, what about
 structs? Should structs behave like basic types, or like arrays here? (I
 discussed this conundrum further in another post in this thread.)

If the struct has a opCat method with match type signature, dispatch to it. If not, raise an error. Can I imagine a use for T ~ T in conjunction with a struct? Yes. A single linked list might well use: head ~ node; or list ~= newNode
 
 What does that equate to, maybe 8 or 10 opcodes?

That's a lot when you're faced with a "D sucks because array ops are slow" benchmark. It can double the time in the loop.

Hmm. How do you balance that view with the impact of immutable strings in Dv2?
 
 (*BTW. Why does char[] replaceSlice(char[] string, char[] slice, char[]
 replacement) require both the target string and target slice of that
 string?)

Because all three parameters are needed to give sufficient information.

I kinda guessed it was done for a reason, but was looking for a clue as to what that reason was. I (probably wrongly, given how bad my assumptions about what D is doing under thc covers so far have panned out) that a slice carried enough information to identify the array it is a slice of. Eg. (something like) struct slice { T[]* parent; type_t pos; type_t length } I guess I have to did around in teh source, assuming that is a part of the open sources. Cheers, b. --
May 06 2008
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Me Here wrote:
 Walter Bright wrote:
 
 (*BTW. Why does char[] replaceSlice(char[] string, char[] slice, char[]
 replacement) require both the target string and target slice of that
 string?)


I kinda guessed it was done for a reason, but was looking for a clue as to what that reason was. I (probably wrongly, given how bad my assumptions about what D is doing under thc covers so far have panned out) that a slice carried enough information to identify the array it is a slice of. Eg. (something like) struct slice { T[]* parent; type_t pos; type_t length }

A slice is stored in the exact same way as a regular dynamic array: a length and a pointer. The GC could figure out what block of memory the pointer points into, but that's probably rather inefficient and doesn't work for string literals (since they aren't heap-allocated so the GC doesn't know about them). And even ignoring all that: the 'string' argument to replaceSlice may itself be a slice of a larger string, in which case there's no way to determine what it was given only the 'slice' argument even if it *was* heap-allocated.
May 06 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Me Here wrote:
 Secondly, what about
 structs? Should structs behave like basic types, or like arrays here? (I
 discussed this conundrum further in another post in this thread.)

If the struct has a opCat method with match type signature, dispatch to it. If not, raise an error.

One of the principles of D is that a struct can be used to 'wrap' any type, and be able to behave like that type. So for your proposal: struct S { char c; } S s; char c; c ~ c => char[] s ~ s => error!
 Hmm. How do you balance that view with the impact of
 immutable strings in Dv2?

I don't agree that immutable strings are slower, but even so, you don't have to use immutable strings in D. char[] can be used. There's no way to avoid the extra tests if overlapping copies are allowed.
 Eg. (something like) struct slice { T[]* parent; type_t pos; type_t length }

It's { length, ptr }.
May 06 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
 Me Here wrote:
 Secondly, what about
 structs? Should structs behave like basic types, or like arrays here? (I
 discussed this conundrum further in another post in this thread.)

If the struct has a opCat method with match type signature, dispatch to it. If not, raise an error.

One of the principles of D is that a struct can be used to 'wrap' any type, and be able to behave like that type. So for your proposal: struct S { char c; } S s; char c; c ~ c => char[] s ~ s => error!

struct S { char c; S[] opCat(S s) {return [*this, s];} } c ~ c => char[] s ~ s => S[] What is the problem with that? -Steve
May 06 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 What is the problem with that?

I went over that problem in another post in this thread.
May 06 2008
prev sibling parent reply Pontus Pihlgren <pontus update.uu.se> writes:
<snippety>

 (**Shame about the need to repeat the abcd[ ] bit so much. Perl#s array slices
 accept multiple individual indexes (as well as ranges). So the equivalent of
 the above would be:
 
 	 table[ ... ] =  abcd[ b1, b2, b3, b4, b5, b5, b7, n8 ];
 
 which is a lot nicer to read. )
 

Perls array slice syntax is quite awsome and powerful, but I'm not sure what implications they would have in D, probably only meaningful in Perl where arrays really are linked lists. Another concept from Perl that would have solved the original problem is list context versus scalar context. That is, when a list is expected things become a list. If it existed in D, then ~ would introduce a list context and abcd[b1] would be interpreted as a slice. Not sure I would like to see either feature in D. Regards, Pontus.
May 06 2008
parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Pontus Pihlgren wrote:

 probably only meaningful in Perl   where
 arrays really are linked lists.

Not quite. Perl's arrays are actually bog standard C style arrays (of pointers to SV*s). Plus a header and some logic: http://www.perl.org/tpc/1998/Perl_Language_and_Modules/Perl%20Illustrated/av.gif The guts of an array is a contiguos allocation of size * 4 bytes. Their power & flexibility comes completely from the syntax and core code that implements it. Their relative efficiency comes from the use of two pointers, and length field and two flag bits in teh header.
 
 Regards,
 Pontus.

Cheers, b. --
May 08 2008
parent Pontus Pihlgren <pontus update.uu.se> writes:
Me Here skrev:
 Pontus Pihlgren wrote:
 
 probably only meaningful in Perl   where
 arrays really are linked lists.

Not quite. Perl's arrays are actually bog standard C style arrays (of pointers to SV*s). Plus a header and some logic: http://www.perl.org/tpc/1998/Perl_Language_and_Modules/Perl%20Illustrated/av.gif The guts of an array is a contiguos allocation of size * 4 bytes. Their power & flexibility comes completely from the syntax and core code that implements it. Their relative efficiency comes from the use of two pointers, and length field and two flag bits in teh header.
 Regards,
 Pontus.

Cheers, b.

This was very interesting read: http://www.perl.org/tpc/1998/Perl_Language_and_Modules/Perl%20Illustrated/ I should probably have read it years ago. Still though, I don't that kind of complexity should go into D, no matter how sugary syntax it gives you. What do you think, would it be bad to make D slice syntax a bit more like Perl? That is, allowing you to mix indexes and slices, and having them both on the right- and lefthand side: a[4, 2, 5..7] = b[1,3..6]; /P
May 09 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
I've read all this arguments on this thread, and I think it would be
/possible/ to implement the suggestion - but highly undesirable.

It really is not difficult to write [ x ] instead of x, so the way I
see it, there is absolutely no problem to be solved.
May 06 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 06/05/2008, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 I just think your other points are invalid.

I think Walter is spot on. This is an OPERATOR, not a function. Operators are supposed to have well defined semantics. The plus sign is supposed to mean addition. The minus sign is supposed to mean subtraction. The tilde sign is supposed to mean concatenation of contents. It is appropriate for structs which are custom containers to overload opCat to emulate contanation of container contents, but overloading opCat to do anything else violates the principle of least surprise, and is every bit as bad as it would be to overload opAdd to create arrays. Like any other operator, the ~ operator shouldn't be treated like an ad hoc function. Sure - you can overload foo() to do whatever you want. But please don't treat opXxxx() in the same way. As far as generic programming is concerned, I think there is a reasonable expection that classes will not overload opCat(), except to emulate an array, and authors of template code should be entitled to make that assumption, just as they are equally entitled to assume that T + T will have have type T.
May 06 2008
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 06/05/2008, Walter Bright <newshound1 digitalmars.com> wrote:
  There is no way opCat can do both jobs.

I completely agree. And there is another reason that this is a bad idea: People observe that array ~ array = array array ~ char = array char ~ array = array (assuming array is an array of chars, of course), and then suppose that the fourth case should also yield array. char ~ char = array But.... Suppose I replace the built in array type with my own custom container, Array. Then I can override opCat and opCat_r to give me MyArray ~ MyArray = MyArray MyArray ~ char = MyArray char ~ array = MyArray However, there is no way I can persuade my custom container to give me the effect: char ~ char = MyArray because the bottom line is, a container needs to know about its elements, but elements do not need to know about their container. Allowing ~ to create arrays from primitive types would give built-in arrays an unfair advantage over custom arrays, and that alone should be enough reason to disallow it.
May 06 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Janice Caron" wrote
 because the bottom line is, a container needs to know about its
 elements, but elements do not need to know about their container.
 Allowing ~ to create arrays from primitive types would give built-in
 arrays an unfair advantage over custom arrays, and that alone should
 be enough reason to disallow it.

This is a much better reason than what Walter has been saying :) Thanks! -Steve
May 06 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Me Here wrote:
 I getting error message from the following code that I do not know how to
 interpret.

When this happens, the best way to find out what is wrong is to make a copy of your code in test.d, then ruthlessly whittle down your code until you get the minimum that produces the error. Then, usually, what's causing the error becomes obvious. In your particular case, the code is trying to concatenate characters, not arrays of characters. There is no language support for concatenating individual char values. As for the int conversions, that is following standard C integral promotion rules. Lots of people argue that those rules don't make much sense today, but the consequence of changing them is to make it very difficult to transliterate C code to D code without subtly breaking things.
 Why does D think I'm trying to concatenate ints, when teh only expressions
 involving catenation are
 slices of char[] abcd?

abcd[x] is not a slice, it is a char value. Per the C integral promotion rules, the char is then promoted to int. A slice would be abcd[x..x+1].
 Why is D casting my carefully specified ushorts to ints when doing
 bit-twiddling?

The C integral promotion rules.
 Finally, is it possible to populate a static lookup table at runtime? 

What you're looking for is array content assignment, which is done in D with: table[x][] = abcd[]; which will copy the contents of the array from abcd to table[x].
May 05 2008
next sibling parent reply "Me Here" <p9e883002 sneakemail.com> writes:
Walter Bright wrote:
 In your particular case, the code is trying to concatenate characters, not
 arrays of characters. There is no language support for concatenating
 individual char values.
 

I know you get a lot of internet wannabees suggesting stuff that doesn't make sense, and this will likely fall on deaf ears. But C doesn't have ~ concatenation, so there's no backwards compatibilty reason for not defining opCat for chars to do the only logical thing and produce a char[]. I said more in another post regarding lvalue slices which I just posted before seeing your reply. Likewise, I have no expectation of changing your decision on this either, but ... but it doesn't make sense to me. Cheers, b. --
May 05 2008
parent Michiel Helvensteijn <nomail please.com> writes:
Me Here wrote:

 But C doesn't have ~ concatenation, so there's
 no backwards compatibilty reason for not defining opCat for chars to do
 the only logical thing and produce a char[].

What if you tried to concatenate two types that DO support concatenation of their own? You're suggesting the concatenation operator could work like this: operator~: T x T -> T[] If T is already an array, however, you wouldn't want those semantics. Would you have it work only on primitive types? That would make it a very inconsistent behavior and I'd rather see the error than have D guess that I need an array. -- Michiel
May 05 2008
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 05 May 2008 12:07:55 -0700, Walter Bright wrote:

 
 In your particular case, the code is trying to concatenate characters, 
 not arrays of characters. There is no language support for concatenating 
 individual char values.

And this is the real issue. Walter, does this statement of yours also mean that there will *never* be such support in D? Concatenating elements to form an array of elements is a pretty natural expectation from people. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 05 2008
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Derek Parnell escribió:
 On Mon, 05 May 2008 12:07:55 -0700, Walter Bright wrote:
 
  
 In your particular case, the code is trying to concatenate characters, 
 not arrays of characters. There is no language support for concatenating 
 individual char values.

And this is the real issue. Walter, does this statement of yours also mean that there will *never* be such support in D? Concatenating elements to form an array of elements is a pretty natural expectation from people.

But this could only work for primitive types, because for classes, for example, there will be ambiguity between "concatenate these elements" and "invoke opCat on these elements".
May 05 2008
parent Ary Borenszweig <ary esperanto.org.ar> writes:
Ary Borenszweig escribió:
 Derek Parnell escribió:
 On Mon, 05 May 2008 12:07:55 -0700, Walter Bright wrote:

  
 In your particular case, the code is trying to concatenate 
 characters, not arrays of characters. There is no language support 
 for concatenating individual char values.

And this is the real issue. Walter, does this statement of yours also mean that there will *never* be such support in D? Concatenating elements to form an array of elements is a pretty natural expectation from people.

But this could only work for primitive types, because for classes, for example, there will be ambiguity between "concatenate these elements" and "invoke opCat on these elements".

Umm... This ambiguity already exists, but opCat/opCat_r always win... nevermind.
May 05 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Derek Parnell wrote:
 Concatenating elements to form an array of elements is a pretty natural
 expectation from people.

I agree, which is why D supports array literals: [T, T] => T[]
May 05 2008
parent "Joel C. Salomon" <joelcsalomon gmail.com> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Walter Bright wrote:
 Derek Parnell wrote:
 Concatenating elements to form an array of elements is a pretty natural
 expectation from people.

I agree, which is why D supports array literals: [T, T] => T[]

Trouble is, people learn that array ~ 'a' & 'a' ~ array work and want to generalize. Maybe it would be better if D required a cast-to-“array”, as in array ~ ['a'] to append. Remove the special syntax altogether. - --Joel -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFIIGFnzLx4GzBL9dYRAs0dAKCCO3nnTP2lu2ax0hqVu37IIMCcQwCggHkW ogmUrjEaMtCbTR/bqZ5JAJQ= =jf0D -----END PGP SIGNATURE-----
May 06 2008
prev sibling parent Don <nospam nospam.com.au> writes:
Walter Bright wrote:
 Me Here wrote:
 Why is D casting my carefully specified ushorts to ints when doing
 bit-twiddling?

The C integral promotion rules.

Something there really needs to change. ushort a = 0; a = a | a; currently gives an error message if compiling with -w. And therefore, bit-twiddling in libraries has to contain ugly workarounds.
May 06 2008