www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why D is annoying =P

reply "Mehrdad" <wfunction hotmail.com> writes:
I couldn't find a better title, sorry.


But yeah, I've spent too many hours on hunting down problems like 
these...


Could someone explain what's going on? Thanks!

import std.stdio;
struct S { int[int] aa; }
void main()
{
	writeln(  [1: 2]  ==   [1: 2] );  // true
	writeln(S([1: 2]) == S([1: 2]));  // false
}

(I'm on Windows DMD v2.060.)
Oct 24 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/24/2012 09:17 PM, Mehrdad wrote:
 I couldn't find a better title, sorry.


 But yeah, I've spent too many hours on hunting down problems like these...


 Could someone explain what's going on? Thanks!

 import std.stdio;
 struct S { int[int] aa; }
 void main()
 {
      writeln(  [1: 2]  ==   [1: 2] );  // true
      writeln(S([1: 2]) == S([1: 2]));  // false
 }

 (I'm on Windows DMD v2.060.)
http://d.puremagic.com/issues/show_bug.cgi?id=3789
Oct 24 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 19:25:47 UTC, Timon Gehr wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=3789
Ouch, bug since 2010... (Thanks for the link.)
Oct 24 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/24/12, Mehrdad <wfunction hotmail.com> wrote:
 Could someone explain what's going on? Thanks!
Struct fields are compared by address by default if no opEquals is defined. http://d.puremagic.com/issues/show_bug.cgi?id=3789
Oct 24 2012
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/24/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 10/24/12, Mehrdad <wfunction hotmail.com> wrote:
 Could someone explain what's going on? Thanks!
Struct fields are compared by address by default if no opEquals is defined. http://d.puremagic.com/issues/show_bug.cgi?id=3789
Well I mean for reference types. Or something like that. To put it bluntly: It's brokeeen.
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 19:28:36 UTC, Andrej Mitrovic 
wrote:
 On 10/24/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 10/24/12, Mehrdad <wfunction hotmail.com> wrote:
 Could someone explain what's going on? Thanks!
Struct fields are compared by address by default if no opEquals is defined. http://d.puremagic.com/issues/show_bug.cgi?id=3789
Well I mean for reference types. Or something like that. To put it bluntly: It's brokeeen.
Yeah, and my attempts to get around it don't seem to help: auto a = [1:1], b = [1:1]; writeln(a == b); // true writeln(a in [a:0]); // null
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 19:32:08 UTC, Mehrdad wrote:
 Yeah, and my attempts to get around it don't seem to help:

 	auto a = [1:1], b = [1:1];
 	writeln(a == b);       // true
 	writeln(a in [a:0]);   // null
Harsh (but true, and perhaps useful) feedback... I feel like this is a *perfect* example of the kinds of things that turn people off of D. I don't know what to expect code like this to do (unlike in C++, where everything is clearly defined in the specs), and when it seems to do what I want, it really turns out to be a bug in the library that it seemed to work in the first place. :(
Oct 24 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-10-24 21:37, Mehrdad wrote:

 I don't know what to expect code like this to do (unlike in C++, where
 everything is clearly defined in the specs), and when it seems to do
 what I want, it really turns out to be a bug in the library that it
 seemed to work in the first place. :(
Everything in C++ is specified as undefined behavior :) -- /Jacob Carlborg
Oct 24 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:04:24 UTC, Jacob Carlborg 
wrote:
 On 2012-10-24 21:37, Mehrdad wrote:

 I don't know what to expect code like this to do (unlike in 
 C++, where everything is clearly defined in the specs), and 
 when it seems to do what I want, it really turns out to be a 
 bug in the library that it seemed to work in the first place. 
 :(
Everything in C++ is specified as undefined behavior :)
lol. I meant more like, it's clear in C++ which operations need to be implemented in order for an object to be hashable, for instance. I can't figure out how hashing works in D at all.
Oct 24 2012
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 24, 2012 at 09:17:09PM +0200, Mehrdad wrote:
[...]
 Could someone explain what's going on? Thanks!
 
 import std.stdio;
 struct S { int[int] aa; }
 void main()
 {
 	writeln(  [1: 2]  ==   [1: 2] );  // true
 	writeln(S([1: 2]) == S([1: 2]));  // false
 }
[...] I don't know if there is any struct-specific problem here, but AA comparison right now is horribly horribly broken (search on the bug tracker for "AA" and you'll see a bunch of issues on that end). You're incredibly lucky that two AA literals actually compared equal. In some cases, not even that is guaranteed. I've tried to clean up the AA code but it's a tangled messy ugly labyrinth with fragile hacks sprinkled in, and didn't get to the point where it's ready to commit. One major obstacle is that parts of it are implemented in compiler hacks, and part of it is schizophrenically duplicated in object_.d, not necessarily consistently, and it's just Not Nice in general. That it works at all is reason enough to be thankful. I don't expect things to be pretty once you start poking into the intricacies of AA's, sad to say. T -- People tell me I'm stubborn, but I refuse to accept it!
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 19:34:15 UTC, H. S. Teoh wrote:
 I don't know if there is any struct-specific problem here, but 
 AA comparison right now is horribly horribly broken (search on 
 the bug tracker for "AA" and you'll see a bunch of issues on 
 that end). You're incredibly lucky that two AA literals 
 actually compared equal. In some cases, not even that is 
 guaranteed.
Yeah, I was a little aware that AAs were semi-broken, but I thought, hey, if it seems to work then it obviously works. Turns out that wasn't so true. :\
 I've tried to clean up the AA code but it's a tangled messy 
 ugly labyrinth with fragile hacks sprinkled in, and didn't get 
 to the point where it's ready to commit. One major obstacle is 
 that parts of it are implemented in compiler hacks, and part of 
 it is schizophrenically duplicated in object_.d, not 
 necessarily consistently, and it's just Not Nice in general. 
 That it works at all is reason enough to be thankful. I don't 
 expect things to be pretty once you start poking into the 
 intricacies of AA's, sad to say.
Yeah, the trouble is, none of the set-based data types (including maps) in D seem to be working... - AAs are broken - AssociativeArray is the same as above, I think? - RedBlackTree is useless (how do I keep a "set of sets"?) etc. So you can't really write a real program in D, to put it blunty.
Oct 24 2012
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote:
 So you can't really write a real program in D, to put it 
 bluntly.
Case in point: there's no way to tell an arbitrary object/struct to give you its hash code.
Oct 24 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 24, 2012 at 09:50:18PM +0200, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote:
So you can't really write a real program in D, to put it bluntly.
Case in point: there's no way to tell an arbitrary object/struct to give you its hash code.
Huh? All objects implement toHash(). If the default toHash() doesn't satisfy you, override it with your own. You can just use rt.util.hash.hashOf for structs. Use UFCS to make it callable as toHash(). Implement your own toHash() where hashOf isn't good enough. Problem solved. T -- Once bitten, twice cry...
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:07:49 UTC, H. S. Teoh wrote:
 On Wed, Oct 24, 2012 at 09:50:18PM +0200, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote:
So you can't really write a real program in D, to put it 
bluntly.
Case in point: there's no way to tell an arbitrary object/struct to give you its hash code.
Huh? All objects implement toHash().
Not Tuples, apparently. (I didn't mean Object, I mean "object" in the general sense.)
 You can just use rt.util.hash.hashOf for structs.
Will try, thanks for the pointer.
Oct 24 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 24, 2012 at 10:09:36PM +0200, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 20:07:49 UTC, H. S. Teoh wrote:
On Wed, Oct 24, 2012 at 09:50:18PM +0200, Mehrdad wrote:
On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote:
So you can't really write a real program in D, to put it
bluntly.
Case in point: there's no way to tell an arbitrary object/struct to give you its hash code.
Huh? All objects implement toHash().
Not Tuples, apparently. (I didn't mean Object, I mean "object" in the general sense.)
Well, Object implements toHash(). Other things don't, but with UFCS you can endow them with toHash(). :)
You can just use rt.util.hash.hashOf for structs.
Will try, thanks for the pointer.
hashOf works for pretty much anything (it's just a byte-based algo). So it's not just structs, you can pass anything to it. Using UFCS to map toHash() to hashOf will give you toHash() for literally everything, which is apparently what you want (though I question the wisdom of wanting a hash value of *everything*, including objects representing network resources, the OS, etc., but hey, you can do it if you *really* want to). T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:15:07 UTC, H. S. Teoh wrote:
 hashOf works for pretty much anything (it's just a byte-based 
 algo).
Byte-based? what about Set!(Tuple!(int, string)) s; s[tuple(1, "hi")] = 1; writeln(tuple(1, "hi".dup) in s); // null or not?
Oct 24 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:18:07 UTC, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 20:15:07 UTC, H. S. Teoh wrote:
 hashOf works for pretty much anything (it's just a byte-based 
 algo).
Byte-based? what about Set!(Tuple!(int, string)) s; s[tuple(1, "hi")] = 1; writeln(tuple(1, "hi".dup) in s); // null or not?
my bad, I mixed up AA and sets. That was supposed to insert the item, not map it to 1. Would it work?
Oct 24 2012
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 24, 2012 at 09:41:41PM +0200, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 19:34:15 UTC, H. S. Teoh wrote:
I don't know if there is any struct-specific problem here, but AA
comparison right now is horribly horribly broken (search on the
bug tracker for "AA" and you'll see a bunch of issues on that
end). You're incredibly lucky that two AA literals actually
compared equal. In some cases, not even that is guaranteed.
Yeah, I was a little aware that AAs were semi-broken, but I thought, hey, if it seems to work then it obviously works. Turns out that wasn't so true. :\
The AA implementation badly needs to be revamped. But the problem is that it's non-trivial, may break existing code, etc.. I do have a (semi) working version of a prospective AA replacement, though: https://github.com/quickfur/New-AA-implementation You might be able to make use of it if you're willing to live with broken IFTI (which is no big deal if you just explicitly type what you instantiate the AA with).
I've tried to clean up the AA code but it's a tangled messy ugly
labyrinth with fragile hacks sprinkled in, and didn't get to the
point where it's ready to commit. One major obstacle is that parts
of it are implemented in compiler hacks, and part of it is
schizophrenically duplicated in object_.d, not necessarily
consistently, and it's just Not Nice in general. That it works at
all is reason enough to be thankful. I don't expect things to be
pretty once you start poking into the intricacies of AA's, sad to
say.
Yeah, the trouble is, none of the set-based data types (including maps) in D seem to be working... - AAs are broken - AssociativeArray is the same as above, I think?
Yes it's the same. It's not meant to be used directly by user code, though. The two are supposed to be the same.
 - RedBlackTree is useless (how do I keep a "set of sets"?)
What's wrong with RedBlackTree? You can just do something like: RedBlackTree!(RedBlackTree!MySet) setOfSets; [...]
 So you can't really write a real program in D, to put it blunty.
That's a bit harsh. It's not hard to write your own hash implementation in D, given the expressiveness of its templates and compile-time features. The bugginess of the built-in AA is lamentable, definitely, but it doesn't *prevent* you from writing your own data structures. All programmers worth their salt should be able to roll their own where the current implementation is inadequate, anyway. ;-) In any case, as they say in the open source community, patches are always welcome. Plus, you *can* use AA's for all sorts of stuff in general, if you just avoid some of the most glaring bugs. It only takes 15 minutes to write your own opEquals() in a struct that wraps around an AA, and it's equally fast to parametrize that struct to take arbitrary types, and provide wrapper functions that work around the current bugs. None of the current issues are showstoppers, as annoying as they may be. T -- Do not reason with the unreasonable; you lose by definition.
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:03:44 UTC, H. S. Teoh wrote:
 What's wrong with RedBlackTree? You can just do something like:

 	RedBlackTree!(RedBlackTree!MySet) setOfSets;
The last time I checked two RedBlackTrees for equality, they seemed to have reference semantics...
 [...]
 So you can't really write a real program in D, to put it 
 blunty.
That's a bit harsh.
Sorry, just saying what I experienced :(
 It's not hard to write your own hash implementation in D
I beg to differ, see below
 given the expressiveness of its templates and compile-time 
 features. The bugginess of the built-in AA is lamentable, 
 definitely, but it doesn't *prevent* you from writing your own 
 data structures.
It does. There's simply no mechanism to hash an arbitrary thing in D. (hashOf, which Andrej just mentioned, is an internal thing, right? aka a hack, which I was not aware of)
 All programmers worth their salt should be able to roll their 
 own where the current implementation is inadequate, anyway. ;-)
Well, there's different issues involved... - Can I? Yes. - Will I? No, it takes more time than it's worth
 In any case,  as they say in the open source community, patches 
 are always welcome.
Yeah, it's just that I can't figure out even the basics of hashing in D (above), so I can't really patch something because then it'll turn out to be working in a different way than I expect.
 It only takes 15 minutes to write your own opEquals() in a 
 struct that wraps around an AA
I've spent longer than that right now and still haven't been able to (but I haven't tried the hashOf hack yet). Maybe you can fill in the blanks? struct Set(T) { int[T] dict; hash_t toHash() const { typeof(return) r = 0; foreach (item; this.dict.keys) { ??? // what should be here? } return r; } }
Oct 24 2012
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 24, 2012 at 10:16:27PM +0200, Mehrdad wrote:
[...]
 struct Set(T)
 {
 	int[T] dict;
 	hash_t toHash() const
 	{
 		typeof(return) r = 0;
 		foreach (item; this.dict.keys)
 		{
 			???       // what should be here?
 		}
 		return r;
 	}
 }
Try this: hash_t toHash() const { hash_t h = 0; foreach (item; this.dict.keys) { // We use a commutative operation here (+) so // that the order of keys don't matter. h += hashOf(&item, item.sizeof); } return h; } T -- What do you get if you drop a piano down a mineshaft? A flat minor.
Oct 24 2012
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:37:08 UTC, H. S. Teoh wrote:
 On Wed, Oct 24, 2012 at 10:16:27PM +0200, Mehrdad wrote:
 [...]
 struct Set(T)
 {
 	int[T] dict;
 	hash_t toHash() const
 	{
 		typeof(return) r = 0;
 		foreach (item; this.dict.keys)
 		{
 			???       // what should be here?
 		}
 		return r;
 	}
 }
Try this: hash_t toHash() const { hash_t h = 0; foreach (item; this.dict.keys) { // We use a commutative operation here (+) so // that the order of keys don't matter. h += hashOf(&item, item.sizeof); } return h; } T
Wouldn't that do a bitwise comparison?
Oct 24 2012
next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:38:08 UTC, Mehrdad wrote:
 Wouldn't that do a bitwise comparison?
sorry, I mean bitwise _hash_
Oct 24 2012
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 24, 2012 at 10:38:07PM +0200, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 20:37:08 UTC, H. S. Teoh wrote:
On Wed, Oct 24, 2012 at 10:16:27PM +0200, Mehrdad wrote:
[...]
struct Set(T)
{
	int[T] dict;
	hash_t toHash() const
	{
		typeof(return) r = 0;
		foreach (item; this.dict.keys)
		{
			???       // what should be here?
		}
		return r;
	}
}
Try this: hash_t toHash() const { hash_t h = 0; foreach (item; this.dict.keys) { // We use a commutative operation here (+) so // that the order of keys don't matter. h += hashOf(&item, item.sizeof); } return h; } T
Wouldn't that do a bitwise comparison?
Umm, the idea of a hash is to *quickly* compute a value that's (mostly) unique for a given object. In most cases, the bit representation is good enough. If you want a thorough recursive comparison of all subobjects, you should overload opEquals and use that instead. Or use compile-time reflection to iterate over every member of the given object and recursively iterate and hash them. Though I fail to see the point of it, since it defeats the purpose of a hash in the first place - you might as well just do the usual recursive compare instead. T -- Never step over a puddle, always step around it. Chances are that whatever made it is still dripping.
Oct 24 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:47:30 UTC, H. S. Teoh wrote:
 Umm, the idea of a hash is to *quickly* compute a value that's 
 (mostly) unique for a given object. In most cases, the bit 
 representation is good enough.
I don't understand what you're saying. hash(tuple("foo".dup)) MUST be equal to hash(tuple("foo".dup")). Bitwise hashing makes no sense whatsoever.
Oct 24 2012
prev sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
Is there any reason why we don't have something like this in 
Phobos?



hash_t toHash(T)(in T t) if (isIntegral!(T) || isSomeChar!(T))
{
	return t;
}

hash_t toHash(T)(in T[] t)
{
	typeof(return) h = 0;
	foreach (item; t)
	{ h = h * 37 + item.toHash(); }
	return h;
}

hash_t toHash(T)(in T t) if (!isIntegral!(T) && !isSomeChar!(T) 
&& !isArray!(T))
{
	typeof(return) h = 0;
	foreach (ref a; t.tupleof)
	{ h = h * 37 + a.toHash(); }
	return h;
}

hash_t toHash(T...)(in Tuple!(T) t)
{
	typeof(return) h = 0;
	foreach (item; t)
	{ h = h * 37 + item.toHash(); }
	return h;
}
Oct 24 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
Better example:



private import std.traits, std.typecons, std.typetuple;

hash_t toHash(T)(in T t)
	if (isIntegral!(T) || isSomeChar!(T))
{ return t; }

hash_t toHash(T)(in T[] t)
{
	typeof(return) h = 0;
	foreach (item; t)
	{ h = (h * 37) ^ item.toHash(); }
	return h;
}

hash_t toHash(V, K)(in V[K] t)
{
	typeof(return) h = 0;
	foreach (k, v; t)
	{ h ^= k.toHash(); }
	return h;
}

hash_t toHash(T)(in T t)
	if (!isIntegral!(T) &&
	    !isSomeChar!(T) &&
	    !isArray!(T) &&
             !isAssociativeArray!(T))
{
	typeof(return) h = 0;
	foreach (ref a; t.tupleof)
	{ h = (h * 37) ^ a.toHash(); }
	return h;
}

void main()
{
	import std.stdio;
	writeln(tuple("hi", [[1: 2].keys.dup], [1: 2, 8: 4]).toHash());
	writeln(tuple("hi", [[1: 2].keys.dup], [1: 2, 8: 4]).toHash());  
// same thing as above
}





We really _need_ something like this in Phobos IMHO.
Oct 24 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/24/2012 10:16 PM, Mehrdad wrote:
 ...

 Maybe you can fill in the blanks?
import std.stdio; struct Set(T){ int[T] dict; hash_t toHash() const{ typeof(return) r = 0; foreach(item; this.dict.keys){ r+=typeid(T).getHash(&item); } return r; } }
Oct 24 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 21:55:11 UTC, Timon Gehr wrote:
 On 10/24/2012 10:16 PM, Mehrdad wrote:
 ...

 Maybe you can fill in the blanks?
import std.stdio; struct Set(T){ int[T] dict; hash_t toHash() const{ typeof(return) r = 0; foreach(item; this.dict.keys){ r+=typeid(T).getHash(&item); } return r; } }
I'm on my phone so I can't test it right now, but I'm wondering how that would possibly work correctly for Tuples and such?
Oct 24 2012
prev sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 10/24/2012 01:16 PM, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 20:03:44 UTC, H. S. Teoh wrote:
 What's wrong with RedBlackTree? You can just do something like:

     RedBlackTree!(RedBlackTree!MySet) setOfSets;
The last time I checked two RedBlackTrees for equality, they seemed to have reference semantics...
Dang. import std.container; import std.stdio; void main() { auto a = make!(RedBlackTree!int)(1,2,3,4); auto b = make!(RedBlackTree!int)(1,2,3,4); writeln(a == b); } prints false Explanation: RedBlackTree doesn't override opEquals. Either file an enhancement request or use equal(a[], b[]), depending on whether opEquals *should* have reference semantics. Actually, it shouldn't, since that would differ from array/string opEquals semantics. SList works Array works Oop. DList goes into infinite loop. Dibs on this bug report.
Oct 25 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Oct 25, 2012 at 06:34:32PM -0700, Ellery Newcomer wrote:
 On 10/24/2012 01:16 PM, Mehrdad wrote:
On Wednesday, 24 October 2012 at 20:03:44 UTC, H. S. Teoh wrote:
What's wrong with RedBlackTree? You can just do something like:

    RedBlackTree!(RedBlackTree!MySet) setOfSets;
The last time I checked two RedBlackTrees for equality, they seemed to have reference semantics...
Dang. import std.container; import std.stdio; void main() { auto a = make!(RedBlackTree!int)(1,2,3,4); auto b = make!(RedBlackTree!int)(1,2,3,4); writeln(a == b); } prints false Explanation: RedBlackTree doesn't override opEquals. Either file an enhancement request or use equal(a[], b[]), depending on whether opEquals *should* have reference semantics.
Hmph. This is what I don't like about the built-in ==. Its semantics are inconsistent once you leave the realm of ints and floats and other numerical types. I think this one is worthy of a bug report.
 Actually, it shouldn't, since that would differ from array/string
 opEquals semantics.
Yeah, Jonathan is right, "==" should *always* do a deep compare, and leave "is" to do a shallow compare. Anything else is inconsistent, and leads to all kinds of pathological bugs. T -- Любишь кататься - люби и саночки возить.
Oct 25 2012
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 10/25/2012 09:19 PM, H. S. Teoh wrote:
 Hmph. This is what I don't like about the built-in ==. Its semantics are
 inconsistent once you leave the realm of ints and floats and other
 numerical types. I think this one is worthy of a bug report.
Well, if nobody else is going to take it http://d.puremagic.com/issues/show_bug.cgi?id=8896
Oct 25 2012
prev sibling next sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote:
 So you can't really write a real program in D, to put it blunty.
So should I drop a project I'm working on and go to C++? That isn't something I look forward to doing...
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 21:55:53 UTC, Era Scarecrow 
wrote:
 On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote:
 So you can't really write a real program in D, to put it 
 blunty.
So should I drop a project I'm working on and go to C++? That isn't something I look forward to doing...
Well if it's been working for you then there's obviously no reason to. :) I couldn't say the same thing, though.
Oct 24 2012
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/24/12 8:53 PM, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 21:55:53 UTC, Era Scarecrow wrote:
 On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote:
 So you can't really write a real program in D, to put it blunty.
So should I drop a project I'm working on and go to C++? That isn't something I look forward to doing...
Well if it's been working for you then there's obviously no reason to. :) I couldn't say the same thing, though.
OK let's stop this. There's a bug that needs fixing, is all. Andrei
Oct 24 2012
next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 25 October 2012 at 01:01:10 UTC, Andrei Alexandrescu 
wrote:
 OK let's stop this. There's a bug that needs fixing, is all.

 Andrei
Sorry, yeah. It was just that I came across it so much that I wanted to put it on the radar here, to let you guys know what sorts of problems you'd run into when you try using D. It was meant to be honest feedback, that's all... I realize it was negative hopefully it was at least constructive. Any opinions on my proposed "fixed" version, which used .tupleof?
Oct 24 2012
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, October 24, 2012 21:01:11 Andrei Alexandrescu wrote:
 OK let's stop this. There's a bug that needs fixing, is all.
And as bad as things may be now, they're _way_ better than they were a couple of years ago (or even a year ago). The situation isn't perfect, but it's constantly improving. It's becoming rarer and rarer for programmers to run into compiler bugs. You can actually write plenty of programmers now without running into any, whereas before, you'd run into them all the time. - Jonathan M Davis
Oct 24 2012
next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 25 October 2012 at 02:55:20 UTC, Jonathan M Davis 
wrote:
 On Wednesday, October 24, 2012 21:01:11 Andrei Alexandrescu 
 wrote:
 OK let's stop this. There's a bug that needs fixing, is all.
And as bad as things may be now, they're _way_ better than they were a couple of years ago (or even a year ago). The situation isn't perfect, but it's constantly improving. It's becoming rarer and rarer for programmers to run into compiler bugs. You can actually write plenty of programmers now without running into any, whereas before, you'd run into them all the time. - Jonathan M Davis
Yeah that's definitely very true. :) Sorry that the negative feedback seems to drown out anything that looks positive... but I've definitely noticed the improvement (and that's what makes me come back and try writing a program in D every once in a while). Props to you guys for the work!
Oct 24 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 25/10/2012 03:35, Jonathan M Davis a écrit :
 On Wednesday, October 24, 2012 21:01:11 Andrei Alexandrescu wrote:
 OK let's stop this. There's a bug that needs fixing, is all.
And as bad as things may be now, they're _way_ better than they were a couple of years ago (or even a year ago). The situation isn't perfect, but it's constantly improving. It's becoming rarer and rarer for programmers to run into compiler bugs.
Is this a joke ? That is true that many bug get solved, but I encounter compiler bugs almost on a daily basis, and a lot of workaround are present in my codebase. I'm ready to heard that I run into more bugs due to my coding style or whatever, but I have hard time to understand how running into compiler bugs can be rarer and rarer. You can actually write plenty of programmers now without
 running into any, whereas before, you'd run into them all the time.

 - Jonathan M Davis
Oct 26 2012
prev sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Thursday, 25 October 2012 at 00:53:31 UTC, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 21:55:53 UTC, Era Scarecrow
 So should I drop a project I'm working on and go to C++? That 
 isn't something I look forward to doing...
Well if it's been working for you then there's obviously no reason to. :) I couldn't say the same thing, though.
You can always work around what does and doesn't work; Although preferably you shouldn't have to. I can only think that the best way to support the D language is simply to use it. If there's several programs that really get attention that shows the flexibility and use of D then it's more likely to be used. My biggest obstacle(s) right now is time & memory. With new issues coming up it makes you think in different directions, which all makes sense once you look for them.
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 25 October 2012 at 01:36:00 UTC, Era Scarecrow wrote:
 On Thursday, 25 October 2012 at 00:53:31 UTC, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 21:55:53 UTC, Era Scarecrow
 So should I drop a project I'm working on and go to C++? That 
 isn't something I look forward to doing...
Well if it's been working for you then there's obviously no reason to. :) I couldn't say the same thing, though.
You can always work around what does and doesn't work; Although preferably you shouldn't have to.
Well I mean, yeah, you can obviously implement your own data structures, and eventually, your own version of Phobos, even. The trouble is, then you're fighting the framework, and nothing integrates with anything else. Some data structure expects a toHash() instance method, another expects .hashOf, another getHash(), another getHashCode(), another might say hashCode(), and yet another might just expect a template specialization, like in C++. So the point is, yes, it's possible. It's not that I can't work around it, but it defeats the whole purpose of switching to D.
Oct 24 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Thursday, 25 October 2012 at 01:50:05 UTC, Mehrdad wrote:
 Well I mean, yeah, you can obviously implement your own data 
 structures, and eventually, your own version of Phobos, even.

 The trouble is, then you're fighting the framework, and nothing 
 integrates with anything else. Some data structure expects a 
 toHash() instance method, another expects .hashOf, another 
 getHash(), another getHashCode(), another might say hashCode(), 
 and yet another might just expect a template specialization, 
 like in C++.

 So the point is, yes, it's possible. It's not that I can't work 
 around it, but it defeats the whole purpose of switching to D.
I have no intention of writing a different version of phobos or breaking the framework. I'll work within the framework as much as possible; Working around the issues usually ends up force casting something so you can get the job done (but you still need to honor the type's original contract). I'll just hope my data processing won't require anything that's broken or going to be depreciated, I've already dropped using std.stream for ranges instead. Dropping classes in favor of structs.
Oct 24 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Oct 25, 2012 at 04:08:21AM +0200, Era Scarecrow wrote:
[...]
 I'll just hope my data processing won't require anything that's
 broken or going to be depreciated, I've already dropped using
 std.stream for ranges instead. Dropping classes in favor of structs.
Huh? Why would you drop classes in favor of structs? They are used for two different purposes. Classes are for when you need polymorphism: inheritance, overloading, interfaces, all the trappings of OO programming. Structs are for when you need value types that doesn't need OO-style manipulations. Not the same thing. T -- One Word to write them all, One Access to find them, One Excel to count them all, And thus to Windows bind them. -- Mike Champion
Oct 24 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Thursday, 25 October 2012 at 02:19:39 UTC, H. S. Teoh wrote:

 Huh? Why would you drop classes in favor of structs? They are 
 used for two different purposes. Classes are for when you need 
 polymorphism: inheritance, overloading, interfaces, all the 
 trappings of OO programming. Structs are for when you need 
 value types that doesn't need OO-style manipulations. Not the 
 same thing.
Indeed. Instead of interfaces you'd use templates, OO doesn't change really all that much. There's also large amounts of memory consumption that just isn't needed for data that hasn't and/or isn't going to change. More often I'm thinking structs w/templates are more powerful than classes. I'm experimenting with a polymorphic struct. Run-time price is a couple enum checks if there's multiple functions that might qualify, and slightly different calling for those polymorphic types.
Oct 24 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Oct 25, 2012 at 04:46:04AM +0200, Era Scarecrow wrote:
 On Thursday, 25 October 2012 at 02:19:39 UTC, H. S. Teoh wrote:
 
Huh? Why would you drop classes in favor of structs? They are used
for two different purposes. Classes are for when you need
polymorphism: inheritance, overloading, interfaces, all the trappings
of OO programming. Structs are for when you need value types that
doesn't need OO-style manipulations. Not the same thing.
Indeed. Instead of interfaces you'd use templates, OO doesn't change really all that much. There's also large amounts of memory consumption that just isn't needed for data that hasn't and/or isn't going to change. More often I'm thinking structs w/templates are more powerful than classes.
[...] Used correctly, *classes* with templates can be pretty powerful too. Recently I wrote an expression parser that can either parse the expression into a tree, or compute its value on-the-fly. I didn't like the idea of duplicating the parser code for both usages, so I decided to turn the parser into a template that would do one or the other. The template would call a static class method at key points during the parse, which alleviates the parser from knowing (or caring) what was done with the parsed expression -- the method could build a tree, or evaluate the expression, etc.. While I was coding that, I realized that lots of code is still being duplicated -- for example, to implement building a tree with +, -, *, and / operators _and_ to evaluate the same operators on-the-fly, required that operator-specific code be written in both classes. That was when I realized that I can leverage inheritance by factoring the operator-specific code into the base class, and overriding the static method in the derived class so that when the parser was instantiated with the base class, it built an expression tree, whereas when instantiated with the derived class, it would evaluate the expression. And moreover, the return type of the parser would be the derived class, so the caller doesn't even need to downcast to read the computed value. And all the while, the derived class can also be used as leaf nodes in the full expression tree, when building the latter. So even though things like templated virtual methods don't work, you *can* still make pretty potent combinations of templates + classes. T -- Doubtless it is a good thing to have an open mind, but a truly open mind should be open at both ends, like the food-pipe, with the capacity for excretion as well as absorption. -- Northrop Frye
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
Funny, I was actually building a (GLR) parser, too.

Keeping track of duplicate item sets was what tripped me up.
Oct 24 2012
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Oct 25, 2012 at 05:34:05AM +0200, Mehrdad wrote:
 Funny, I was actually building a (GLR) parser, too.
 
 Keeping track of duplicate item sets was what tripped me up.
Oh. You should've said so earlier -- for such specific applications, you don't _need_ a fully generalized solution to the AA hash problem. You can just implement your own .toHash methods on the structs/objects your parser uses, and be done with it. No need to try to accomodate every single type D has or can have -- that's the kind of thing Phobos developers have to worry about, not people who have a specific application in mind. I've learnt from hard experience that premature generalization is just as evil as premature optimization. (Believe me, I'm a sucker for completely general solutions too -- I like killing ants with nuclear warheads, proverbially speaking, just for the feeling of confidence that that it would've also worked in the hypothetical scenario of levelling an entire city.) You usually end up completely frustrated that the system/language you're using just doesn't have that one last bit of homogeneity for your generalization to fully work, and eventually the project never gets off the ground. But in many cases, I've learned, this is all needless pain. Write the case-specific code first, and then refactor and generalize it afterwards. Works much better, I find, and you have a tangible product to speak of from the get-go, instead of spending countless hours writing a generic framework that eventually never gets used. Plus, when you actually have a *working* codebase, exactly which generalizations will work, and which are just castles in the air, tend to be a lot more obvious than when you're just sketching the product on the drawing board. Just my slightly more than $0.02. :) T -- English has the lovely word "defenestrate", meaning "to execute by throwing someone out a window", or more recently "to remove Windows from a computer and replace it with something useful". :-) -- John Cowan
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
Haha thanks a bunch for the advice. :) I was actually intending 
it to be a quick hack, not a highly-generalized thing.

So I thought, hey, I'll just use a
Tuple!(string, q{symbol}, size_t, q{iRule}, size_t, q{iSymbol})
to denote an "LR Item".



So an "item set" became RedBlackTree!(Tuple!(...)), but that 
didn't work because of the reference semantics.

So I tried int[Tuple!(...)], and hence the story.



(I actually even scrapped the idea of using a 'set' and just used 
an array.

Screw the O(n) performance.

But one of my goals was getting the code to be concise (the idea 
was to use CTFE + mixins/templates to generate some optimized 
code with switch statements for the parser), but sprinkling it 
with all the sort()s and all the code required to switch from 
hashtables to arrays just made it too ugly/indecipherable for me 
to continue working on it.)

etc.

But yeah, thanks for the advice, I'll keep it in mind. :)
Oct 24 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Oct 25, 2012 at 06:21:02AM +0200, Mehrdad wrote:
 Haha thanks a bunch for the advice. :) I was actually intending it
 to be a quick hack, not a highly-generalized thing.
 
 So I thought, hey, I'll just use a
 Tuple!(string, q{symbol}, size_t, q{iRule}, size_t, q{iSymbol})
 to denote an "LR Item".
[...] Hmm, why are you using Tuple? Shouldn't you be using a struct? T -- People tell me I'm stubborn, but I refuse to accept it!
Oct 24 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 25 October 2012 at 04:39:28 UTC, H. S. Teoh wrote:
 On Thu, Oct 25, 2012 at 06:21:02AM +0200, Mehrdad wrote:
 Haha thanks a bunch for the advice. :) I was actually 
 intending it
 to be a quick hack, not a highly-generalized thing.
 
 So I thought, hey, I'll just use a
 Tuple!(string, q{symbol}, size_t, q{iRule}, size_t, q{iSymbol})
 to denote an "LR Item".
[...] Hmm, why are you using Tuple? Shouldn't you be using a struct? T
Hmm, why would I prefer a struct over a Tuple? I see it as, like, coordinates -- the index of the symbol in the production, and the index of the production for a given nonterminal symbol. So tuple(x, y, z) kinda made sense. Especially since I was going back/forth between D & Python.
Oct 24 2012
prev sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Thu, Oct 25, 2012 at 5:34 AM, Mehrdad <wfunction hotmail.com> wrote:
 Funny, I was actually building a (GLR) parser, too.

 Keeping track of duplicate item sets was what tripped me up.
H. S. Teoh, Mehrdad: are your codebases in a public website?
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 25 October 2012 at 05:11:38 UTC, Philippe Sigaud 
wrote:
 On Thu, Oct 25, 2012 at 5:34 AM, Mehrdad 
 <wfunction hotmail.com> wrote:
 Funny, I was actually building a (GLR) parser, too.

 Keeping track of duplicate item sets was what tripped me up.
H. S. Teoh, Mehrdad: are your codebases in a public website?
Nope. I'll consider releasing it when I make it decent, but right now, there's really nothing to put anywhere. (I've probably re-started like 6 times now, like twice with each language. Each one had its own downfalls; I tried D because I thought it would have great opportunities with CTFE and mixins. But so far the code has always been ugly and I've run into the problem of not really wanting to debug my own code.)
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
Actually, I think I might as well send you a link to something I 


https://gist.github.com/203f8d65b60fe2d75339



Grab it before it's gone ;) I might delete it at some point.



It was meant to be my stab at what I _thought_ a "recursive 
ascent-descent parser" should do.

I really have no idea if it's correct or not, so be careful.

I also don't know if the code is buggy or not, so... yeah.
Oct 24 2012
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Thu, Oct 25, 2012 at 7:51 AM, Mehrdad <wfunction hotmail.com> wrote:
 Actually, I think I might as well send you a link to something I had in


 https://gist.github.com/203f8d65b60fe2d75339



 Grab it before it's gone ;) I might delete it at some point.
Thanks :)
Oct 25 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/24/2012 09:41 PM, Mehrdad wrote:
 ...
 So you can't really write a real program in D, to put it blunty.
Yes I can.
Oct 24 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 22:00:27 UTC, Timon Gehr wrote:
 On 10/24/2012 09:41 PM, Mehrdad wrote:
 ...
 So you can't really write a real program in D, to put it 
 blunty.
Yes I can.
So you made your own AA and Set implementations instead of trying to use Photos? Or did you never run into these problems?
Oct 24 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/25/2012 12:22 AM, Mehrdad wrote:
 On Wednesday, 24 October 2012 at 22:00:27 UTC, Timon Gehr wrote:
 On 10/24/2012 09:41 PM, Mehrdad wrote:
 ...
 So you can't really write a real program in D, to put it blunty.
Yes I can.
So you made your own AA and Set implementations instead of trying to use Photos?
I have written a custom hash map.
 Or did you never run into these problems?
It is actually hard to miss them.
Oct 24 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-10-24 21:41, Mehrdad wrote:

 Yeah, the trouble is, none of the set-based data types (including maps)
 in D seem to be working...

 - AAs are broken
 - AssociativeArray is the same as above, I think?
 - RedBlackTree is useless (how do I keep a "set of sets"?)
 etc.


 So you can't really write a real program in D, to put it blunty.
I haven't read the rest of thread yet but if you're not happy the the collections in D or Phobos, Tango has a collection package and Steven Schveighoffer has a collection library (don't remember where though). -- /Jacob Carlborg
Oct 24 2012
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/24/2012 12:17 PM, Mehrdad wrote:
 I couldn't find a better title, sorry.


 But yeah, I've spent too many hours on hunting down problems like these...


 Could someone explain what's going on? Thanks!

 import std.stdio;
 struct S { int[int] aa; }
 void main()
 {
      writeln(  [1: 2]  ==   [1: 2] );  // true
      writeln(S([1: 2]) == S([1: 2]));  // false
 }

 (I'm on Windows DMD v2.060.)
The compare for associative arrays is to compare the members. The default compare for structs is a bit compare of the contents.
Oct 24 2012
next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 24 October 2012 at 20:32:00 UTC, Walter Bright 
wrote:
 The default compare for structs is a bit compare of the 
 contents.
Thanks for the reply. And hmm, that should be changed IMO. ;) Bitwise comparison is nearly useless.
Oct 24 2012
prev sibling next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, October 24, 2012 13:31:14 Walter Bright wrote:
 The default compare for structs is a bit compare of the contents.
Which definitely seems inherently broken. Doing that only works if the struct only contains integral types, character types, or bool. Nothing else will compare properly that way. It really needs to work like arrays do (or are supposed to anyway) and compare each member according to == and only fallback to an outright bitwise compare when it knows that the results would be identical (i.e. because all of the members are integral types, character types, bool, or other structs which hold only integral types, character types, or bool - be it directly or in other structs that they hold). Bitwise comparison is the is operator's job, not ==. - Jonathan M Davis
Oct 24 2012
next sibling parent "Dejan Lekic" <dejan.lekic gmail.com> writes:
On Thursday, 25 October 2012 at 02:12:58 UTC, Jonathan M Davis 
wrote:
 On Wednesday, October 24, 2012 13:31:14 Walter Bright wrote:
 The default compare for structs is a bit compare of the 
 contents.
Which definitely seems inherently broken. Doing that only works if the struct only contains integral types, character types, or bool. Nothing else will compare properly that way. It really needs to work like arrays do (or are supposed to anyway) and compare each member according to == and only fallback to an outright bitwise compare when it knows that the results would be identical (i.e. because all of the members are integral types, character types, bool, or other structs which hold only integral types, character types, or bool - be it directly or in other structs that they hold). Bitwise comparison is the is operator's job, not ==. - Jonathan M Davis
+1 I can only agree with this. People who monitor the NG know about the problem but it is probably very confusing to D newbies.
Oct 25 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 25/10/2012 04:12, Jonathan M Davis a écrit :
 On Wednesday, October 24, 2012 13:31:14 Walter Bright wrote:
 The default compare for structs is a bit compare of the contents.
Which definitely seems inherently broken. Doing that only works if the struct only contains integral types, character types, or bool. Nothing else will compare properly that way. It really needs to work like arrays do (or are supposed to anyway) and compare each member according to == and only fallback to an outright bitwise compare when it knows that the results would be identical (i.e. because all of the members are integral types, character types, bool, or other structs which hold only integral types, character types, or bool - be it directly or in other structs that they hold). Bitwise comparison is the is operator's job, not ==. - Jonathan M Davis
That will broke code. But That is the way to go IMO. D needs to evolve to make things more consistent in general. Still not doable without a proper versionning scheme.
Oct 26 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, October 26, 2012 19:46:16 deadalnix wrote:
 Le 25/10/2012 04:12, Jonathan M Davis a =C3=A9crit :
 On Wednesday, October 24, 2012 13:31:14 Walter Bright wrote:
 The default compare for structs is a bit compare of the contents.
=20 Which definitely seems inherently broken. Doing that only works if =
the
 struct only contains integral types, character types, or bool. Noth=
ing
 else will compare properly that way. It really needs to work like a=
rrays
 do (or are supposed to anyway) and compare each member according to=
=3D=3D
 and only fallback to an outright bitwise compare when it knows that=
the
 results would be identical (i.e. because all of the members are int=
egral
 types, character types, bool, or other structs which hold only inte=
gral
 types, character types, or bool - be it directly or in other struct=
s that
 they hold). Bitwise comparison is the is operator's job, not =3D=3D=
.
=20
 - Jonathan M Davis
=20 That will broke code. =20 But That is the way to go IMO. D needs to evolve to make things more consistent in general. =20 Still not doable without a proper versionning scheme.
TDPL clearly states that each of the struct's members are supposed to b= e=20 checked for equality (see section 7.1.5.2, p. 258 - 259). It's outright= a bug=20 for structs to be checked for equality with a bitwise comparison when t= he=20 bitwise comparison does not do exactly what =3D=3D would have done had = each and=20 every member variable been compared with =3D=3D. And as with all bugs, = fixing it=20 could break code which depends on the buggy behavior. But given the nat= ure of=20 this bug, I seriously question that much of anyone thought that the =3D= =3D on=20 structs was supposed to do anything other than what TDPL states that it= should=20 and that pretty much no one was expecting it to do a bitwise comparison= . So,=20 if anything, this will _fix_ far more code than it breaks. - Jonathan M Davis
Oct 27 2012
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Oct 27, 2012 at 07:52:37PM -0700, Jonathan M Davis wrote:
[...]
 TDPL clearly states that each of the struct's members are supposed to
 be checked for equality (see section 7.1.5.2, p. 258 - 259). It's
 outright a bug for structs to be checked for equality with a bitwise
 comparison when the bitwise comparison does not do exactly what ==
 would have done had each and every member variable been compared with
 ==. And as with all bugs, fixing it could break code which depends on
 the buggy behavior. But given the nature of this bug, I seriously
 question that much of anyone thought that the == on structs was
 supposed to do anything other than what TDPL states that it should and
 that pretty much no one was expecting it to do a bitwise comparison.
 So, if anything, this will _fix_ far more code than it breaks.
[...] +1. I have to say I was surprised to find out about this after I started using D; after first reading TDPL, I had the impression that it was supposed to do the "right thing" (and the right thing being == on each field, which I assumed the compiler would optimize into a bitwise compare where possible). Let's fix this. T -- He who does not appreciate the beauty of language is not worthy to bemoan its flaws.
Oct 27 2012
parent reply "Rob T" <rob ucora.com> writes:
On Sunday, 28 October 2012 at 05:28:20 UTC, H. S. Teoh wrote:

 I have to say I was surprised to find out about this after I 
 started
 using D; after first reading TDPL, I had the impression that it 
 was
 supposed to do the "right thing" (and the right thing being == 
 on each
 field, which I assumed the compiler would optimize into a 
 bitwise
 compare where possible).

 Let's fix this.
There is a problem with floating point memebers, since nan values will always compare false. There's other things in D that bother me, such as how struc pointers are managed, where they sometimes behave exactly like class references, but not always. The inconsistent behaviour is a trap for the programmer to fall into, and it leads to subtle hard to find errors. For example: struct S { int a; ~this() {} } class C { int a; ~this() {} } // identical behaviour auto Sp = new S; auto Cr = new C; // identical behaviour writeln(Sp.a); writeln(Cr.a); // identical behaviour auto Sp2 = Sp; auto Cr2 = Cr; writeln(Sp2.a); writeln(Cr2.a); // ? assert(Sp2 == Sp); assert(Cr2 == Cr); // different behaviour! clear(Sp); clear(Cr); Last two line compile OK, but clear(Sp) does not invoke the destructor while clear(Cr) does. clear(*Sp) works, but why allow clear(Sp) if it's a pointless operation? Is this a bug in the compiler or with the language design? Subtle differences like this are very nasty. The code should behave identically for both the struct pointer and the class reference, and if this is not poosible for some obscure reason, then the compiler should fail at the clear(Sp) line. If I invoke with clear(*Sp) it works, but the inconsistency makes template code that takes in both a struct or a class impossible to do (or at best needlessly difficult to do). --rt
Oct 29 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Oct 29, 2012 at 06:34:14PM +0100, Rob T wrote:
[...]
 There is a problem with floating point memebers, since nan values will
 always compare false.
This is IEEE specification. There is no problem. T -- Frank disagreement binds closer than feigned agreement.
Oct 29 2012
parent reply "Rob T" <rob ucora.com> writes:
On Monday, 29 October 2012 at 18:39:41 UTC, H. S. Teoh wrote:
 On Mon, Oct 29, 2012 at 06:34:14PM +0100, Rob T wrote:
 [...]
 There is a problem with floating point memebers, since nan 
 values will
 always compare false.
This is IEEE specification. There is no problem. T
If struc comparisions compare value by value, and both have Nan values in one member variable, then the two otherwise completely identical structs will always compare false even though they are identical. I think it would be best to have the ability to compare structs in two ways, one as struct equivalence, which would be the default method, the other as vale by value equivalence, which would have to be programmer defined through overload of == operator. --rt
Oct 29 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 29 October 2012 at 19:55:41 UTC, Rob T wrote:
 On Monday, 29 October 2012 at 18:39:41 UTC, H. S. Teoh wrote:
 On Mon, Oct 29, 2012 at 06:34:14PM +0100, Rob T wrote:
 [...]
 There is a problem with floating point memebers, since nan 
 values will
 always compare false.
This is IEEE specification. There is no problem. T
If struc comparisions compare value by value, and both have Nan values in one member variable, then the two otherwise completely identical structs will always compare false even though they are identical. I think it would be best to have the ability to compare structs in two ways, one as struct equivalence, which would be the default method, the other as vale by value equivalence, which would have to be programmer defined through overload of == operator. --rt
I understand the problem, but it doesn't seem related to structs at all. Any two attempts to compare two default-valued floats will fail, irrespective of whether or not they're inside structs.
Oct 29 2012
parent reply "Rob T" <rob ucora.com> writes:
On Tuesday, 30 October 2012 at 02:27:30 UTC, Mehrdad wrote:
 I understand the problem, but it doesn't seem related to 
 structs at all.

 Any two attempts to compare two default-valued floats will 
 fail, irrespective of whether or not they're inside structs.
True at the level of float by float comparisons, but not necessarilly true when struct by struct bit pattern compares are done. My original understandiong of the struct type in D, is that it is defined as a POD which means == (without override) is done as a simple bit pattern compare, rather than doing a value by value compare of member data types. If this is the case, then two structs with default valued equivalent float types should compare equal, even though a value by value compare would compare not equal.
 TDPL clearly states that each of the struct's members are 
 supposed to
 be checked for equality (see section 7.1.5.2, p. 258 - 259).
So I guess that the POD definition of struct was changed at some point? If so, then how are value by value compares performed when unions are involved? What about when there are member pointers, and other structures that cannot be compared in a meaningful way by default? I guess the question is if the bit pattern comparision of structs has sufficient justification to be worth having as the default behaviour, or if there is more value attempting a value by value comparision, even though in many situations it may be pointless to attempt either strategy. In my experience, I cannot recall doing very many direct struct comparisons either as a complete value by value compare or as a full bit pattern compare, I just never found it to be all that useful, no matter, I can try and imagine both strategies being useful in some situations. With operator overloading you can have both strategies, but only if bit pattern compare is the default stategy, plus with overloading, compare can do exactly what you want to make sense out of unions and pointers, etc. So we should be good as is. I would expect that most times no one compares structs fully by value or by bit pattern anyway, to do so very often is difficult for me to imagine, but I could be wrong. --rt
Oct 30 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, October 30, 2012 08:14:59 Rob T wrote:
 TDPL clearly states that each of the struct's members are
 supposed to
 be checked for equality (see section 7.1.5.2, p. 258 - 259).
So I guess that the POD definition of struct was changed at some point?
Structs never were just PODs in D. They have _way_ more capabilities to them than that. If you want bitwise comparison, then use the is operator. That's what it's for. - Jonathan M Davis
Oct 30 2012
parent reply "Rob T" <rob ucora.com> writes:
On Tuesday, 30 October 2012 at 07:22:30 UTC, Jonathan M Davis 
wrote:
 On Tuesday, October 30, 2012 08:14:59 Rob T wrote:
 TDPL clearly states that each of the struct's members are
 supposed to
 be checked for equality (see section 7.1.5.2, p. 258 - 259).
So I guess that the POD definition of struct was changed at some point?
Structs never were just PODs in D. They have _way_ more capabilities to them than that.
I do understand what you are saying, however the docs in here describe structs as POD's, with the capabilities you mention. http://dlang.org/glossary.html#pod
 If you want bitwise comparison, then use the is operator. 
 That's what it's
 for.
Where can I find an up-to-date language reference? What I'm reading does not seem to be up to date or complete. For example, I never saw mention of the "is" operator until now. --rt
Oct 30 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, October 30, 2012 08:37:47 Rob T wrote:
 Where can I find an up-to-date language reference? What I'm
 reading does not seem to be up to date or complete. For example,
 I never saw mention of the "is" operator until now.
It's in the online docs: http://dlang.org/expression.html It's in the "Identity Expressions" section. The best reference is TDPL though. - Jonathan M Davis
Oct 30 2012
prev sibling parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
 Where can I find an up-to-date language reference? What I'm 
 reading does not seem to be up to date or complete. For 
 example, I never saw mention of the "is" operator until now.

 --rt
It's hard to find because it can not be overloaded. Look here: http://dlang.org/expression.html#IdentityExpression In TDPL it's explained as well.
Oct 30 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Oct 30, 2012 at 08:57:01AM +0100, Tobias Pankrath wrote:
Where can I find an up-to-date language reference? What I'm
reading does not seem to be up to date or complete. For example, I
never saw mention of the "is" operator until now.

--rt
It's hard to find because it can not be overloaded. Look here: http://dlang.org/expression.html#IdentityExpression In TDPL it's explained as well.
Sigh, one of these days I'm gonna have to rewrite many of these pages. I find them very hard to navigate and very unfriendly to newbies, because very basic information (like what 'is' is) is buried deep in long verbose infodumps of diverse language features, with no indication at all which are fundamental concepts and which are just details. It's virtually impossible to find what you're looking for unless you already know what it is. TDPL lays things out in a much saner fashion, but how many newbies actually own the book? We need the online docs to be just as newbie-friendly. T -- MSDOS = MicroSoft's Denial Of Service
Oct 30 2012
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
 Sigh, one of these days I'm gonna have to rewrite many of these 
 pages.
 I find them very hard to navigate and very unfriendly to 
 newbies,
 because very basic information (like what 'is' is) is buried 
 deep in
 long verbose infodumps of diverse language features, with no 
 indication
 at all which are fundamental concepts and which are just 
 details. It's
 virtually impossible to find what you're looking for unless you 
 already
 know what it is.

 TDPL lays things out in a much saner fashion, but how many 
 newbies
 actually own the book? We need the online docs to be just as
 newbie-friendly.
I agree, that the online docs are insufficient for learning the language. But that's the case for phobos, too. Both are just a listings of what is there and don't give you any overview of what design decisions were made and what implications they have. Just take a look std.container. I hope that Ali Çehreli efforts will be midterm solution at least for the language docs. Maybe he should credits by linking from the homepage to his book.
Oct 30 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-10-30 17:09, Tobias Pankrath wrote:

 I agree, that the online docs are insufficient for learning the
 language.
 But that's the case for phobos, too. Both are just a listings of
 what is there and don't give you any overview of what design
 decisions were made and what implications they have.

 Just take a look std.container.

 I hope that Ali Çehreli efforts will be midterm solution at
 least for the language docs. Maybe he should credits by linking
 from the homepage to his book.
A language needs several types of documentation. Reference documentation (basically what we have now), higher level documentation, tutorials and examples. -- /Jacob Carlborg
Oct 30 2012
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Oct 30, 2012 at 08:50:50PM +0100, Jacob Carlborg wrote:
 On 2012-10-30 17:09, Tobias Pankrath wrote:
 
I agree, that the online docs are insufficient for learning the
language.  But that's the case for phobos, too. Both are just a
listings of what is there and don't give you any overview of what
design decisions were made and what implications they have.

Just take a look std.container.

I hope that Ali ehreli efforts will be midterm solution at
least for the language docs. Maybe he should credits by linking
from the homepage to his book.
A language needs several types of documentation. Reference documentation (basically what we have now), higher level documentation, tutorials and examples.
[...] I contend that much of the current documentation isn't even up to reference standard. Incompleteness, for one thing. Things like Throwable and Exception aren't even documented right now (though this has been fixed in git HEAD). I'm sure there are many other fundamental holes. And a randomly-sorted list of unrelated module items does not constitute a reference, either. It has to be at least sorted alphabetically, or preferably, by logical categories. And things like class members need to be properly indented (I think this was fixed recently) instead of being flattened out, making it impossible to discern whether it belongs to the previous declaration or the global module scope. Moreover, nested classes/structs, etc., need to be put AFTER simpler members. It's basically unreadable when, for example, two int members are separated by the docs of a 2-page nested struct. And don't even get me started on navigability. Dumping a morass of modules NEED to have docs split into separate pages. A 10-page infodump of randomly sorted items is simply impossible to use effectively. Clickable identifiers would be nice, so that you don't have to separately navigate and lookup a particular symbol when you're not sure what it means, while trying to keep track of where you left off (and I thought we were in the age of automation...). T -- The right half of the brain controls the left half of the body. This means that only left-handed people are in their right mind. -- Manoj Srivastava
Oct 30 2012
prev sibling next sibling parent Jens Mueller <jens.k.mueller gmx.de> writes:
Jonathan M Davis wrote:
 On Friday, October 26, 2012 19:46:16 deadalnix wrote:
 Le 25/10/2012 04:12, Jonathan M Davis a =C3=A9crit :
 On Wednesday, October 24, 2012 13:31:14 Walter Bright wrote:
 The default compare for structs is a bit compare of the contents.
=20 Which definitely seems inherently broken. Doing that only works if the struct only contains integral types, character types, or bool. Nothing else will compare properly that way. It really needs to work like arr=
ays
 do (or are supposed to anyway) and compare each member according to =
=3D=3D
 and only fallback to an outright bitwise compare when it knows that t=
he
 results would be identical (i.e. because all of the members are integ=
ral
 types, character types, bool, or other structs which hold only integr=
al
 types, character types, or bool - be it directly or in other structs =
that
 they hold). Bitwise comparison is the is operator's job, not =3D=3D.
=20
 - Jonathan M Davis
=20 That will broke code. =20 But That is the way to go IMO. D needs to evolve to make things more consistent in general. =20 Still not doable without a proper versionning scheme.
=20 TDPL clearly states that each of the struct's members are supposed to be=
=20
 checked for equality (see section 7.1.5.2, p. 258 - 259). It's outright a=
bug=20
 for structs to be checked for equality with a bitwise comparison when the=
=20
 bitwise comparison does not do exactly what =3D=3D would have done had ea=
ch and=20
 every member variable been compared with =3D=3D. And as with all bugs, fi=
xing it=20
 could break code which depends on the buggy behavior. But given the natur=
e of=20
 this bug, I seriously question that much of anyone thought that the =3D=
=3D on=20
 structs was supposed to do anything other than what TDPL states that it s=
hould=20
 and that pretty much no one was expecting it to do a bitwise comparison. =
So,=20
 if anything, this will _fix_ far more code than it breaks.
I was looking for that section. 3789 is clearly a bug and should be fixed as soon as possible. Votes indicate how important a bug should be. But duplicates are also a good indicator. This bug has six duplicates. Jens
Oct 28 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-10-26 19:46, deadalnix wrote:

 That will broke code.

 But That is the way to go IMO. D needs to evolve to make things more
 consistent in general.

 Still not doable without a proper versionning scheme.
Fixing bugs can always break code and I don't think any version scheme can help here. But what a version scheme can help with is when changing the API. When you add a new function, that won't break any code. Removing a function will break code. -- /Jacob Carlborg
Oct 28 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 24, 2012 at 10:12:48PM -0400, Jonathan M Davis wrote:
 On Wednesday, October 24, 2012 13:31:14 Walter Bright wrote:
 The default compare for structs is a bit compare of the contents.
Which definitely seems inherently broken. Doing that only works if the struct only contains integral types, character types, or bool. Nothing else will compare properly that way. It really needs to work like arrays do (or are supposed to anyway) and compare each member according to == and only fallback to an outright bitwise compare when it knows that the results would be identical (i.e. because all of the members are integral types, character types, bool, or other structs which hold only integral types, character types, or bool - be it directly or in other structs that they hold). Bitwise comparison is the is operator's job, not ==.
[...] The built-in AA's suffer from the same problem. Which is why sometimes, if you use a struct as key, entries cannot be found because the key being looked up is bitwise different from any key in the AA, but they have the same value (e.g., the struct has a reference to two distinct objects that have the same value). T -- Food and laptops don't mix.
Oct 24 2012
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, October 24, 2012 22:12:48 Jonathan M Davis wrote:
 On Wednesday, October 24, 2012 13:31:14 Walter Bright wrote:
 The default compare for structs is a bit compare of the contents.
Which definitely seems inherently broken. Doing that only works if the struct only contains integral types, character types, or bool. Nothing else will compare properly that way.
Actually, slight correction. Pointers are fine too. I'd expect to have to overload opEquals to get deep comparisons for those (and I expect that the same happens with arrays), but basically anything which isn't an integral value of some kind (which pointers essentially are) won't compare properly if the default opEquals for structs is doing the same as the is operator like it is right now. - Jonathan M Davis
Oct 25 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 27, 2012 22:30:25 H. S. Teoh wrote:
 He who does not appreciate the beauty of language is not worthy to bemoan
 its flaws.
That presupposes that the language has any beauty to begin with. It could just be one big flaw. ;) - Jonathan M Davis
Oct 27 2012
parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sat, 27 Oct 2012 22:42:21 -0700
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 On Saturday, October 27, 2012 22:30:25 H. S. Teoh wrote:
 He who does not appreciate the beauty of language is not worthy to
 bemoan its flaws.
That presupposes that the language has any beauty to begin with. It could just be one big flaw. ;)
Did someone say "PHP"? ;)
Oct 28 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Oct 29, 2012 at 01:28:51AM -0400, Nick Sabalausky wrote:
 On Sat, 27 Oct 2012 22:42:21 -0700
 Jonathan M Davis <jmdavisProg gmx.com> wrote:
 
 On Saturday, October 27, 2012 22:30:25 H. S. Teoh wrote:
 He who does not appreciate the beauty of language is not worthy to
 bemoan its flaws.
That presupposes that the language has any beauty to begin with. It could just be one big flaw. ;)
Did someone say "PHP"? ;)
I thought I heard "Javascript"... :-P T -- In theory, there is no difference between theory and practice.
Oct 28 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 29 October 2012 at 05:43:43 UTC, H. S. Teoh wrote:
 On Mon, Oct 29, 2012 at 01:28:51AM -0400, Nick Sabalausky wrote:
 Did someone say "PHP"? ;)
I thought I heard "Javascript"... :-P
Both seem to have their own issues, although I'd say javascript is worse than PHP. (at least PHP runs on the server).
Oct 28 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-10-29 07:42, Era Scarecrow wrote:

   Both seem to have their own issues, although I'd say javascript is
 worse than PHP. (at least PHP runs on the server).
You can run JavaScript on the server too. -- /Jacob Carlborg
Oct 29 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Oct 27, 2012 at 10:42:21PM -0700, Jonathan M Davis wrote:
 On Saturday, October 27, 2012 22:30:25 H. S. Teoh wrote:
 He who does not appreciate the beauty of language is not worthy to
 bemoan its flaws.
That presupposes that the language has any beauty to begin with. It could just be one big flaw. ;)
[...] Wait, are you saying that D is one big flaw? ;-) T -- Ph.D. = Permanent head Damage
Oct 28 2012