www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Pointers vs. References

reply Michael Neumann <mneumann ntecs.de> writes:
Hi,

What I find confusing in D is the difference between references and 
pointers. References server somehow the same purpose.
What are the impacts on using references instead of pointers? (e.g. 
Neuron instead of Neuron*). Is there some GC magic involved for 
references? I've ported a pulsed neuronal network simulator from C++ to 
see how it behaves performance wise in D, but there must be really 
something wrong in D (or in my implementation), as it's at least 4x 
slower (and when the datasets grow, it takes infinitively long time).

And I guess I also found a bug in gdc:

Synapse x = ...;
while (x != null)
{
}

This segfaults, while:

Synapse x = ...
while (!(x is null))
{
}

does not.

Best regards,

   Michael
Jun 13 2007
next sibling parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
Michael Neumann wrote:
 Synapse x = ...;
 while (x != null)
 {
 }
 
 This segfaults, while:
 
 Synapse x = ...
 while (!(x is null))
 {
 }
 
 does not.
That's not a bug. '==' and '!=' result in a call to opEquals, which is likely to segfault when one of the operands is null. You should use 'is' or in your case '!is'. while (x !is null) { } As for your question about references. A reference is basically the same as a pointer, so there should be no performance difference between the two. Without more details, it's hard to say what could be the reason behind the bad performance. L.
Jun 13 2007
next sibling parent reply Dan <murpsoft hotmail.com> writes:
Lionello Lunesu Wrote:

 Michael Neumann wrote:
 Synapse x = ...;
 while (x != null)
 {
 }
 
 This segfaults, while:
 
 Synapse x = ...
 while (!(x is null))
 {
 }
 
 does not.
That's not a bug. '==' and '!=' result in a call to opEquals, which is likely to segfault when one of the operands is null. You should use 'is' or in your case '!is'. while (x !is null) { } As for your question about references. A reference is basically the same as a pointer, so there should be no performance difference between the two. Without more details, it's hard to say what could be the reason behind the bad performance. L.
Heh... using classes in any language will cut your performance compared to using structs. D has nice structs. References are pointers to pointers to something; not "the same". Also, using while(x !is null) after explicitly defining it is usually wrong; you usually want do { ... } while(x !is null); That's all I can gather though from your vague post.
Jun 13 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
 As for your question about references. A reference is basically the same 
 as a pointer, so there should be no performance difference between the 
 two. Without more details, it's hard to say what could be the reason 
 behind the bad performance.

 L.
Heh... using classes in any language will cut your performance compared to using structs. D has nice structs. References are pointers to pointers to something; not "the same". Also, using while(x !is null) after explicitly defining it is usually wrong; you usually want do { ... } while(x !is null); That's all I can gather though from your vague post.
Odd; last time I looked at disassembled machine code that used references, they sure as hell looked like pointers... -- Daniel
Jun 13 2007
parent BCS <BCS pathlink.com> writes:
Daniel Keep wrote:
As for your question about references. A reference is basically the same 
as a pointer, so there should be no performance difference between the 
two. Without more details, it's hard to say what could be the reason 
behind the bad performance.

L.
Heh... using classes in any language will cut your performance compared to using structs. D has nice structs. References are pointers to pointers to something; not "the same". Also, using while(x !is null) after explicitly defining it is usually wrong; you usually want do { ... } while(x !is null); That's all I can gather though from your vague post.
Odd; last time I looked at disassembled machine code that used references, they sure as hell looked like pointers... -- Daniel
class Foo { } Foo ref; // reference (pointer) to object Foo* ptr; // pointer to reference (pointer) to object The point that should be remembered is that objects already have reference semantics and classType* is almost never of any use.
Jun 13 2007
prev sibling parent Michael Neumann <mneumann ntecs.de> writes:
Dan wrote:
 Lionello Lunesu Wrote:
 
 Michael Neumann wrote:
 Synapse x = ...;
 while (x != null)
 {
 }

 This segfaults, while:

 Synapse x = ...
 while (!(x is null))
 {
 }

 does not.
That's not a bug. '==' and '!=' result in a call to opEquals, which is likely to segfault when one of the operands is null. You should use 'is' or in your case '!is'. while (x !is null) { } As for your question about references. A reference is basically the same as a pointer, so there should be no performance difference between the two. Without more details, it's hard to say what could be the reason behind the bad performance. L.
Heh... using classes in any language will cut your performance compared to using structs. D has nice structs. References are pointers to pointers to something; not "the same". Also, using while(x !is null) after explicitly defining it is usually wrong; you usually want do { ... } while(x !is null); That's all I can gather though from your vague post.
Thanks for all your answers. Well, the C++ version of course uses classes as well. It's a literal translation from C++ to D. For those interested, the source is available via my mercurial repository at: http://ntecs.de/hg-projects/inspire/ (branch "d"). hg clone static-http://ntecs.de/hg-projects/inspire/ cd inspire hg update -C d Regards, Michael
Jun 13 2007
prev sibling next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Lionello Lunesu wrote:
 Michael Neumann wrote:
 Synapse x = ...;
 while (x != null)
 {
 }

 This segfaults, while:

 Synapse x = ...
 while (!(x is null))
 {
 }

 does not.
That's not a bug. '==' and '!=' result in a call to opEquals, which is likely to segfault when one of the operands is null. You should use 'is' or in your case '!is'. while (x !is null) { } As for your question about references. A reference is basically the same as a pointer, so there should be no performance difference between the two. Without more details, it's hard to say what could be the reason behind the bad performance. L.
This issue comes up frequently enough that I'm starting to think "check against null literal" should maybe be special cased. It even bites me from time to time and I know what I'm supposed to do. --bb
Jun 13 2007
prev sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
Lionello Lunesu escribió:
 That's not a bug.
 '==' and '!=' result in a call to opEquals, which is likely to segfault 
 when one of the operands is null. You should use 'is' or in your case 
 '!is'.
Can't writing x == null, x != null be rewritten by the compiler to x is null, x !is null ? I think the two firsts will always segfault. When would a user want to segfault her program? Or, better asked, when would a user want to do x == null? Regards, Ary
Jun 13 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Ary Manzana" <ary esperanto.org.ar> wrote in message 
news:f4ombu$16mp$1 digitalmars.com...
 Can't writing

 x == null, x != null

 be rewritten by the compiler to

 x is null, x !is null

 ?


 I think the two firsts will always segfault. When would a user want to 
 segfault her program? Or, better asked, when would a user want to do x == 
 null?
I don't think the compiler should rewrite it, but I don't think it should be allowed either. Either make it a warning or an error to ==/!= to null.
Jun 13 2007
parent reply Georg Wrede <georg nospam.org> writes:
Jarrett Billingsley wrote:
 "Ary Manzana" <ary esperanto.org.ar> wrote in message 
 news:f4ombu$16mp$1 digitalmars.com...
 
Can't writing

x == null, x != null

be rewritten by the compiler to

x is null, x !is null

?


I think the two firsts will always segfault. When would a user want to 
segfault her program? Or, better asked, when would a user want to do x == 
null?
I don't think the compiler should rewrite it, but I don't think it should be allowed either. Either make it a warning or an error to ==/!= to null.
Count me in. While I'd prefer to use x == null, I can understand that it may be bad from a language design point. It would create an anomaly (because it artificially avoids calling a member function) which is misleading and requires one to remember it when reasoning about the language. So, instead, it should not be allowed. It should be an error. It is a construct the programmer didn't intend to write. :-) And which will bite him, period.
Jun 13 2007
parent reply OF <dummy nospam.org> writes:
Georg Wrede Wrote:
 Jarrett Billingsley wrote:
 "Ary Manzana" <ary esperanto.org.ar> wrote in message 

 I don't think the compiler should rewrite it, but I don't think it should be 
 allowed either.  Either make it a warning or an error to ==/!= to null. 
Count me in.
Count me in too. I've had problems with this. At least a warning would be nice.
Jun 13 2007
parent reply Extrawurst <spam extrawurst.org> writes:
OF schrieb:
 Georg Wrede Wrote:
 Jarrett Billingsley wrote:
 "Ary Manzana" <ary esperanto.org.ar> wrote in message 

 I don't think the compiler should rewrite it, but I don't think it should be 
 allowed either.  Either make it a warning or an error to ==/!= to null. 
Count me in.
Count me in too. I've had problems with this. At least a warning would be nice.
definitely ! i ran into this very often and i know many D beginners who do. a warning cant hurt
Jun 13 2007
parent reply Georg Wrede <georg nospam.org> writes:
Extrawurst wrote:
 OF schrieb:
 Georg Wrede Wrote:
 Jarrett Billingsley wrote:
 "Ary Manzana" wrote
 I don't think the compiler should rewrite it, but I don't think it 
 should be allowed either.  Either make it a warning or an error to 
 ==/!= to null. 
Count me in.
Count me in too. I've had problems with this. At least a warning would be nice.
definitely ! i ran into this very often and i know many D beginners who do. a warning cant hurt
Actually, why do we use the foo !is null idiom at all? (Or try to use the foo != null idiom?) The following works as expected: import std.stdio; void main() { Object o = new Object; // while(o !is null) while(o) { writefln("Yee."); o = null; } Object o2; while(!o2) { writefln("Haw."); o2 = new Object; } } The expected output being: Yee. Haw. Embarrassingly, I don't seem to remember if there was a historical reason for not (at some time?) using "while(o)". Anyhow, this would seem to be the canonical way to do it in a C family language in the first place. So maybe we should (of course first mark o==null as an error, and then) amend the documentation to suggest o itself as the Politically Correct test for nullness. Finally, the *error message* should suggest o itself for the test.
Jun 13 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Georg Wrede" <georg nospam.org> wrote in message 
news:467045F1.6030603 nospam.org...
 Actually, why do we use the foo !is null idiom at all? (Or try to use the 
 foo != null idiom?)

 Anyhow, this would seem to be the canonical way to do it in a C family 
 language in the first place. So maybe we should (of course first mark 
 o==null as an error, and then) amend the documentation to suggest o itself 
 as the Politically Correct test for nullness.
Except there's one tiny inconsistency in the language. assert(o); This stupidly does not check that o is non-null; instead it runs the object's invariants. Which, if o really _is_ null, will cause an access violation. Whee. In this case, you have to write: assert(o !is null); Other syntaxes to run the invariant, such as "o.invariant()" or "o.assert()" have been proposed, but as usual nothing has come of it.
Jun 13 2007
next sibling parent Georg Wrede <georg nospam.org> writes:
Jarrett Billingsley wrote:
 "Georg Wrede" <georg nospam.org> wrote 
 
Actually, why do we use the foo !is null idiom at all? (Or try to use the 
foo != null idiom?)

Anyhow, this would seem to be the canonical way to do it in a C family 
language in the first place. So maybe we should (of course first mark 
o==null as an error, and then) amend the documentation to suggest o itself 
as the Politically Correct test for nullness.
Except there's one tiny inconsistency in the language. assert(o); This stupidly does not check that o is non-null; instead it runs the object's invariants. Which, if o really _is_ null, will cause an access violation. Whee.
Geez!!! There better be a seriously solid reason for it!
 In this case, you have to write:
 
 assert(o !is null);
 
 Other syntaxes to run the invariant, such as "o.invariant()" or "o.assert()" 
 have been proposed, but as usual nothing has come of it. 
An assert test is not the place to gratuituously save a few keystrokes! If anywhere, here clarity of expression and consistency are simply essential. If a programmer wants to assert there is an o, the first thing he'd do (unless too familiar with the above, er, interesting properties of D) is write assert(o); If a programmer wants to assert that the o object is happy and feels well, then we should have him write it explicitly. Dammit! assert(o.invariant()); or assert(o.assert()); or even assert(o.thisObjectIsHappy()); Making shortcuts (and saving keystrokes) _in the wrong place_ has historically led to grievances and wasted productivity few of us can fathom. Don't let this be another example. --- (Getting my adrenaline up here...) If there *ever* was a place where obscurity, short cuts, the unexpected, or inconsistency, are NOT welcome, it is debugging related code. For chrissake! And anybody who finds himself needing to write "assert(o&&o.assert());" five times a day, might consider putting this in F1 as an editor macro. --- After a cigarrette on the balcony, and proofreading, I got to the notion that the current behavior is trying to kill two flies in one stroke. assert(o) wants to give an access violation if o doesn't exist, and an assert failed if the object was unhappy. Well, I'm sorry but that's not good enough. As if what I've written above isn't enough, there's one more thing: testing whether we have an object at all, and testing whether it is debugging is, one step at a time. Still insist on testing both? Write two lines! Hey, _both_ your boss, and you yourself, should be able to understand the code (including the debugging statements) even after the Summer vacation.
Jun 13 2007
prev sibling parent "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Wed, 13 Jun 2007 23:32:10 +0300, Jarrett Billingsley  
<kb3ctd2 yahoo.com> wrote:
<snip>
 assert(o);

 This stupidly does not check that o is non-null; instead it runs the
 object's invariants.  Which, if o really _is_ null, will cause an access
 violation.  Whee.

 In this case, you have to write:

 assert(o !is null);

 Other syntaxes to run the invariant, such as "o.invariant()" or  
 "o.assert()"
 have been proposed, but as usual nothing has come of it.
I think this deserves its own thread, again. ;) So, I have created one: "Suggestion: "fix" assert(obj)"
Jun 14 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Ary Manzana wrote:
 Lionello Lunesu escribió:
 That's not a bug.
 '==' and '!=' result in a call to opEquals, which is likely to 
 segfault when one of the operands is null. You should use 'is' or in 
 your case '!is'.
Can't writing x == null, x != null be rewritten by the compiler to x is null, x !is null ? I think the two firsts will always segfault. When would a user want to segfault her program? Or, better asked, when would a user want to do x == null? Regards, Ary
Why not have the compiler just rewrite all equality comparisons on class objects? x == y ===> (x is y || x.opEquals(y)) I mean you might as well check first that they aren't the same object, because if they are then obviously they are equal too[1]. That would make the behavior the norm and not a special case. I don't see how doing one extra pointer comparison is going to significantly affect performance. But then I guess there's that bizzarro-business about opEquals returning an int because that's "more efficient". So I guess someone is hypersensitive about object equality operations being as fast as possible. --bb [1] Unless you're trying to implement some weirdo NaN like object which is not equal to anything, including itself.
Jun 13 2007
parent reply Myron Alexander <someone somewhere.com> writes:
Bill Baxter wrote:
 
    x == y    ===>    (x is y || x.opEquals(y))
 
I prefer that the compiler does not rewrite my code. There is nothing wrong with the current syntax, it's just different from what most people here are used to. If Walter changed '==' to be a reference check, then it would mean '==' works differently for different types. That inconsistency would kick up a hurricane - precisely what happened in Java. D does get this one right but a warning would be nice. Regards, Myron.
Jun 13 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Myron Alexander wrote:
 Bill Baxter wrote:
    x == y    ===>    (x is y || x.opEquals(y))
I prefer that the compiler does not rewrite my code. There is nothing wrong with the current syntax, it's just different from what most people here are used to. If Walter changed '==' to be a reference check, then it would mean '==' works differently for different types. That inconsistency would kick up a hurricane - precisely what happened in Java. D does get this one right but a warning would be nice.
But '==' *does* work differently for different types. Already. Anyway, yeh, I'd be happy with a warning (or an error really -- unless someone can think of a case where you really _want_ to crash your program like that). --bb
Jun 13 2007
parent reply Myron Alexander <someone somewhere.com> writes:
Bill Baxter wrote:
 But '==' *does* work differently for different types.  Already.
Sorry. What I meant is that is has the same semantics. When you see ==, you can be sure that it means "check if value is the same".
Jun 14 2007
parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Myron Alexander skrev:
 Bill Baxter wrote:
 But '==' *does* work differently for different types.  Already.
Sorry. What I meant is that is has the same semantics. When you see ==, you can be sure that it means "check if value is the same".
One could argue that = should be analogous to ==. I.e, if = assigns references, == should compare references. I am not arguing either way. :) /Oskar
Jun 14 2007
parent Regan Heath <regan netmail.co.nz> writes:
Oskar Linde Wrote:
 Myron Alexander skrev:
 Bill Baxter wrote:
 But '==' *does* work differently for different types.  Already.
Sorry. What I meant is that is has the same semantics. When you see ==, you can be sure that it means "check if value is the same".
One could argue that = should be analogous to ==. I.e, if = assigns references, == should compare references. I am not arguing either way. :)
One could also argue that the value of a class reference is the memory address of the class to which it refers, as is the case with pointers. struct A{} A* p; A* s; if (s == p) //compares address pointer 'points' at Regan
Jun 14 2007
prev sibling next sibling parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Wed, 13 Jun 2007 10:09:24 +0300, Michael Neumann <mneumann ntecs.de> =
 =

wrote:
<snip>
 ..., but there must be really something wrong in D (or in my  =
 implementation), as it's at least 4x slower (and when the datasets gro=
w, =
 it takes infinitively long time).
<snip> Well, one thing that comes to mind is that allocating memory from the he= ap = is *slow* (in any programming language I guess). If you do that (i.e. heap allocation) inside a loop, a program will = probably get slower and slower, nonlinearly, when the loop count increas= es = (I recently noticed that in a (C++) project of mine). For example, if yo= u = have something like this in C++: void foo() { MyClass myclass; ... } void bar() { int i; for(i =3D 0; i < 1000000; i++) foo(); } , then you should use the 'scope' keyword in 'foo()' when programmin in = D: void foo() { scope MyClass myclass =3D new MyClass; //(or just plain "scope myc= lass = =3D new MyClass;") } This way 'myclass' is allocated from the stack instead of the heap. I hope this will help (that is, if you hadn't used 'scope' (in similar = cases), of course).
Jun 14 2007
parent Michael Neumann <mneumann ntecs.de> writes:
Kristian Kilpi wrote:
 On Wed, 13 Jun 2007 10:09:24 +0300, Michael Neumann <mneumann ntecs.de> 
 wrote:
 <snip>
 ..., but there must be really something wrong in D (or in my 
 implementation), as it's at least 4x slower (and when the datasets 
 grow, it takes infinitively long time).
<snip> Well, one thing that comes to mind is that allocating memory from the heap is *slow* (in any programming language I guess).
Thanks. Yeah, I know! That's why I'm using a free-list in my program and recycle old objects. Regards, Michael
Jun 14 2007
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Bill Baxter Wrote:
 Anyway, yeh, I'd be happy with a warning (or an error really -- unless 
 someone can think of a case where you really _want_ to crash your 
 program like that).
 
 --bb
Here's one: say you have a clas Wrapper that wraps another class. You might want to overload opEquals() to test against the wrapped object reference, so opEquals(null) will return true if the wrapped object is null. For erxample, Wrapper w = new Wrapper(null); // ... if(w == null) // Doesn't segfault and does what you want it to This could be throught of as a bad design decision (of course, I think all operator overloading in general makes code harder to read, with the possible exception of Box/Variant a very few other uses), but it's a valid use case.
Jun 14 2007