September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright Attachments: | Walter Bright schrieb am 2006-09-29:
> The problem in general with hiding pointers is that it'll break with a moving garbage collector. You could work around this by 'pinning' the objects, but pinning objects long term is a bad idea.
How about an GC allocation area that isn't searched for valid pointers but is still collected?
Thomas
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote: > Bill Baxter wrote: >> I think railroading Qt's S&S into a language is the wrong approach. What goes into the language should be a more general mechanism on top of which schemes like dynamic S&S can be easily built. > > I agree, and thanks for letting me know about the string matching. That'll become possible in D later when it gets more introspection abilities. Some thoughts about introspection: The most basic introspection would simply be, for each class and struct Typeinfo, add a pointer to a string that's just a concatenation of names and mangled types. [name]\0[mangleof]\0[name]\0[mangleof]\0...[name]\0[mangleof]\0\0. Since we have .alignof and .sizeof, this would allow all data members to be identified; and would allow code to be developed that could do serialization stuff. It would also be reasonably compact. And an identical treatment for the functions in the vtable (just need to maintain the same order of functions). Given a string XXX, you could search for a function named "slotXXX" in the manglelist, and call the corresponding entry in the vtable. It wouldn't deal with static functions (where you need the address as well as the name and type info) I guess the challenging issue is to make sure that functions that aren't referenced don't get type info stored? I imagine those dynamic languages have trouble discarding unused functions at link time. I think you'd need to tell the compiler "don't discard this function even if you think it's not used, it's only referenced in a text string". |
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> Ok, before anyone jumps on me, this has all been discussed in http://www.digitalmars.com/d/archives/28456.html
>
> Looks like the deletion problem is a real issue. Let me think about it a bit.
Hmm. A "big" SS implementation (see previous thread here "Dissecting the SS") c.f. like the 111 case, has more deletion related issues.
In a non-trivial application one can almost take it for granted that there's instance pooling going on, too.
A robust implementation would guarantee that any way the observer gets "removed" guarantees it also ceases to exist as an observer. This includes
- getting deleted
- simply not being referred to anymore
- getting moved to the unused instances pool
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> Walter Bright wrote:
>
>> Some of the boilerplate can be eliminated with a mixin.
>
>
> Here's the mixin. Actually, 3 of them, one each for 0 arguments, 1 argument, and 2 arguments. I added a disconnect() function. Note how trivial it is to use - no need for preprocessing.
>
> import std.stdio;
>
> template Signal() // for 0 arguments
> {
> void emit()
> {
> foreach (dg; slots)
> dg();
> }
>
> void connect( void delegate() dg)
> {
> slots ~= dg;
> }
>
> void disconnect( void delegate() dg)
> {
> for (size_t i = 0; i < slots.length; i++)
> {
> if (slots[i] == dg)
> {
> if (i + 1 == slots.length)
> slots = slots[0 .. i];
> else
> slots = slots[0 .. i] ~ slots[i + 1 .. length];
> }
> }
> }
>
> private:
> void delegate()[] slots;
> }
>
> template Signal(T1) // for one argument
> {
> void emit( T1 i )
> {
> foreach (dg; slots)
> dg(i);
> }
>
> void connect( void delegate(T1) dg)
> {
> slots ~= dg;
> }
>
> void disconnect( void delegate(T1) dg)
> {
> for (size_t i = 0; i < slots.length; i++)
> {
> if (slots[i] == dg)
> {
> if (i + 1 == slots.length)
> slots = slots[0 .. i];
> else
> slots = slots[0 .. i] ~ slots[i + 1 .. length];
> }
> }
> }
>
> private:
> void delegate(T1)[] slots;
> }
>
> template Signal(T1, T2) // for two arguments
> {
> void emit( T1 i, T2 j )
> {
> foreach (dg; slots)
> dg(i, j);
> }
>
> void connect( void delegate(T1, T2) dg)
> {
> slots ~= dg;
> }
>
> void disconnect( void delegate(T1, T2) dg)
> {
> for (size_t i = 0; i < slots.length; i++)
> {
> if (slots[i] == dg)
> {
> if (i + 1 == slots.length)
> slots = slots[0 .. i];
> else
> slots = slots[0 .. i] ~ slots[i + 1 .. length];
> }
> }
> }
>
> private:
> void delegate(T1, T2)[] slots;
> }
>
>
> class Foo
> {
> this() { }
>
> int value() { return val; }
>
> void setValue( int v )
> {
> if ( v != val )
> {
> val = v;
> emit(v);
> }
> }
>
> mixin Signal!(int); // adds in all the boilerplate to make it work
>
> private:
> int val;
> }
>
> void main()
> {
> Foo a = new Foo;
> Foo b = new Foo;
> a.connect(&b.setValue);
> b.setValue( 11 ); // a == 0 b == 11
> a.setValue( 79 ); // a == 79 b == 79
> writefln(b.value()); // prints 79
> a.disconnect(&b.setValue);
> a.setValue( 80);
> writefln(b.value()); // prints 79
> }
One problem with this setup is that here every observee "knows" about all its observers.
If, on top of this, we want to give the observers the ability to unregister themselves (e.g. before getting destroyed), the observer has to know about all the observees.
This essentially creates a network with pointers.
Having instead an external entity to handle SS reduces drastically the number of needed connections.
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter wrote:
>
> What goes into the language should be a more general mechanism on top
> of which schemes like dynamic S&S can be easily built.
Now this does sound reasonable.
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Thomas Kuehne | Thomas Kuehne wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Walter Bright schrieb am 2006-09-29:
>> The problem in general with hiding pointers is that it'll break with a moving garbage collector. You could work around this by 'pinning' the objects, but pinning objects long term is a bad idea.
>
> How about an GC allocation area that isn't searched for valid pointers
> but is still collected?
Couldn't we use malloc/free + RAII for that? ...auto_ptr<>?
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Thomas Kuehne | Thomas Kuehne wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Walter Bright schrieb am 2006-09-29:
>
>>The problem in general with hiding pointers is that it'll break with a moving garbage collector. You could work around this by 'pinning' the objects, but pinning objects long term is a bad idea.
>
>
> How about an GC allocation area that isn't searched for valid pointers
> but is still collected?
>
> Thomas
>
> -----BEGIN PGP SIGNATURE-----
>
> iD8DBQFFHPsFLK5blCcjpWoRAg5cAJ0Tg9vDT3A7N8XMOMBk5gkVBcU7twCgkVaM
> wl6LSgAw6xnyhduUo4tDKcI=
> =zWvW
> -----END PGP SIGNATURE-----
I wish we had such a gc area.
This could make the gc more efficient as well as solving weak references (at least weak refs on the heap). You would have two allocation functions in the GC (ideally exposed for user code use, no more malloc please) - one that allocates on a heap that is scanned for pointers, and one that allocates on the unscanned heap. The unscanned heap is still sweeped of course. Then whenever the compiler sees something like int[] = new int[4096]; it will make sure that array data is allocated on the unscanned heap, since its type implies it will not contain pointers. Now the GC doesn't have to scan all 4096*4=16384 bytes of memory contained by that array, which in some cases will massively speed up the mark phase of a collection.
Currently there is some saving grace in the fact that when you use C libraries like SDL, a lot of your data will end up in the C heap, which accomplishes the same speed boost. But that still has D reliant on the C heap, and said data isn't garbage collected unless you use wrappers or something :( Ultimately this will bite us if we write libraries in D that use large data structures that contain no pointers (um graphics libs), so for example a D port of SDL would kinda suck right now unless it used malloc.
(end of sales speech for gc optimization/modification)
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Georg Wrede | Georg Wrede wrote:
> Chad J > wrote:
>
>> Couldn't you also do weak pointers by XORing them with 0xFFFFFFFF (or, better yet, const size_t weakxor = -1), then XORing again before and after you need to operate on them?
>>
>> Just thought I'd toss that out there.
>
>
> What happens the day we're halfway up the virtual memory space?
Then we might keep alive other dead objects. That's life with a conservative gc. Even mundane variables like int's in your code today can cause objects to be kept around past their expiration date.
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> The problem in general with hiding pointers is that it'll break with a moving garbage collector. You could work around this by 'pinning' the objects, but pinning objects long term is a bad idea.
Am I the only one who is screaming "OMG! What a hack!" while reading this thread?
Sincerely, my impression of D dropped 2 points after reading the proposed solutions on this thread.
|
September 29, 2006 Re: Signals and Slots in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lionello Lunesu Attachments: | Lionello Lunesu schrieb am 2006-09-29:
> Thomas Kuehne wrote:
>> Walter Bright schrieb am 2006-09-29:
>>> The problem in general with hiding pointers is that it'll break with a moving garbage collector. You could work around this by 'pinning' the objects, but pinning objects long term is a bad idea.
>>
>> How about an GC allocation area that isn't searched for valid pointers but is still collected?
>
> Couldn't we use malloc/free + RAII for that? ...auto_ptr<>?
No. The trick is that this area is collected(and updated by a moving GC), but isn't considered while looking for pointers into the "normal" area.
Thomas
|
Copyright © 1999-2021 by the D Language Foundation