www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Nulling a reference to a class with opAssign ...

reply Mike <vertex gmx.at> writes:
Erm ... this totally catched me off guard ...

class Foo()
{
     Bar barRef;
     ~this() { barRef.noMoreFoo(); }
     void opAssign(float f);
}

class Bar()
{
     Foo fooRef;
     void setFoo(Foo foo) { fooRef =3D foo; }
     void noMoreFoo()     { fooRef =3D null; } // error: can't cast void=
* to  =

float ...
}

?

-Mike

-- =

Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Dec 07 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
Your exact code compiles for me (dmd 1.0.23)...  You sure you are using the 
latest dmd?

One observation, your destructor in Foo should not be accessing barRef 
because the garbage collector cannot guarantee that the barRef instance 
hasn't been collected.  If you are in the destructor, there is no reason to 
clean up GC references anyways, as the GC will handle that.

-Steve

"Mike" wrote in message
Erm ... this totally catched me off guard ...

class Foo()
{
     Bar barRef;
     ~this() { barRef.noMoreFoo(); }
     void opAssign(float f);
}

class Bar()
{
     Foo fooRef;
     void setFoo(Foo foo) { fooRef = foo; }
     void noMoreFoo()     { fooRef = null; } // error: can't cast void* to
float ...
}

?

-Mike

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/ 
Dec 07 2007
parent reply Mike <vertex gmx.at> writes:
On Fri, 07 Dec 2007 21:12:44 +0100, Steven Schveighoffer  =

<schveiguy yahoo.com> wrote:

DMD 1.023.

Hmm. I've not tried the example before. Maybe it's because Foo and Bar a=
re  =

actually template classes. Here's the actual code (yeah, I'm lazy with  =

comments and it's not yet finished).

-----------------------------------------------------------------------
// test code
void datacb(float value, uint id)
{
	Stdout("datacb - val: ")(value)(" id: ")(id).newline;
}
void messagecb(EDBMessage msg, uint id)
{
	Stdout("messagecb - id: ")(id).newline;
}

Stdout("testing databinding").newline;
auto testsource =3D new CDataSource!(float);
auto testsink1 =3D new CDataSink!(float)(testsource, &datacb, &messagecb=
, 1);
	=

testsource =3D 1.;
-----------------------------------------------------------------------
// the actual code
module tools.databinding;

enum EDBMessage
{
	sourceDeleted,
	sourceUpdated,
}

enum EDBForwardMode
{
	push,
	poll,
}

enum EDBAccessMode
{
	read,
	full,
}

class CDataSource(T)
{
	public this(EDBForwardMode forward =3D EDBForwardMode.push, EDBAccessMo=
de  =

access =3D EDBAccessMode.read)
	{
		myForwarding =3D forward;
		myAccess =3D access;
	}
	=

	public ~this()
	{
		// send every subscriber the deleted message
		foreach (item; mySubscribers)
		{
			if (item !is null) item.message(EDBMessage.sourceDeleted);
		}
	}
	=

	public void subscribe(CDataSink!(T) datasink)
	{
		// search if this sink is already subscribed
		foreach (item; mySubscribers)
		{ if (item !is null && item is datasink) return; }
		=

		// search for a deleted subscriber
		foreach (item; mySubscribers)
		{
			if (item is null)
			{
				item =3D datasink;
				mySubscriberCount++;
				return;
			}
		}
			=

		// add at end of list
		mySubscribers ~=3D datasink;
		mySubscriberCount++;
	}
	=

	public void unSubscribe(CDataSink!(T) datasink)
	{
		foreach (item; mySubscribers)
		{
			if (item !is null && item is datasink)
			{
				item =3D null;
				mySubscriberCount--;
				return;
			}
		}
	}
	=

	public T opAssign(T value)
	{
		myValue =3D value;
		if (mySubscriberCount =3D=3D 0) return value;
		foreach (item; mySubscribers)
		{
			if (item !is null)
			{
				if (myForwarding =3D=3D EDBForwardMode.push)
					item.update(value);
				else
					item.message(EDBMessage.sourceUpdated);
			}
		}
		return myValue;
	}
	=

	public T opCall()
	{ return myValue; }
	=

	public long subscriberCount()
	{ return mySubscriberCount; }
	=

	private T myValue;
	private CDataSink!(T)[] mySubscribers;
	private long mySubscriberCount;
	private EDBForwardMode myForwarding;
	private EDBAccessMode myAccess;
}

class CDataSink(T)
{
	public this(CDataSource!(T) source, void delegate(T, uint) valuecb, voi=
d  =

delegate(EDBMessage, uint) messagecb, uint id)
	{
		myValueCallback =3D valuecb;
		myMessageCallback =3D messagecb;
		myId =3D id;
		subscribe(source);
	}
	=

	public ~this()
	{
		if (mySource !is null) mySource.unSubscribe(this);
	}
	=

	public void subscribe(CDataSource!(T) source)
	{
		if (mySource !is null) mySource.unSubscribe(this);
		if (source !is null)
		{
			mySource =3D source;
			mySource.subscribe(this);
		}
	}
	=

	public T opCall()
	{ return mySource.myValue; }
	=

	public T opAssign(T value)
	{
		if (mySource.myAccess =3D=3D EDBAccessMode.full) return mySource =3D v=
alue;
		throw new Exception("Databinding: Datasource is write protected.");
	}
	=

	public EDBForwardMode forwarding()
	{ return mySource.myForwarding; }
	=

	public EDBAccessMode access()
	{ return mySource.myAccess; }
	=

	private void update(T value)
	{
		if (myValueCallback !is null) myValueCallback(value, myId);
	}
	=

	private void message(EDBMessage message)
	{
		if (message =3D=3D EDBMessage.sourceDeleted) mySource =3D null;
		if (myMessageCallback !is null) myMessageCallback(message, myId);
	}
	=

	private CDataSource!(T) mySource;
	private void delegate(T, uint) myValueCallback;
	private void delegate(EDBMessage, uint) myMessageCallback;
	private uint myId;
}
----------------------------------------------------------------------

 Your exact code compiles for me (dmd 1.0.23)...  You sure you are usin=
g =
 the
 latest dmd?

 One observation, your destructor in Foo should not be accessing barRef=
 because the garbage collector cannot guarantee that the barRef instanc=
e
 hasn't been collected.  If you are in the destructor, there is no reas=
on =
 to
 clean up GC references anyways, as the GC will handle that.

 -Steve

 "Mike" wrote in message
 Erm ... this totally catched me off guard ...

 class Foo()
 {
      Bar barRef;
      ~this() { barRef.noMoreFoo(); }
      void opAssign(float f);
 }

 class Bar()
 {
      Foo fooRef;
      void setFoo(Foo foo) { fooRef =3D foo; }
      void noMoreFoo()     { fooRef =3D null; } // error: can't cast vo=
id* =
 to
 float ...
 }

 ?

 -Mike
-- = Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Dec 07 2007
parent reply Frank Benoit <keinfarbton googlemail.com> writes:
the best chance to get a good answer is, to provide a minimalistic and
tested example that shows your problem.
Dec 07 2007
next sibling parent Mike <vertex gmx.at> writes:
On Fri, 07 Dec 2007 23:25:44 +0100, Frank Benoit  
<keinfarbton googlemail.com> wrote:

 the best chance to get a good answer is, to provide a minimalistic and
 tested example that shows your problem.
The problem is that every minimalistic example compiles. I don't know. Maybe I'll spend some more time on that. But I figured out the solution anyway - I now just cast the null to the correct type and it works. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Dec 07 2007
prev sibling parent reply Mike <vertex gmx.at> writes:
On Fri, 07 Dec 2007 23:25:44 +0100, Frank Benoit  =

<keinfarbton googlemail.com> wrote:

Ok ... got it:

class Foo(T)
{
	T opAssign(T v) { return v; }
}

void main()
{
	auto foo =3D new Foo!(float)();
	foo =3D cast(Foo!(float))null; // Works
	foo =3D null;                  // Error: Can't convert null to float
}

I'm not sure ... but I think the second assignment should work.

-- =

Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Dec 07 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Mike" <vertex gmx.at> wrote in message news:op.t2zshuvdkgfkbn lucia...
On Fri, 07 Dec 2007 23:25:44 +0100, Frank Benoit
<keinfarbton googlemail.com> wrote:
-------------------
Ok ... got it:

class Foo(T)
{
T opAssign(T v) { return v; }
}

void main()
{
auto foo = new Foo!(float)();
foo = cast(Foo!(float))null; // Works
foo = null;                  // Error: Can't convert null to float
}

I'm not sure ... but I think the second assignment should work.
-------------------

I absolutely think it should.  It's checking for an opAssign, finding it, 
but not falling back to the default behavior. 
Dec 07 2007
parent reply Mike <vertex gmx.at> writes:
On Sat, 08 Dec 2007 03:13:34 +0100, Jarrett Billingsley  =

<kb3ctd2 yahoo.com> wrote:

 "Mike" <vertex gmx.at> wrote in message news:op.t2zshuvdkgfkbn lucia..=
.
 On Fri, 07 Dec 2007 23:25:44 +0100, Frank Benoit
 <keinfarbton googlemail.com> wrote:
 -------------------
 Ok ... got it:

 class Foo(T)
 {
 T opAssign(T v) { return v; }
 }

 void main()
 {
 auto foo =3D new Foo!(float)();
 foo =3D cast(Foo!(float))null; // Works
 foo =3D null;                  // Error: Can't convert null to float
 }

 I'm not sure ... but I think the second assignment should work.
 -------------------

 I absolutely think it should.  It's checking for an opAssign, finding =
it,
 but not falling back to the default behavior.
Should I file it as a bug? -- = Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Dec 07 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Mike" <vertex gmx.at> wrote in message news:op.t2zvuik9kgfkbn lucia...

Should I file it as a bug?
--

Go ahead! 
Dec 07 2007