www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Structs with pointers?

reply Sean Eskapp <eatingstaples gmail.com> writes:
Why doesn't this code work?

struct Bar
{
	int* x;
}

void foo(Bar a) {}

void main()
{
	const a = Bar();
	foo(a);
}

But replacing int* with some other type works fine? Even if a write a postblit
function for Bar, it still fails to compile.
Jan 22 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Sean Eskapp:

 Why doesn't this code work?

This works, the Bar instance you give to foo is const. void foo(const Bar a) {} Bye, bearophile
Jan 22 2011
prev sibling parent reply Sean Eskapp <eatingstaples gmail.com> writes:
== Quote from Sean Eskapp (eatingstaples gmail.com)'s article
 Why doesn't this code work?
 struct Bar
 {
 	int* x;
 }
 void foo(Bar a) {}
 void main()
 {
 	const a = Bar();
 	foo(a);
 }
 But replacing int* with some other type works fine? Even if a write a postblit
 function for Bar, it still fails to compile.

Nevermind, I realized it's because constness is transitive in pointers. A const struct with a pointer member has a const pointer member, and those can't be implicitly cast to non-const pointer members.
Jan 22 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Sean Eskapp:

 Nevermind, I realized it's because constness is transitive in pointers. A const
 struct with a pointer member has a const pointer member, and those can't be
 implicitly cast to non-const pointer members.

Uhm, the struct having a pointer is not important. In theory this too can't compile: struct Bar {} void foo(Bar b) {} void main() { const b = Bar(); foo(b); } Is this another compiler bug? Bye, bearophile
Jan 22 2011
next sibling parent Sean Eskapp <eatingstaples gmail.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 Sean Eskapp:
 Nevermind, I realized it's because constness is transitive in pointers. A const
 struct with a pointer member has a const pointer member, and those can't be
 implicitly cast to non-const pointer members.

struct Bar {} void foo(Bar b) {} void main() { const b = Bar(); foo(b); } Is this another compiler bug? Bye, bearophile

No, that compiles fine. Because the struct owns a pointer, the const struct owns a const pointer. When copying a const-struct to a non-const struct, this means you must cast a const-pointer to a non-const pointer, which shouldn't be allowed.
Jan 22 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
 Is this another compiler bug?

The situation is nice: struct Foo1 {} struct Foo2 { int x; } const struct Foo3 { int* p; } struct Foo4 { int* p; } void bar1(Foo1 f) {} void bar2(Foo2 f) {} void bar3(Foo3 f) {} void bar4(Foo4 f) {} void main() { const f1 = Foo1(); bar1(f1); // no error const f2 = Foo2(); bar2(f2); // no error const f3 = Foo3(); bar3(f3); // no error const f4 = Foo4(); bar4(f4); // error } Bye, bearophile
Jan 22 2011
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 23.01.2011 2:02, bearophile wrote:
 Is this another compiler bug?

struct Foo1 {} struct Foo2 { int x; } const struct Foo3 { int* p; } struct Foo4 { int* p; } void bar1(Foo1 f) {} void bar2(Foo2 f) {} void bar3(Foo3 f) {} void bar4(Foo4 f) {} void main() { const f1 = Foo1(); bar1(f1); // no error const f2 = Foo2(); bar2(f2); // no error const f3 = Foo3(); bar3(f3); // no error const f4 = Foo4(); bar4(f4); // error } Bye, bearophile

The first two are actually OK, since you pass a copy of a value type FooX to barX. If signature was void bar(ref FooX) then it should have failed. But the third makes me wonder what the *** is going on. -- Dmitry Olshansky
Jan 23 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Dmitry Olshansky:

 The first two are actually OK, since you pass a copy of a value type 
 FooX to barX.
 If signature was void bar(ref FooX) then it should have failed.
 But the third makes me wonder what the *** is going on.

I have added the third case to this bug report of mine: http://d.puremagic.com/issues/show_bug.cgi?id=3934 Bye, bearophile
Jan 23 2011
prev sibling parent reply Mafi <mafi example.org> writes:
Am 23.01.2011 11:00, schrieb Dmitry Olshansky:
 On 23.01.2011 2:02, bearophile wrote:
 Is this another compiler bug?

struct Foo1 {} struct Foo2 { int x; } const struct Foo3 { int* p; } struct Foo4 { int* p; } void bar1(Foo1 f) {} void bar2(Foo2 f) {} void bar3(Foo3 f) {} void bar4(Foo4 f) {} void main() { const f1 = Foo1(); bar1(f1); // no error const f2 = Foo2(); bar2(f2); // no error const f3 = Foo3(); bar3(f3); // no error const f4 = Foo4(); bar4(f4); // error } Bye, bearophile

The first two are actually OK, since you pass a copy of a value type FooX to barX. If signature was void bar(ref FooX) then it should have failed. But the third makes me wonder what the *** is going on.

I think it's absolutely correct. Look: Foo3 is declared as const struct meaning all it's members are const. We are passing a struct like that to bar3: const Foo3 { const int* p} which is implicitely converted to: Foo3 { const int* p } //not ref !! Because it's not ref you can't manipulate the original struct anyways and the pointer is still const. As long as you don't cast you cannot change what the pointer points to so this implicit conversion is correct IMO. It's like const(T[]) => const(T)[] . Mafi
Jan 23 2011
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 23.01.2011 19:05, Mafi wrote:
 Am 23.01.2011 11:00, schrieb Dmitry Olshansky:
 On 23.01.2011 2:02, bearophile wrote:
 Is this another compiler bug?

struct Foo1 {} struct Foo2 { int x; } const struct Foo3 { int* p; } struct Foo4 { int* p; } void bar1(Foo1 f) {} void bar2(Foo2 f) {} void bar3(Foo3 f) {} void bar4(Foo4 f) {} void main() { const f1 = Foo1(); bar1(f1); // no error const f2 = Foo2(); bar2(f2); // no error const f3 = Foo3(); bar3(f3); // no error const f4 = Foo4(); bar4(f4); // error } Bye, bearophile

The first two are actually OK, since you pass a copy of a value type FooX to barX. If signature was void bar(ref FooX) then it should have failed. But the third makes me wonder what the *** is going on.

I think it's absolutely correct. Look: Foo3 is declared as const struct meaning all it's members are const. We are passing a struct like that to bar3: const Foo3 { const int* p} which is implicitely converted to: Foo3 { const int* p } //not ref !! Because it's not ref you can't manipulate the original struct anyways and the pointer is still const. As long as you don't cast you cannot change what the pointer points to so this implicit conversion is correct IMO. It's like const(T[]) => const(T)[] .

But do we really need this syntax: const struct { ... } ?
 Mafi

-- Dmitry Olshansky
Jan 23 2011
prev sibling parent Dan Olson <zans.is.for.cans yahoo.com> writes:
bearophile <bearophileHUGS lycos.com> writes:

 Is this another compiler bug?

The situation is nice: struct Foo1 {} struct Foo2 { int x; } const struct Foo3 { int* p; } struct Foo4 { int* p; } void bar1(Foo1 f) {} void bar2(Foo2 f) {} void bar3(Foo3 f) {} void bar4(Foo4 f) {} void main() { const f1 = Foo1(); bar1(f1); // no error const f2 = Foo2(); bar2(f2); // no error const f3 = Foo3(); bar3(f3); // no error const f4 = Foo4(); bar4(f4); // error } Bye, bearophile

I was going to say its because structs are passed by value. But then I changed bar2 to bar2(ref Foo2 f) {f.x = 2;} and that compiled without error and even changed f2.x to 2 when I printed it. That seems like a bug.
Jan 23 2011