|
Archives
D Programming
D
D.gnu
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.ide
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
electronics
|
digitalmars.D - More D newb questions.
↑ ↓ ← → "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.
--
↑ ↓ ← → 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?
↑ ↓ ← → 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]"
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → 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
↑ ↓ ← → "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.
↑ ↓ ← → 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.
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → 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.
↑ ↓ ← → 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[]
↑ ↓ ← → 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
↑ ↓ ← → 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.
↑ ↓ ← → "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
↑ ↓ ← → 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.
↑ ↓ ← → "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
↑ ↓ ← → 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.
↑ ↓ ← → 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.
↑ ↓ ← → "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.
--
↑ ↓ ← → "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
↑ ↓ ← → "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.
--
↑ ↓ ← → "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:)
--
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → 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
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → "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;
}
--
↑ ↓ ← → 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;
}
↑ ↓ ← → "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.
--
↑ ↓ ← → 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
↑ ↓ ← → 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
↑ ↓ ← → 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
↑ ↓ ← → 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
↑ ↓ ← → 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
↑ ↓ ← → 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
↑ ↓ ← → 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.
↑ ↓ ← → "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']);
↑ ↓ ← → "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.
↑ ↓ ← → "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?
↑ ↓ ← → "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.
↑ ↓ ← → "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...
↑ ↓ ← → "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?
↑ ↓ ← → "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.
↑ ↓ ← → "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 );
}
↑ ↓ ← → "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.
↑ ↓ ← → "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 ] );
↑ ↓ ← → "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. )
--
↑ ↓ ← → 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.
↑ ↓ ← → "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.
--
↑ ↓ ← → 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.
↑ ↓ ← → 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 }.
↑ ↓ ← → "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
↑ ↓ ← → 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.
↑ ↓ ← → 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.
↑ ↓ ← → "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.
--
↑ ↓ ← → 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
↑ ↓ ← → "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.
↑ ↓ ← → "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.
↑ ↓ ← → "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.
↑ ↓ ← → "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
↑ ↓ ← → 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].
↑ ↓ ← → "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.
--
↑ ↓ ← → 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
↑ ↓ ← → 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
↑ ↓ ← → 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".
↑ ↓ ← → 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.
↑ ↓ ← → 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[]
↑ ↓ ← → "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-----
↑ ↓ ← → 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.
|