November 12, 2012
Ok, i was trying out D and wanted to see if i could create something that behaves like a property but adds a change notification signal. Doing this, I encountered a hangup which might be a bug. So far I have the following:

-----------------------------------------------------------

import std.signals;
import std.stdio;

struct Property
{
	alias get this;
	
	int set(int v) { emit(); return data_ = v; }
	int get() { return data_; }
	
	int opAssign(int v) { return set(v); }
	
	mixin Signal!();

private:
	int data_ = 0;
}

struct Foo
{
	Property prop;
}

class Observer
{
	void watch()
	{
		writeln("Value change observed!");
	}
}

-----------------------------------------------------------

This works:
void main()
{
	Foo f;
	Observer o = new Observer;
	f.prop.connect(&o.watch);
	f.prop = 7;
}

This also works:
void main()
{
	Foo f;
	Observer o = new Observer;
	f.prop = 7;
	writeln(f.prop);
}

This never terminates:
void main()
{
	Foo f;
	Observer o = new Observer;
	f.prop.connect(&o.watch);
	f.prop = 7;
	writeln(f.prop);
}
November 13, 2012
No one? Is this a bug, or am I overlooking something? (entirely possible since I didn't use D since trying it once in D1 times)

On Monday, 12 November 2012 at 11:59:50 UTC, Joe wrote:
> Ok, i was trying out D and wanted to see if i could create something that behaves like a property but adds a change notification signal. Doing this, I encountered a hangup which might be a bug. So far I have the following:
>
> -----------------------------------------------------------
>
> import std.signals;
> import std.stdio;
>
> struct Property
> {
> 	alias get this;
> 	
> 	int set(int v) { emit(); return data_ = v; }
> 	int get() { return data_; }
> 	
> 	int opAssign(int v) { return set(v); }
> 	
> 	mixin Signal!();
>
> private:
> 	int data_ = 0;
> }
>
> struct Foo
> {
> 	Property prop;
> }
>
> class Observer
> {
> 	void watch()
> 	{
> 		writeln("Value change observed!");
> 	}
> }
>
> -----------------------------------------------------------
>
> This works:
> void main()
> {
> 	Foo f;
> 	Observer o = new Observer;
> 	f.prop.connect(&o.watch);
> 	f.prop = 7;
> }
>
> This also works:
> void main()
> {
> 	Foo f;
> 	Observer o = new Observer;
> 	f.prop = 7;
> 	writeln(f.prop);
> }
>
> This never terminates:
> void main()
> {
> 	Foo f;
> 	Observer o = new Observer;
> 	f.prop.connect(&o.watch);
> 	f.prop = 7;
> 	writeln(f.prop);
> }


November 13, 2012
The third version using dmd 2.060 linux crashes. Valgrind shows lots of errors (other two are clean) relating to corrupted heap caused likely here (https://github.com/D-Programming-Language/phobos/blob/master/std/signals.d#L248) which is not surprising judging by semi-manual memory management in __dtor. I guess either you are abusing library feature or found a bug. Consider posting this to Bugzilla.
November 13, 2012
Not a compiler bug. A bug in the implementation of std.signals.
> > 	writeln(f.prop);

Property is a struct and thus it is passed by value, which means that the signal is copied. Signal does not define a postblit constructor, because it was intended to be used in classes, so a bitwise copy is done. Meaning that the internal allocated storage is freed twice.

If used in a class there is no issue with copying a signal, because it is a mixin and does not exist on its own and an object has reference semantics.

I am already working on a replacement for std.signals which fixes some of its shortcomings. It will also fix this one.

Best regards,

Robert

November 14, 2012
In your particular case, which this definitely is a bug and if only for missing documentation that you should only use it from classes, you might regardless be better of with writeln(f.prop.get) because you avoid the needless copy with memory allocation/deallocation (if done correctly) of the signal.

Passing f.prop directly should be possible for any function that takes an int, but not for generic template functions because then you pass the struct directly.

Best regards,

Robert


November 14, 2012
On Tuesday, 13 November 2012 at 22:55:38 UTC, eskimo wrote:
> Property is a struct and thus it is passed by value, which means that
> the signal is copied.

But wait! Due to "alias get this;", f.prop shouldn't copy prop
but call get (which it does in the working - second - case)!

How to check? Remove the alias and writeln(f.prop) prints
"Property(7)", with the alias writeln(f.prop) prints "7"
November 14, 2012
> 
> But wait! Due to "alias get this;", f.prop shouldn't copy prop but call get (which it does in the working - second - case)!
-> Also here the struct is copied, but the signal has no content yet and thus no memory allocation yet occurred. (So no double free)
> 
> How to check? Remove the alias and writeln(f.prop) prints
> "Property(7)", with the alias writeln(f.prop) prints "7"

It should copy f.prop and it does. Your check results have another explanation: writefln is a complete generic templated function, it has no way of knowing that you want to pass the contained integer instead of the struct. So by default it takes the struct (it has no requirements that would lead to trigger the alias this). Eventually it will call some function taking concrete arguments for printing the data. This concrete function is not overloaded for your struct so the alias this to int triggers now and the overload for int is being called.

But first it is copied to every generic function that might be called on the way.

November 15, 2012
On Wednesday, 14 November 2012 at 09:31:47 UTC, eskimo wrote:
> But first it is copied to every generic function that might be called on
> the way.

Ok, I guess it just doesn't do what I understood it to do (which is too bad, but to be expected with a new language). In any case you would appear to be correct, as

void main()
{
	Foo f;
	Observer o = new Observer;
	f.prop.connect(&o.watch);
	f.prop = 7;
	writeln(f.prop.get);
}

works. It just doesn't look like intended.
November 15, 2012
On Thu, 2012-11-15 at 09:53 +0100, Joe wrote:
> On Wednesday, 14 November 2012 at 09:31:47 UTC, eskimo wrote:
> > But first it is copied to every generic function that might be
> > called on
> > the way.
> 
> Ok, I guess it just doesn't do what I understood it to do (which is too bad, but to be expected with a new language). In any case you would appear to be correct, as
> 
> void main()
> {
> 	Foo f;
> 	Observer o = new Observer;
> 	f.prop.connect(&o.watch);
> 	f.prop = 7;
> 	writeln(f.prop.get);
> }
> 
> works. It just doesn't look like intended.

Well if signal had a proper postblit constructor your original way of doing it would work. It is just not as efficient, but this is a price you have to pay. The compiler has no way of knowing that you intended to pass the contained int from the beginning, when you are actually passing the containing struct.

But, considering that the alias this triggers only when you are issuing an operation not supported by the struct itself, it is pretty reasonable behaviour and everything else would be pretty surprising.

Best regards,

Robert


November 15, 2012
On Thursday, 15 November 2012 at 09:37:55 UTC, eskimo wrote:
>
> But, considering that the alias this triggers only when you are issuing
> an operation not supported by the struct itself, it is pretty reasonable
> behaviour and everything else would be pretty surprising.
>
> Best regards,
>
> Robert

I wonder though why it works at all then, because without the
alias the string conversion *is* supported and produces
"Property(7)".
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home