www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Aquivalent References as in C++?

reply "Namespace" <rswhite4 googlemail.com> writes:
Hi,

I have a few questions about D and could use some help. For
instance, how can i rebuild such a behavior?

class Foo {
public:
Foo(const Bar& b) {

At C++ you can ensure that a reference is requested and must not
null.
Nevertheless lvalues are functional, which means Foo(Bar(42))
would operate just as good as
Bar b(42);
Foo(b);

The same procedure doesn't seem to operate with const ref,
instead you can only use ref. But in this case Ivalues doesn't
operate.
Because of the fact that in D all objects are indication of
references I thought that I simply didn't need a storage class.
But then I recognized that at my D equivalent…

class Foo {
public:
this(Bar b) {


…null can also be passed.

That case I would like to prevent, but at the same time allow
Ivalues. How does that work in D classes?
As far as I know this operates with structs, but shouldn't it be
possible with classes and objects too?

Would be really nice if anyone had an advice for me.
Apr 16 2012
next sibling parent Kevin Cox <kevincox.ca gmail.com> writes:
--0015175d07bc6461d504bdd293e0
Content-Type: text/plain; charset=UTF-8

On Apr 16, 2012 5:29 PM, "Namespace" <rswhite4 googlemail.com> wrote:

 That case I would like to prevent, but at the same time allow
 Ivalues. How does that work in D classes?
 As far as I know this operates with structs, but shouldn't it be
 possible with classes and objects too?

I would recommend a precondition. It is a language enforced method of restricting what values may be passed into a function. If the code is compiled for release the checks are not included and do not cost anything. --0015175d07bc6461d504bdd293e0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <p><br> On Apr 16, 2012 5:29 PM, &quot;Namespace&quot; &lt;<a href=3D"mailto:rswhit= e4 googlemail.com">rswhite4 googlemail.com</a>&gt; wrote:</p> <p>&gt; That case I would like to prevent, but at the same time allow<br> &gt; Ivalues. How does that work in D classes?<br> &gt; As far as I know this operates with structs, but shouldn&#39;t it be<b= r> &gt; possible with classes and objects too?</p> <p>I would recommend a precondition.=C2=A0 It is a language enforced method= of restricting what values may be passed into a function.=C2=A0 If the cod= e is compiled for release the checks are not included and do not cost anyth= ing. <br> </p> --0015175d07bc6461d504bdd293e0--
Apr 16 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/16/2012 11:25 PM, Namespace wrote:
 Hi,

 I have a few questions about D and could use some help. For
 instance, how can i rebuild such a behavior?

 class Foo {
 public:
 Foo(const Bar& b) {

 At C++ you can ensure that a reference is requested and must not
 null.
 Nevertheless lvalues are functional, which means Foo(Bar(42))
 would operate just as good as
 Bar b(42);
 Foo(b);

 The same procedure doesn't seem to operate with const ref,
 instead you can only use ref. But in this case Ivalues doesn't
 operate.
 Because of the fact that in D all objects are indication of
 references I thought that I simply didn't need a storage class.
 But then I recognized that at my D equivalent…

 class Foo {
 public:
 this(Bar b) {


 …null can also be passed.

 That case I would like to prevent, but at the same time allow
 Ivalues. How does that work in D classes?
 As far as I know this operates with structs, but shouldn't it be
 possible with classes and objects too?

 Would be really nice if anyone had an advice for me.

You could do this: this(Bar b)in{assert(b !is null);}body{
Apr 16 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/17/2012 02:39 AM, Namespace wrote:

 Bar b = new Bar(42);

 new Foo(b); // works
 new Foo(null); // compiler error


That fails because null is a compile time value and you have a special template code for that that fails the compilation.
 new Foo(Bar(23)); // works
 new Foo(Bar(25)); // works

But if I write Bar bn; new Foo(bn); it works also and doesn't throw a compiler error.

There, bn is a variable that has it's own life at runtime. Although the compiler can analyze the code to determine that bn never becomes anything but null, we may not want it to be too smart. Imagine that there are lines after Bar bn; that you have just commented out: Bar bn; // bn = foo(); new Foo(bn); Now the compilation would failure would be an annoyance. That's part of the reason why the compiler does not go that deep in its analysis.
 To avoid this, I have to write an assert(obj !is null); again.

Yes, you must because whetheer obj is null is only known at runtime.
 This really sucks. If anybody else works with my Code and puts a null
 reference to any method he gets no compiler error and wonder why he gets
 a runtime error instead.
 Thats very annoying...

Ali
Apr 17 2012
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/17/2012 08:49 AM, Ali Çehreli wrote:

 That fails because null is a compile time value and you have a special
 template code for that that fails the compilation.

Scratch the 'template' part. You don't have templates there but what I said is still valid. Basically, you have some code that fails at compile time. Ali
Apr 17 2012
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/17/2012 10:37 AM, Namespace wrote:
 Yes, you must because whetheer obj is null is only known at runtime.

Yes, but if i forget the assert i get an Access Violation error with no more informations. Problem is nobody knows _why_ he gets this error, because the error message gives no information.

In order to get a meaningful error, the compiler would have to inject code that checked every access through a class reference. Unfortunately that would bring too much overhead and not be acceptable in a system language. But it could be a part of the non-release builds. I don't have any idea how slow program would become if every class dereferencing would be checked against null like that. (?)
 So it must be a better solution then to write in every method
 "assert(obj_param !is null");".

Not in every method, but only in methods that actually dereference that pointer. Intermediate functions that simply pass the parameter to another function need not check the condition. In the end, null references are a part of D. The code must be written in a way to accept it. As an aside, enforce() may be more suitable and a little shorter: enforce(obj_param, "Even with a message"); Whether to use assert() or enforce() depends on the function.
 Best of all solutions would be that a
 special keyword, for example scope, ensure that lvalues would except but
 _no_ null-references.

Yes, the keyword would be a little shorter than the assert() or enforce() above but D already has very many keywords. :) Finally, actually it is possible to have bugs of the same sort even with references in C++: // C++ code struct S { int i; S(int param_i) : i(param_i) {} }; S * make_S(int i) { return (i == 42) ? new S(i) : 0; } void use_S(const S & s) { int i = s.i; } int main() { use_S(*make_S(100)); } The output is the same as in D: Segmentation fault So, as you see, neither C++ provide any help here. C++'s references have these meanings: * On the parameter list: "I would like to have a real object please." As seen above, it is so easy to violate that. The caller of use_S() realizes that a reference is needed and just dereferences the pointer at hand. See, the caller must ensure even in C++ that the pointer that is available is not NULL. * On the return type: "What I give you is an alias to an existing object." Even this is a false promise without tool support, because the reference may be of an automatic local object. Ali
Apr 17 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/17/2012 08:10 PM, Namespace wrote:
 Best of all solutions would be that a
 special keyword, for example scope, ensure that lvalues would

 _no_ null-references.

Yes, the keyword would be a little shorter than the assert() or enforce() above but D already has very many keywords. :)

Yes, but scope is an unused storage keyword, isn't it?

It is used.
 So it could be an idea to avoid speed losses with the current method and
 ensure that the object is not null, if it's intentional.

Define 'ensure'.
Apr 17 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/17/2012 08:40 PM, Namespace wrote:
 Define 'ensure'.

Guarantee, that the given object parameter isn't a null reference.

But C++ does not do that either. Are you asking for a full-blown non-null type system?
Apr 17 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/17/2012 09:16 PM, Namespace wrote:
 But C++ does not do that either.
 Are you asking for a full-blown non-null type system?

Yes, but of course only with a special Keyword/Storage class.

If it is not the default, how would you enforce it at the caller side?
Apr 17 2012
parent bearophile <bearophileHUGS lycos.com> writes:
Namespace:

 But i think, i'm probably the only one in D who really wants 
 something like that.

I have discussed this topic three or more times, and opened an enhancement request around 2010-08-02: http://d.puremagic.com/issues/show_bug.cgi?id=4571 Bye, bearophile
Apr 18 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 how can i rebuild such a behavior?

 class Foo {
 public:
 Foo(const Bar& b) {

In D struct instances are values, and you can manage them as values, or as a pointer to value (or pointer to pointer to value, etc). In D class instances are always managed by reference, and such references, like pointers, can be null (and emplace() is supposed to allow in-place allocation of a class instance). So in normal D code you can't write D code equivalent to that C++ code. Some possibilities: class Foo {} void bar(Foo f) {} void bar(const Foo f) {} struct Baz {} void spam(Baz b) {} void spam(in Baz b) {} void spam(ref Baz b) {} void spam(Baz* b) {} void spam(const Baz* b) {} void spam(const ref Baz b) {} void spam(immutable ref Baz b) {} There is also inout, out, etc. Lot of people (me too) have asked non-null class references (and pointers) in D. We are now able to disable some constructors... Bye, bearophile
Apr 16 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
This is what I am actually doing at the moment, but I thougth 
that in a modern language like D, it is possible to have non-null 
references to avoid such constructs with assert.
My last hope was that an explicit ref would allow me both: 
non-null references _and_ lvalues, at least for objects.

That is very sad. Any possibility that this might change?
I really like that objects are implicit references and so i would 
not use structs, but it looks like i have no choice if i would 
avoid asserts..

On Monday, 16 April 2012 at 21:34:34 UTC, Timon Gehr wrote:
 On 04/16/2012 11:25 PM, Namespace wrote:
 Hi,

 I have a few questions about D and could use some help. For
 instance, how can i rebuild such a behavior?

 class Foo {
 public:
 Foo(const Bar& b) {

 At C++ you can ensure that a reference is requested and must 
 not
 null.
 Nevertheless lvalues are functional, which means Foo(Bar(42))
 would operate just as good as
 Bar b(42);
 Foo(b);

 The same procedure doesn't seem to operate with const ref,
 instead you can only use ref. But in this case Ivalues doesn't
 operate.
 Because of the fact that in D all objects are indication of
 references I thought that I simply didn't need a storage class.
 But then I recognized that at my D equivalent…

 class Foo {
 public:
 this(Bar b) {


 …null can also be passed.

 That case I would like to prevent, but at the same time allow
 Ivalues. How does that work in D classes?
 As far as I know this operates with structs, but shouldn't it 
 be
 possible with classes and objects too?

 Would be really nice if anyone had an advice for me.

You could do this: this(Bar b)in{assert(b !is null);}body{

Apr 16 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
Now i have something like this. It works and manipulates lvalues 
so that i can pass my objects by ref to except null.

But is this smart?

class Bar {
public:
	int x;
	
	static ref Bar opCall(int x) {
		static Bar b;
		
		b = new Bar(x);
		
		return b;
	}
	
	this(int x) {
		this.x = x;
	}
}

class Foo {
private:
	Bar _bar;

public:
	int y;
	
	this() { }
	
	this(ref Bar b) {
		//assert(b !is null);
		
		writefln("B.x %d", b.x);
	}
}

Bar b = new Bar(42);
	
new Foo(b); // works
new Foo(null); // compiler error
new Foo(Bar(23)); // works
new Foo(Bar(25)); // works
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 17 April 2012 at 08:02:02 UTC, Namespace wrote:
 Now i have something like this. It works and manipulates 
 lvalues so that i can pass my objects by ref to except null.

 But is this smart?

 class Bar {
 public:
 	int x;
 	
 	static ref Bar opCall(int x) {
 		static Bar b;
 		
 		b = new Bar(x);
 		
 		return b;
 	}
 	
 	this(int x) {
 		this.x = x;
 	}
 }

 class Foo {
 private:
 	Bar _bar;

 public:
 	int y;
 	
 	this() { }
 	
 	this(ref Bar b) {
 		//assert(b !is null);
 		
 		writefln("B.x %d", b.x);
 	}
 }

 Bar b = new Bar(42);
 	
 new Foo(b); // works
 new Foo(null); // compiler error
 new Foo(Bar(23)); // works
 new Foo(Bar(25)); // works

But if I write Bar bn; new Foo(bn); it works also and doesn't throw a compiler error. To avoid this, I have to write an assert(obj !is null); again. This really sucks. If anybody else works with my Code and puts a null reference to any method he gets no compiler error and wonder why he gets a runtime error instead. Thats very annoying...
Apr 17 2012
prev sibling next sibling parent "Dejan Lekic" <dejan.lekic gmail.com> writes:
On Tuesday, 17 April 2012 at 09:39:10 UTC, Namespace wrote:
 On Tuesday, 17 April 2012 at 08:02:02 UTC, Namespace wrote:
 Now i have something like this. It works and manipulates 
 lvalues so that i can pass my objects by ref to except null.

 But is this smart?

 class Bar {
 public:
 	int x;
 	
 	static ref Bar opCall(int x) {
 		static Bar b;
 		
 		b = new Bar(x);
 		
 		return b;
 	}
 	
 	this(int x) {
 		this.x = x;
 	}
 }

 class Foo {
 private:
 	Bar _bar;

 public:
 	int y;
 	
 	this() { }
 	
 	this(ref Bar b) {
 		//assert(b !is null);
 		
 		writefln("B.x %d", b.x);
 	}
 }

 Bar b = new Bar(42);
 	
 new Foo(b); // works
 new Foo(null); // compiler error
 new Foo(Bar(23)); // works
 new Foo(Bar(25)); // works

But if I write Bar bn; new Foo(bn); it works also and doesn't throw a compiler error. To avoid this, I have to write an assert(obj !is null); again. This really sucks. If anybody else works with my Code and puts a null reference to any method he gets no compiler error and wonder why he gets a runtime error instead. Thats very annoying...

For that, you have static if contitions, and indeed you can make it a compile-time error.
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 For that, you have static if contitions, and indeed you can 
 make it a compile-time error.

Can you show me this as code? And are there any plans to realize non-null references or strategies to avoid such things? Otherwise there would really be something important missing in D.
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 Yes, you must because whetheer obj is null is only known at 
 runtime.

Yes, but if i forget the assert i get an Access Violation error with no more informations. Problem is nobody knows _why_ he gets this error, because the error message gives no information. So it must be a better solution then to write in every method "assert(obj_param !is null");". Best of all solutions would be that a special keyword, for example scope, ensure that lvalues would except but _no_ null-references.
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 Best of all solutions would be that a
 special keyword, for example scope, ensure that lvalues would

 _no_ null-references.

Yes, the keyword would be a little shorter than the assert() or enforce() above but D already has very many keywords. :)

Yes, but scope is an unused storage keyword, isn't it? So it could be an idea to avoid speed losses with the current method and ensure that the object is not null, if it's intentional.
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 Define 'ensure'.

Guarantee, that the given object parameter isn't a null reference.
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 But C++ does not do that either.
 Are you asking for a full-blown non-null type system?

Yes, but of course only with a special Keyword/Storage class.
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 17 April 2012 at 19:56:11 UTC, Timon Gehr wrote:
 On 04/17/2012 09:16 PM, Namespace wrote:
 But C++ does not do that either.
 Are you asking for a full-blown non-null type system?

Yes, but of course only with a special Keyword/Storage class.

If it is not the default, how would you enforce it at the caller side?

By the compiler who throws an error message or a warning. A warning or a better error message would help also, if a null-reference was in use. But only the message "Access violation" without any information isn't enough, imo. It seems that not-null references wouldn't be a part of D in near future.
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
Another idea: instead scope, "in" can get a new functionality. 
Instead as a synonym for "const" it could mean "not null" for 
objects.
Apr 17 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:
 Another idea: instead scope, "in" can get a new functionality. 
 Instead as a synonym for "const" it could mean "not null" for 
 objects.

Note that currently in D2 "in" means "scope const". Bye, bearophile
Apr 17 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 17 April 2012 at 23:56:12 UTC, bearophile wrote:
 Namespace:
 Another idea: instead scope, "in" can get a new functionality. 
 Instead as a synonym for "const" it could mean "not null" for 
 objects.

Note that currently in D2 "in" means "scope const". Bye, bearophile

Yes I know. But the importand fact is that it's only a shorthand, you could use it for something more meaningful. I only want to point out how important this content is to me. Many user in other languages are wishing for a non-null reference keyword (e.g. Java, C#). So why should D don't give a solution? But i think, i'm probably the only one in D who really wants something like that.
Apr 18 2012
prev sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 18 April 2012 at 11:36:30 UTC, bearophile wrote:
 Namespace:

 But i think, i'm probably the only one in D who really wants 
 something like that.

I have discussed this topic three or more times, and opened an enhancement request around 2010-08-02: http://d.puremagic.com/issues/show_bug.cgi?id=4571 Bye, bearophile

That is incredible. What are the reasons against such implementation? I will open a new topic to discuss about that again.
Apr 18 2012