digitalmars.D - opEquals(const ref yadaYada)
- dsimcha <dsimcha yahoo.com> Dec 12 2009
- Richard Webb <webby beardmouse.org.uk> Dec 12 2009
- Steven Schveighoffer <schveiguy yahoo.com> Dec 13 2009
- lws <invalid email.com> Dec 14 2009
- lws <invalid email.com> Dec 14 2009
- dsimcha <dsimcha yahoo.com> Dec 14 2009
- lws <invalid email.com> Dec 14 2009
- dsimcha <dsimcha yahoo.com> Dec 14 2009
- Sergey Gromov <snake.scaly gmail.com> Dec 15 2009
- lws <invalid email.com> Dec 14 2009
- lws <invalid email.com> Dec 14 2009
- "Steven Schveighoffer" <schveiguy yahoo.com> Dec 15 2009
- "Simen kjaeraas" <simen.kjaras gmail.com> Dec 15 2009
- "Steven Schveighoffer" <schveiguy yahoo.com> Dec 15 2009
- Leandro Lucarella <llucax gmail.com> Dec 14 2009
- Leandro Lucarella <llucax gmail.com> Dec 14 2009
I've noticed that, for DMD 2.037, we've started mandating that the input
parameter for struct opEquals be const ref T. This seemed like a good idea
initially, but it creates the horribly leaky abstraction that the right-hand
argument to opEquals can't be an rvalue. Example:
struct Foo {
bool opEquals(const ref Foo rhs) const { // Only signature
// that compiles.
return true;
}
}
Foo getFoo() {
return Foo();
}
void main() {
Foo foo = getFoo();
bool isEqual = foo == getFoo();
}
Error: Foo.opEquals type signature should be const bool(ref const(Foo)) not
const bool(Foo rhs)
Will this be getting fixed witht he new operator overloading?
Dec 12 2009
Hi, I mentioned this problem in the thread http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=18405 I ran into the rvalue problem while trying to get Juno to compile, and found that it builds ok if you declare both bool opEquals(const ref Foo rhs) const and bool opEquals(Foo rhs) const
Dec 12 2009
Richard Webb Wrote:Hi, I mentioned this problem in the thread http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=18405 I ran into the rvalue problem while trying to get Juno to compile, and found that it builds ok if you declare both bool opEquals(const ref Foo rhs) const and bool opEquals(Foo rhs) const
Note the resulting bug: http://d.puremagic.com/issues/show_bug.cgi?id=3607 I also don't believe Richard's workaround is a "solution". The compiler should not force you to create a const ref version if the argument can be implicitly cast from const to mutable. -Steve
Dec 13 2009
On 2009-12-13 04:29:28 -0800, Steven Schveighoffer <schveiguy yahoo.com> said:Richard Webb Wrote:Hi, I mentioned this problem in the thread http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=18405
Iran into the rvalue problem while trying to get Juno to compile, and found that it builds ok if you declare both bool opEquals(const ref Foo rhs) const and bool opEquals(Foo rhs) const
Note the resulting bug: http://d.puremagic.com/issues/show_bug.cgi?id=3607 I also don't believe Richard's workaround is a "solution". The compiler should not force you to create a const ref version if the argument can be implicitly cast from const to mutable. -Steve
I don't know if I buy that the opEquals thing is a bug. However, that const destructor thing in the other thread needs to be fixed. //////////////////////////////// struct Foo { ~this() { } } void Bar() { const Foo f; } //////////////////////////////// Definitely produces incorrect behavior.
Dec 14 2009
I don't know if I believe this is necesarrily bad. It's revealing some
bad coding on your part.
You shouldn't be doing opEquals with an rvalue of a class. Make
getFoo return a reference.
ref Foo getFoo() {} fixes the problem and avoids value-copying for no
reason to an rvalue that's going to get garbage collected.
-lws
On 2009-12-12 07:14:50 -0800, dsimcha <dsimcha yahoo.com> said:
I've noticed that, for DMD 2.037, we've started mandating that the input
parameter for struct opEquals be const ref T. This seemed like a good idea
initially, but it creates the horribly leaky abstraction that the right-hand
argument to opEquals can't be an rvalue. Example:
struct Foo {
bool opEquals(const ref Foo rhs) const { // Only signature
// that compiles.
return true;
}
}
Foo getFoo() {
return Foo();
}
void main() {
Foo foo = getFoo();
bool isEqual = foo == getFoo();
}
Error: Foo.opEquals type signature should be const bool(ref const(Foo)) not
const bool(Foo rhs)
Will this be getting fixed witht he new operator overloading?
Dec 14 2009
== Quote from lws (invalid email.com)'s articleI don't know if I believe this is necesarrily bad. It's revealing some bad coding on your part. You shouldn't be doing opEquals with an rvalue of a class. Make getFoo return a reference. ref Foo getFoo() {} fixes the problem and avoids value-copying for no reason to an rvalue that's going to get garbage collected.
1. This was in DFL's code, not stuff I wrote. 2. It was a small struct that was cheap to copy, not a class. 3. At any rate, the inconsistency with builtins is inexcusable.
Dec 14 2009
On 2009-12-14 07:01:47 -0800, dsimcha <dsimcha yahoo.com> said:== Quote from lws (invalid email.com)'s articleI don't know if I believe this is necesarrily bad. It's revealing some bad coding on your part. You shouldn't be doing opEquals with an rvalue of a class. Make getFoo return a reference. ref Foo getFoo() {} fixes the problem and avoids value-copying for no reason to an rvalue that's going to get garbage collected.
1. This was in DFL's code, not stuff I wrote. 2. It was a small struct that was cheap to copy, not a class. 3. At any rate, the inconsistency with builtins is inexcusable.
1. Well, stuff like this is good warning to whomever about the code. Since D is a imperative language, it should at least give you a warning when you're doing something really inefficient that has a boilerplate way of accomplishing it that is much faster. 2. That's odd. structs DO have stack scope in D. Right? It shouldn't even warn in that case. IMHO. 3. For classes, it is consistent with the whole point of the new const stuff and the GC, and the fact that they are heap objects by definition. Classes have always been treated "differently." And I think it's good. Walter has enabled a lot of expressiveness with the syntax in D when compared to C++, and it allows nice warnings when you're doing things you probably shouldn't. Unfortunately, this isn't an error.... Maybe for some reason you REALLY want to be copying around structs and classes.
Dec 14 2009
== Quote from lws (invalid email.com)'s articleOn 2009-12-14 07:01:47 -0800, dsimcha <dsimcha yahoo.com> said:== Quote from lws (invalid email.com)'s articleI don't know if I believe this is necesarrily bad. It's revealing some bad coding on your part. You shouldn't be doing opEquals with an rvalue of a class. Make getFoo return a reference. ref Foo getFoo() {} fixes the problem and avoids value-copying for no reason to an rvalue that's going to get garbage collected.
1. This was in DFL's code, not stuff I wrote. 2. It was a small struct that was cheap to copy, not a class. 3. At any rate, the inconsistency with builtins is inexcusable.
Since D is a imperative language, it should at least give you a warning when you're doing something really inefficient that has a boilerplate way of accomplishing it that is much faster.
Right, but only if this warning doesn't have too many false positives that are just annoying when the programmer **does** know what he/she is doing. In this case, passing small structs by value isn't inefficient.2. That's odd. structs DO have stack scope in D. Right? It shouldn't even warn in that case. IMHO.
That's my whole point. The behavior is a bug, not a feature.3. For classes, it is consistent with the whole point of the new const stuff and the GC, and the fact that they are heap objects by definition. Classes have always been treated "differently." And I think it's good. Walter has enabled a lot of expressiveness with the syntax in D when compared to C++, and it allows nice warnings when you're doing things you probably shouldn't. Unfortunately, this isn't an error.... Maybe for some reason you REALLY want to be copying around structs and classes.
Maybe what we need is for it to be legal to pass rvalues to functions that expect const ref params. If it's an rvalue, just place it on the caller's stack frame implicitly and be done with it.
Dec 14 2009
Simen kjaeraas wrote:Steven Schveighoffer <schveiguy yahoo.com> wrote:On Mon, 14 Dec 2009 11:44:18 -0500, lws <invalid email.com> wrote:On 2009-12-14 07:01:47 -0800, dsimcha <dsimcha yahoo.com> said: 1. Well, stuff like this is good warning to whomever about the code. Since D is a imperative language, it should at least give you a warning when you're doing something really inefficient that has a boilerplate way of accomplishing it that is much faster.
It's not faster, it's slower. Passing a reference to an integer or smaller value type is not as efficient passing the value type itself.
This is hardly true on modern architectures. I don't have the numbers on it, but even for ints and floats, ref is just as fast (and sometimes faster).
To return a reference you must allocate the value. And to use the value you must dereference the reference. All this takes cycles no matter how modern your architecture is.
Dec 15 2009
Unless I'm confused, classses are ALWAYS heap (unless explicitely scoped) objects in D. The garbage collector is the one that is tasked with reclaiming their memory and calling their deconstructor. If you want the semantics you're talking about Foo would need to be a "scoped Foo foo = new Foo();" I could be wrong, I haven't had a change to touch D in about a year though, some stuff could have changed. (And please don't top quote, argh! ;)) -SC On 2009-12-14 05:47:44 -0800, Leandro Lucarella <llucax gmail.com> said:lws, el 14 de diciembre a las 01:06 me escribiste:I don't know if I believe this is necesarrily bad. It's revealing some bad coding on your part. You shouldn't be doing opEquals with an rvalue of a class. Make getFoo return a reference. ref Foo getFoo() {} fixes the problem and avoids value-copying for no reason to an rvalue that's going to get garbage collected.
If you are using "garbage collected" as a general term to denote "automatic memory reclamation", you are right, but the garbage collector have nothing to do with rvalues, they are allocated in the stack, and they will be "garbage collected" by the compiler when unwinding the stack, not the GC. I don't know if this is relevant to the discussion, I'm clarifying, just in case :)On 2009-12-12 07:14:50 -0800, dsimcha <dsimcha yahoo.com> said:I've noticed that, for DMD 2.037, we've started mandating that the input parameter for struct opEquals be const ref T. This seemed like a good idea initially, but it creates the horribly leaky abstraction that the right-hand argument to opEquals can't be an rvalue. Example: struct Foo { bool opEquals(const ref Foo rhs) const { // Only signature // that compiles. return true; } } Foo getFoo() { return Foo(); } void main() { Foo foo = getFoo(); bool isEqual = foo == getFoo(); } Error: Foo.opEquals type signature should be const bool(ref const(Foo)) not const bool(Foo rhs) Will this be getting fixed witht he new operator overloading?
Dec 14 2009
On 2009-12-14 11:04:53 -0800, Leandro Lucarella <llucax gmail.com> said:lws, el 14 de diciembre a las 08:31 me escribiste:Unless I'm confused, classses are ALWAYS heap (unless explicitely scoped) objects in D.
Yes, and classes are always references too. But that's not even the point, the point is, the example was a struct :)
Even if they are always references, they behave as pass-by-value types. Also, excuse me I read struct as class for some reason earlier. (*doh!*) This error-that-should-be-warning is for both types though.struct Foo { bool opEquals(const ref Foo rhs) const { // Only signature // that compiles. return true; } } Foo getFoo() { return Foo(); } void main() { Foo foo = getFoo(); bool isEqual = foo == getFoo(); } Error: Foo.opEquals type signature should be const bool(ref const(Foo)) not const bool(Foo rhs) Will this be getting fixed witht he new operator overloading?
[snip](And please don't top quote, argh! ;))
!!!
Dec 14 2009
On Mon, 14 Dec 2009 11:44:18 -0500, lws <invalid email.com> wrote:On 2009-12-14 07:01:47 -0800, dsimcha <dsimcha yahoo.com> said:== Quote from lws (invalid email.com)'s articleI don't know if I believe this is necesarrily bad. It's revealing some bad coding on your part. You shouldn't be doing opEquals with an rvalue of a class. Make getFoo return a reference. ref Foo getFoo() {} fixes the problem and avoids value-copying for no reason to an rvalue that's going to get garbage collected.
2. It was a small struct that was cheap to copy, not a class. 3. At any rate, the inconsistency with builtins is inexcusable.
1. Well, stuff like this is good warning to whomever about the code. Since D is a imperative language, it should at least give you a warning when you're doing something really inefficient that has a boilerplate way of accomplishing it that is much faster.
It's not faster, it's slower. Passing a reference to an integer or smaller value type is not as efficient passing the value type itself.2. That's odd. structs DO have stack scope in D. Right? It shouldn't even warn in that case. IMHO.
The issue is that the compiler is incorrectly assuming that it *must* use a const ref form of opEquals for a member when composing an opEquals function for a struct that doesn't provide one. To this end, it always ensures any overload set of opEquals has a const ref form. The premise that const ref is always required is false in some cases, and this is the bug.3. For classes, it is consistent with the whole point of the new const stuff and the GC, and the fact that they are heap objects by definition. Classes have always been treated "differently." And I think it's good. Walter has enabled a lot of expressiveness with the syntax in D when compared to C++, and it allows nice warnings when you're doing things you probably shouldn't.
Classes should be allowed to be passed as const only, no ref. Passing a reference to a class makes no sense since they are references already (Even scoped class variables are references). In fact, const ref makes absolutely no sense for a class, ever.Unfortunately, this isn't an error.... Maybe for some reason you REALLY want to be copying around structs and classes.
It is an error, not a warning. The following opEquals functions should always compile: struct S1 { int x; bool opEquals(S1 s) const { return true; } } struct S2 { int *x; bool opEquals(const S2 s) const { return true; } } The following should not necessarily compile: struct Sbad { int *x; bool opEquals(Sbad s) const { return true; } } -Steve
Dec 15 2009
Steven Schveighoffer <schveiguy yahoo.com> wrote:On Mon, 14 Dec 2009 11:44:18 -0500, lws <invalid email.com> wrote:On 2009-12-14 07:01:47 -0800, dsimcha <dsimcha yahoo.com> said: 1. Well, stuff like this is good warning to whomever about the code. Since D is a imperative language, it should at least give you a warning when you're doing something really inefficient that has a boilerplate way of accomplishing it that is much faster.
It's not faster, it's slower. Passing a reference to an integer or smaller value type is not as efficient passing the value type itself.
This is hardly true on modern architectures. I don't have the numbers on it, but even for ints and floats, ref is just as fast (and sometimes faster). -- Simen
Dec 15 2009
On Tue, 15 Dec 2009 18:41:30 -0500, Simen kjaeraas <simen.kjaras gmail.com> wrote:Steven Schveighoffer <schveiguy yahoo.com> wrote:On Mon, 14 Dec 2009 11:44:18 -0500, lws <invalid email.com> wrote:On 2009-12-14 07:01:47 -0800, dsimcha <dsimcha yahoo.com> said: 1. Well, stuff like this is good warning to whomever about the code. Since D is a imperative language, it should at least give you a warning when you're doing something really inefficient that has a boilerplate way of accomplishing it that is much faster.
It's not faster, it's slower. Passing a reference to an integer or smaller value type is not as efficient passing the value type itself.
This is hardly true on modern architectures. I don't have the numbers on it, but even for ints and floats, ref is just as fast (and sometimes faster).
I don't see how this is possible. It's a double-indirection vs. a single indirection when you look at the value. Yes, it might be inlined, making the lookup just as fast as if it were a stack variable, but I don't see how it could be faster. I guess it may be faster if you don't actually use the value in the function. Besides that point, passing ints or floats by value is not "something really inefficient" that should be considered a compiler error. -Steve
Dec 15 2009
lws, el 14 de diciembre a las 01:06 me escribiste:I don't know if I believe this is necesarrily bad. It's revealing some bad coding on your part. You shouldn't be doing opEquals with an rvalue of a class. Make getFoo return a reference. ref Foo getFoo() {} fixes the problem and avoids value-copying for no reason to an rvalue that's going to get garbage collected.
If you are using "garbage collected" as a general term to denote "automatic memory reclamation", you are right, but the garbage collector have nothing to do with rvalues, they are allocated in the stack, and they will be "garbage collected" by the compiler when unwinding the stack, not the GC. I don't know if this is relevant to the discussion, I'm clarifying, just in case :)On 2009-12-12 07:14:50 -0800, dsimcha <dsimcha yahoo.com> said:I've noticed that, for DMD 2.037, we've started mandating that the input parameter for struct opEquals be const ref T. This seemed like a good idea initially, but it creates the horribly leaky abstraction that the right-hand argument to opEquals can't be an rvalue. Example: struct Foo { bool opEquals(const ref Foo rhs) const { // Only signature // that compiles. return true; } } Foo getFoo() { return Foo(); } void main() { Foo foo = getFoo(); bool isEqual = foo == getFoo(); } Error: Foo.opEquals type signature should be const bool(ref const(Foo)) not const bool(Foo rhs) Will this be getting fixed witht he new operator overloading?
-- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- I would drape myself in velvet if it were socially acceptable. -- George Constanza
Dec 14 2009
lws, el 14 de diciembre a las 08:31 me escribiste:Unless I'm confused, classses are ALWAYS heap (unless explicitely scoped) objects in D.
Yes, and classes are always references too. But that's not even the point, the point is, the example was a struct :)struct Foo { bool opEquals(const ref Foo rhs) const { // Only signature // that compiles. return true; } } Foo getFoo() { return Foo(); } void main() { Foo foo = getFoo(); bool isEqual = foo == getFoo(); } Error: Foo.opEquals type signature should be const bool(ref const(Foo)) not const bool(Foo rhs) Will this be getting fixed witht he new operator overloading?
[snip](And please don't top quote, argh! ;))
!!! -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Every day 21 new born babies will be given to the wrong parents
Dec 14 2009









lws <invalid email.com> 