www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - toString() on struct template

reply Henning Hasemann <hhasemann web.de> writes:
I have a struct template with just 2 data members
(thats why I'd actually preferred a struct over a class).

It implements several methods such as overloaded operators
and the pseudo constructor roughly like this:

struct Vector2d(T) {
	T x, y;
	Vector2d!(T) opCall(T x, T y) {
	  Vector2d!(T) v;
	  v.x = x;
	  v.y = y;
	  return v;
	}
	char[] toString() {
	  return format("(%d|%d)", x, y);
	}
}

But the toString actually crashes hard everytime *before* the format-call.
(Btw: Dont be afraid because of the %d's I actually only instantiate the
template with int for testing).

Is there something wrong with my understanding or with the compiler
(tested dmd 1.005 and 1.007)?

Whats the proper way of implementing toString vor structs if not like this?

Henning
Feb 28 2007
next sibling parent Reiner Pope <reIGNOREiner.poCAPSpe gmFOOail.cBARom> writes:
Henning Hasemann wrote:
 I have a struct template with just 2 data members
 (thats why I'd actually preferred a struct over a class).
 
 It implements several methods such as overloaded operators
 and the pseudo constructor roughly like this:
 
 struct Vector2d(T) {
 	T x, y;
 	Vector2d!(T) opCall(T x, T y) {
 	  Vector2d!(T) v;
 	  v.x = x;
 	  v.y = y;
 	  return v;
 	}
 	char[] toString() {
 	  return format("(%d|%d)", x, y);
 	}
 }

I couldn't get your code to work as is, because it wasn't a 'static' opCall. The following code, however, runs fine on my computer:
 import std.stdio;
 import std.string;
 
 struct Vector2d(T) {
 	T x, y;
 	static Vector2d!(T) opCall(T x, T y) {
 	  Vector2d!(T) v;
 	  v.x = x;
 	  v.y = y;
 	  return v;
 	}
 	char[] toString() {
 	  return format("(%d|%d)", x, y);
 	}
 }
 
 void main()
 {
     auto a = Vector2d!(int)(5, 6);
     writefln(a.toString());
 }

Hope that helps, Reiner
Feb 28 2007
prev sibling next sibling parent reply mario pernici <mario.pernici mi.infn.it> writes:
Henning Hasemann Wrote:

 I have a struct template with just 2 data members
 (thats why I'd actually preferred a struct over a class).
 
 It implements several methods such as overloaded operators
 and the pseudo constructor roughly like this:
 
 struct Vector2d(T) {
 	T x, y;
 	Vector2d!(T) opCall(T x, T y) {
 	  Vector2d!(T) v;
 	  v.x = x;
 	  v.y = y;
 	  return v;
 	}
 	char[] toString() {
 	  return format("(%d|%d)", x, y);
 	}
 }
 
 But the toString actually crashes hard everytime *before* the format-call.
 (Btw: Dont be afraid because of the %d's I actually only instantiate the
 template with int for testing).
 
 Is there something wrong with my understanding or with the compiler
 (tested dmd 1.005 and 1.007)?
 
 Whats the proper way of implementing toString vor structs if not like this?
 
 Henning

It works in this example void main() { Vector2d!(int) a; auto b = a(5,6); writefln(b); } output: (5|6) Mario
Feb 28 2007
parent endea <endea users.sourceforge.net> writes:
Henning Hasemann kirjoitti:
 Hm, if I just break it down to that small example it works at expected,
 so my bug has to be somewhere else, sorry for bothering you before
 testing the minimal code myself.
 
 Henning

"%d" formats int type, that might be problem for Vector2d!(other-than-int)
Feb 28 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
Hm, if I just break it down to that small example it works at expected,
so my bug has to be somewhere else, sorry for bothering you before
testing the minimal code myself.

Henning
Feb 28 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
On Thu, 01 Mar 2007 08:01:37 +1100
Reiner Pope <reIGNOREiner.poCAPSpe gmFOOail.cBARom> wrote:

 I couldn't get your code to work as is, because it wasn't a 'static' 
 opCall. The following code, however, runs fine on my computer:

sorry, I just forgot to copy the static. The opCall itself seems to work just fine. Henning
Feb 28 2007
prev sibling next sibling parent reply Henning Hasemann <hhasemann web.de> writes:
I think I got it now:
If you build the source together with the main function, there
is no problem.

However in my constellation (the struct an the code that calls toString
in a linux static library which is linked against a main function)
this error occurs. The stacktrace says something about TypeInfo IIRC.

So it seems this information gets lost somehow?
I use dmd-1.007 (tried with 1.005 too), build the library with rebuild-0.12.
Maybe I should say that I use derelict too, but the error also occurs when
toString is called before any derelict-function.

I will try to further reduce the example, maybe later today.

Henning
Feb 28 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Henning Hasemann wrote:
 I think I got it now:
 If you build the source together with the main function, there
 is no problem.
 
 However in my constellation (the struct an the code that calls toString
 in a linux static library which is linked against a main function)
 this error occurs. The stacktrace says something about TypeInfo IIRC.
 
 So it seems this information gets lost somehow?
 I use dmd-1.007 (tried with 1.005 too), build the library with rebuild-0.12.
 Maybe I should say that I use derelict too, but the error also occurs when
 toString is called before any derelict-function.
 
 I will try to further reduce the example, maybe later today.
 
 Henning

You mentioned a library... If I remember correctly (standard disclaimers apply), then templates are NOT compiled into a library. For example, let's say you compiled the following file into a library: struct Foo(T) { void bar(T value) { writefln("%s", value); } } And then used it like so: void main() { Foo!(int) x; x.bar(42); } And finally compiled it like thus: dmd FooLib.lib main.d This would fail since FooLib.lib doesn't actually *have* the implementation of Foo in it. In order for D to compile a templated struct or class into a library, it would need to compile it for every possible type, which obviously isn't going to happen. If you want to use templates in a library, you *need* to ship and compile against the source code, not against a precompiled library. The one exception to this is that it should work for any templates you've explicitly instantiated. So, if you append this to Foo's source file: alias Foo!(int) FooInt; then it should work. -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Mar 01 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Henning Hasemann wrote:
 O
 And finally compiled it like thus:

     dmd FooLib.lib main.d

 This would fail since FooLib.lib doesn't actually *have* the
 implementation of Foo in it.  In order for D to compile a templated
 struct or class into a library, it would need to compile it for every
 possible type, which obviously isn't going to happen.

The more I play around with my code the more I think you are right. But I dont understand why I dont get an error at compile time but at runtime? Shouldnt the compiler already see if the template instantiation is available or not in the linking step?

Yes, it should... I thought these were link errors, which leads me to...
 If you want to use templates in a library, you *need* to ship and
 compile against the source code, not against a precompiled library.  The
 one exception to this is that it should work for any templates you've
 explicitly instantiated. So, if you append this to Foo's source file:

   alias Foo!(int) FooInt;

 then it should work.

The problem occurs also when the "main module" does not call any template function but only code from inside the library does. Can you explain that with your theory? What would be the solution? Henning

I think the best explanation in that case would be: "I was wrong." It was something of a long-shot, stab in the dark guess... Sorry. -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Mar 01 2007
parent Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Henning Hasemann schrieb am 2007-03-02:

[snip]

 But the return statement crashes like this:

 Program received signal SIGSEGV, Segmentation fault.
 [Switching to Thread -1209821504 (LWP 3999)]
 0xb7ea69cc in memcpy () from /lib/tls/i686/cmov/libc.so.6
 (gdb) bt
 #0  0xb7ea69cc in memcpy () from /lib/tls/i686/cmov/libc.so.6
 #1  0x0805627b in _d_arraycatnT ()
 #2  0x0805e521 in _D7indiana8vector2d15__T8Vector2dTiZ8Vector2
12my_to_stringMFZAa (this=0xbf81110c) at vector2d.d:94
 #3  0xbf81110c in ?? ()
 #4  0xbf811128 in ?? ()
 #5  0x0804ac9b in _Dmain () at test.d:45
 Previous frame inner to this frame (corrupt stack?)

Please use the following command to get the corret stack trace: objcopy -R .debug_frame original-binary fixed-binary http://d.puremagic.com/issues/show_bug.cgi?id=136#c6 Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFF6CU8LK5blCcjpWoRAiHuAJ4hHUSfBWyJ9zWTOWnrG6ItqJsRjgCfS+Op 9nYgVZYmDiWK9FfZUopV4HA= =kbea -----END PGP SIGNATURE-----
Mar 02 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
On Thu, 01 Mar 2007 21:20:38 +1100
Daniel Keep <daniel.keep.lists gmail.com> wrote:

 
 
 Henning Hasemann wrote:
 I think I got it now:
 If you build the source together with the main function, there
 is no problem.
 
 However in my constellation (the struct an the code that calls toString
 in a linux static library which is linked against a main function)
 this error occurs. The stacktrace says something about TypeInfo IIRC.
 
 So it seems this information gets lost somehow?
 I use dmd-1.007 (tried with 1.005 too), build the library with rebuild-0.12.
 Maybe I should say that I use derelict too, but the error also occurs when
 toString is called before any derelict-function.
 
 I will try to further reduce the example, maybe later today.
 
 Henning

You mentioned a library... If I remember correctly (standard disclaimers apply), then templates are NOT compiled into a library. For example, let's say you compiled the following file into a library: struct Foo(T) { void bar(T value) { writefln("%s", value); } } And then used it like so: void main() { Foo!(int) x; x.bar(42); } And finally compiled it like thus: dmd FooLib.lib main.d This would fail since FooLib.lib doesn't actually *have* the implementation of Foo in it. In order for D to compile a templated struct or class into a library, it would need to compile it for every possible type, which obviously isn't going to happen.

Sounds logical to me, but atm the only type I use for T is int and the template is instantiated in the library so the version used should be implemented. Calling other methods seems to work, too.
 If you want to use templates in a library, you *need* to ship and
 compile against the source code, not against a precompiled library.  The
 one exception to this is that it should work for any templates you've
 explicitly instantiated. So, if you append this to Foo's source file:
 
   alias Foo!(int) FooInt;
 
 then it should work.

And that's what I'm doing, too. So no problem here. Ill now start to find a minimal example of the problem. Henning
Mar 01 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
O
 And finally compiled it like thus:
 
     dmd FooLib.lib main.d
 
 This would fail since FooLib.lib doesn't actually *have* the
 implementation of Foo in it.  In order for D to compile a templated
 struct or class into a library, it would need to compile it for every
 possible type, which obviously isn't going to happen.

The more I play around with my code the more I think you are right. But I dont understand why I dont get an error at compile time but at runtime? Shouldnt the compiler already see if the template instantiation is available or not in the linking step?
 If you want to use templates in a library, you *need* to ship and
 compile against the source code, not against a precompiled library.  The
 one exception to this is that it should work for any templates you've
 explicitly instantiated. So, if you append this to Foo's source file:
 
   alias Foo!(int) FooInt;
 
 then it should work.

The problem occurs also when the "main module" does not call any template function but only code from inside the library does. Can you explain that with your theory? What would be the solution? Henning
Mar 01 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
On Fri, 02 Mar 2007 12:32:22 +1100
Daniel Keep <daniel.keep.lists gmail.com> wrote:

 
 I think the best explanation in that case would be: "I was wrong."  It
 was something of a long-shot, stab in the dark guess...

Hm okay it has nothing to do with templates it seems, I implemented my speciasization "Point" directly as struct (not as a special template implementation) and it produces the same error at run time. The traces always look like this: #0 0x080521a8 in _D3std6format8doFormatFDFwZvAC8TypeInfoPvZv () #1 0x0804f3b9 in _D3std6string6formatFYAa () #2 0x0805e498 in _D7indiana8vector2d5Point12my_to_stringMFZAa (this=0xbf92921c) at vector2d.d:170 #3 0xbf92921c in ?? () #4 0xbf929238 in ?? () #5 0x0804ac9b in _Dmain () at test.d:45 Previous frame inner to this frame (corrupt stack?) Also I did not manage to reduce this to some presentable code piece, when I start from ground I dont manage to get this error. Arr, I hate this kind of problems, feels like C where a fault somewhere causes misbehaviour somewhere else. But why is the problem just there? The rest of the code happily calls methods everywhere and works. Very strange thing. Henning -- v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR hackerkey.com
Mar 02 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
Now it seems to me, the problem is when calling format().
(I thought I exchanged format() before with a simple string without result,
strange again).

-- 
v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR
hackerkey.com
Mar 02 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
On Fri, 2 Mar 2007 09:53:03 +0100
Henning Hasemann <hhasemann web.de> wrote:

 
 Now it seems to me, the problem is when calling format().
 (I thought I exchanged format() before with a simple string without result,
 strange again).
 
 -- 
 v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR
hackerkey.com

It gets stranger more and more. I added a method to my vector2d struct template: (line numbers included) 92 char[] my_to_string() { 93 writefln(x); 94 return "(" ~ .toString(x) ~ "|" ~ .toString(y) ~ ")"; 95 } (I wanted to be sure the problem is not somewhere around foo.toString vs toString(foo)) x and y are members of the struct. The writefln prints the correct x value, so I think the template must have been correctly instantiated and this exists and is correct. But the return statement crashes like this: Program received signal SIGSEGV, Segmentation fault. [Switching to Thread -1209821504 (LWP 3999)] 0xb7ea69cc in memcpy () from /lib/tls/i686/cmov/libc.so.6 (gdb) bt #0 0xb7ea69cc in memcpy () from /lib/tls/i686/cmov/libc.so.6 #1 0x0805627b in _d_arraycatnT () #2 0x0805e521 in _D7indiana8vector2d15__T8Vector2dTiZ8Vector2 12my_to_stringMFZAa (this=0xbf81110c) at vector2d.d:94 #3 0xbf81110c in ?? () #4 0xbf811128 in ?? () #5 0x0804ac9b in _Dmain () at test.d:45 Previous frame inner to this frame (corrupt stack?) indiana is the name of the library and the module is vector2d. test.d is the module that holds main and calls my_to_string. It also seems when I at writefln("some_const_string") at the beginning of my_to_string, it crashes at an internal function called doFormat. Im getting crazy with this strange thing, I'd be happy about any small hint what I could do. Henning -- v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR hackerkey.com
Mar 02 2007
prev sibling parent Henning Hasemann <hhasemann web.de> writes:
You where right from the beginning.
In another module in the same library there was an instantiation of the
template with real, which natuarally wasnt available.

But its very evil that this throws an error when using the int-Version which
is correctly there.
Anyway this should really be detected at compile/link - time, since it is hard
to
track down.

Thanks for your time to anybody :-)

Henning

-- 
v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR
hackerkey.com
Mar 02 2007