www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Thin delegate adapter

reply Guilherme Vieira <n2.nitrogen gmail.com> writes:
Hi,

I'm wondering if a delegate adapter template like isn't handy for Phobos (it
may be especially useful for std.signal):

class Switch
{
    enum State { ON, OFF }

    void trigger()
    {
        switch (mState)
        {
            case State.ON: mState = State.OFF; break;
            case State.OFF: mState = State.ON; break;
            default: break;
        }

        if (watch !is null) watch(mState);
    }

    void delegate(State s) watch;

    private State mState;
}

class ToggleButton
{
     property toggled(bool toggled)
    {
        writeln("ToggleButton.toggled(", toggled, ")");
    }
}

void main()
{
    scope s = new Switch();
    scope b = new ToggleButton();

    s.watch = &b.toggled; // error: invalid conversion
    s.watch = adapt!("obj.toggled = cast(bool)(a)", Switch.State)(b);

    s.trigger(); // prints `ToggleButton.toggled(true)`
    s.trigger(); // prints `ToggleButton.toggled(false)`
    s.trigger(); // prints `ToggleButton.toggled(true)`
    s.trigger(); // prints `ToggleButton.toggled(false)`
}


Yes, it urges to be polished. Particularly, it doesn't support multiple
arguments. I also wanted to place the argument type tuple somwhere else
(actually wanted to hide it completely, but I think that's not possible).

Feedback?

-- 
Atenciosamente / Sincerely,
Guilherme ("n2liquid") Vieira
Jan 12 2011
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 12.01.2011 15:41, Guilherme Vieira wrote:
 Hi,

 I'm wondering if a delegate adapter template like isn't handy for 
 Phobos (it may be especially useful for std.signal):

     class Switch
     {
         enum State { ON, OFF }

         void trigger()
         {
             switch (mState)
             {
                 case State.ON: mState = State..OFF; break;
                 case State.OFF: mState = State.ON; break;
                 default: break;
             }

             if (watch !is null) watch(mState);
         }

         void delegate(State s) watch;

         private State mState;
     }

     class ToggleButton
     {
          property toggled(bool toggled)
         {
             writeln("ToggleButton.toggled(", toggled, ")");
         }
     }

     void main()
     {
         scope s = new Switch();
         scope b = new ToggleButton();

         s.watch = &b.toggled; // error: invalid conversion
         s.watch = adapt!("obj.toggled = cast(bool)(a)", Switch.State)(b);

         s.trigger(); // prints `ToggleButton.toggled(true)`
         s.trigger(); // prints `ToggleButton.toggled(false)`
         s.trigger(); // prints `ToggleButton.toggled(true)`
         s.trigger(); // prints `ToggleButton.toggled(false)`
     }


 Yes, it urges to be polished. Particularly, it doesn't support 
 multiple arguments. I also wanted to place the argument type tuple 
 somwhere else (actually wanted to hide it completely, but I think 
 that's not possible).

 Feedback?

 -- 
 Atenciosamente / Sincerely,
 Guilherme ("n2liquid") Vieira
How is it better then built-in language feature? This works just fine: void main() { //they can't be scope and compiler enforces this (+ scope is deprecated) //actually, the orignal code is unsafe - what hapens if adapted delegate escapes current scope? auto s = new Switch(); auto b = new ToggleButton(); s.watch = (Switch.State a){ b.toggled = cast(bool)a; }; s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } -- Dmitry Olshansky
Jan 12 2011
parent reply Guilherme Vieira <n2.nitrogen gmail.com> writes:
Ah, I totally missed that. But what if `s' went out of the scope and the
scope ended? Wouldn't the scope reference (the one containing `b') be lost
and cause memory corruption?

E.g.:

Switch make_switch()
{
    auto s = new Switch();
    auto b = new ToggleButton();

    s.watch = (Switch.State state) { b.toggled = cast(bool)(state); };


    return s;
}


-- 
Atenciosamente / Sincerely,
Guilherme ("n2liquid") Vieira

On Wed, Jan 12, 2011 at 10:57 AM, Dmitry Olshansky <dmitry.olsh gmail.com>wrote:

 On 12.01.2011 15:41, Guilherme Vieira wrote:

 Hi,

 I'm wondering if a delegate adapter template like isn't handy for Phobos
 (it may be especially useful for std.signal):

    class Switch
    {
        enum State { ON, OFF }

        void trigger()
        {
            switch (mState)
            {
                case State.ON: mState = State..OFF; break;
                case State.OFF: mState = State.ON; break;
                default: break;
            }

            if (watch !is null) watch(mState);
        }

        void delegate(State s) watch;

        private State mState;
    }

    class ToggleButton
    {
         property toggled(bool toggled)
        {
            writeln("ToggleButton.toggled(", toggled, ")");
        }
    }

    void main()
    {
        scope s = new Switch();
        scope b = new ToggleButton();

        s.watch = &b.toggled; // error: invalid conversion
        s.watch = adapt!("obj.toggled = cast(bool)(a)", Switch.State)(b);

        s.trigger(); // prints `ToggleButton.toggled(true)`
        s.trigger(); // prints `ToggleButton.toggled(false)`
        s.trigger(); // prints `ToggleButton.toggled(true)`
        s.trigger(); // prints `ToggleButton.toggled(false)`
    }


 Yes, it urges to be polished. Particularly, it doesn't support multiple
 arguments. I also wanted to place the argument type tuple somwhere else
 (actually wanted to hide it completely, but I think that's not possible).

 Feedback?

 --
 Atenciosamente / Sincerely,
 Guilherme ("n2liquid") Vieira
How is it better then built-in language feature? This works just fine: void main() { //they can't be scope and compiler enforces this (+ scope is deprecated) //actually, the orignal code is unsafe - what hapens if adapted delegate escapes current scope? auto s = new Switch(); auto b = new ToggleButton(); s.watch = (Switch.State a){ b.toggled = cast(bool)a; }; s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } -- Dmitry Olshansky
Jan 12 2011
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 12.01.2011 16:07, Guilherme Vieira wrote:
 Ah, I totally missed that. But what if `s' went out of the scope and 
 the scope ended? Wouldn't the scope reference (the one containing `b') 
 be lost and cause memory corruption?

 E.g.:

     Switch make_switch()
     {
         auto s = new Switch();
         auto b = new ToggleButton();

         s.watch = (Switch.State state) { b.toggled = cast(bool)(state); };


         return s;
     }
That's the main point of built-in delegates - the compiler detects them and places the enclosing stack frame on heap, so it's all sort of cool magic that just works :)
 -- 
 Atenciosamente / Sincerely,
 Guilherme ("n2liquid") Vieira

 On Wed, Jan 12, 2011 at 10:57 AM, Dmitry Olshansky 
 <dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>> wrote:

     On 12.01.2011 15:41, Guilherme Vieira wrote:

         Hi,

         I'm wondering if a delegate adapter template like isn't handy
         for Phobos (it may be especially useful for std.signal):

            class Switch
            {
                enum State { ON, OFF }

                void trigger()
                {
                    switch (mState)
                    {
                        case State.ON: mState = State..OFF; break;
                        case State.OFF: mState = State.ON; break;
                        default: break;
                    }

                    if (watch !is null) watch(mState);
                }

                void delegate(State s) watch;

                private State mState;
            }

            class ToggleButton
            {
                 property toggled(bool toggled)
                {
                    writeln("ToggleButton.toggled(", toggled, ")");
                }
            }

            void main()
            {
                scope s = new Switch();
                scope b = new ToggleButton();

                s.watch = &b.toggled; // error: invalid conversion
                s.watch = adapt!("obj.toggled = cast(bool)(a)",
         Switch.State)(b);

                s.trigger(); // prints `ToggleButton.toggled(true)`
                s.trigger(); // prints `ToggleButton.toggled(false)`
                s.trigger(); // prints `ToggleButton.toggled(true)`
                s.trigger(); // prints `ToggleButton.toggled(false)`
            }


         Yes, it urges to be polished. Particularly, it doesn't support
         multiple arguments. I also wanted to place the argument type
         tuple somwhere else (actually wanted to hide it completely,
         but I think that's not possible).

         Feedback?

         -- 
         Atenciosamente / Sincerely,
         Guilherme ("n2liquid") Vieira

     How is it better then built-in language feature? This works just fine:
        void main()
        {
     //they can't be scope  and compiler enforces this (+ scope is
     deprecated)
     //actually, the orignal code is unsafe - what hapens if adapted
     delegate escapes current scope?
            auto s = new Switch();
            auto b = new ToggleButton();


            s.watch = (Switch.State a){ b.toggled = cast(bool)a; };

            s.trigger(); // prints `ToggleButton.toggled(true)`
            s.trigger(); // prints `ToggleButton.toggled(false)`
            s.trigger(); // prints `ToggleButton.toggled(true)`
            s.trigger(); // prints `ToggleButton.toggled(false)`
        }

     -- 
     Dmitry Olshansky
-- Dmitry Olshansky
Jan 12 2011
parent reply Guilherme Vieira <n2.nitrogen gmail.com> writes:
No sh*t..?!  __  That's so cool! But is it smart enough to know the stack
frame doesn't need to go to heap in this case? (since it returns a heap
object referecing another heap object, i.e. can it untangle `b' from the
stack?)

-- 
Atenciosamente / Sincerely,
Guilherme ("n2liquid") Vieira


On Wed, Jan 12, 2011 at 11:49 AM, Dmitry Olshansky <dmitry.olsh gmail.com>wrote:

 On 12.01.2011 16:07, Guilherme Vieira wrote:

 Ah, I totally missed that. But what if `s' went out of the scope and the
 scope ended? Wouldn't the scope reference (the one containing `b') be lost
 and cause memory corruption?

 E.g.:

    Switch make_switch()
    {
        auto s = new Switch();
        auto b = new ToggleButton();

        s.watch = (Switch.State state) { b.toggled = cast(bool)(state); };


        return s;
    }


  That's the main point of built-in delegates - the compiler detects them
and places the enclosing stack frame on heap, so it's all sort of cool magic that just works :)
 --
 Atenciosamente / Sincerely,
 Guilherme ("n2liquid") Vieira

 On Wed, Jan 12, 2011 at 10:57 AM, Dmitry Olshansky
<dmitry.olsh gmail.com<mailto:
 dmitry.olsh gmail.com>> wrote:

    On 12.01.2011 15:41, Guilherme Vieira wrote:

        Hi,

        I'm wondering if a delegate adapter template like isn't handy
        for Phobos (it may be especially useful for std.signal):

           class Switch
           {
               enum State { ON, OFF }

               void trigger()
               {
                   switch (mState)
                   {
                       case State.ON: mState = State..OFF; break;
                       case State.OFF: mState = State.ON; break;
                       default: break;
                   }

                   if (watch !is null) watch(mState);
               }

               void delegate(State s) watch;

               private State mState;
           }

           class ToggleButton
           {
                property toggled(bool toggled)
               {
                   writeln("ToggleButton.toggled(", toggled, ")");
               }
           }

           void main()
           {
               scope s = new Switch();
               scope b = new ToggleButton();

               s.watch = &b.toggled; // error: invalid conversion
               s.watch = adapt!("obj.toggled = cast(bool)(a)",
        Switch.State)(b);

               s.trigger(); // prints `ToggleButton.toggled(true)`
               s.trigger(); // prints `ToggleButton.toggled(false)`
               s.trigger(); // prints `ToggleButton.toggled(true)`
               s.trigger(); // prints `ToggleButton.toggled(false)`
           }


        Yes, it urges to be polished. Particularly, it doesn't support
        multiple arguments. I also wanted to place the argument type
        tuple somwhere else (actually wanted to hide it completely,
        but I think that's not possible).

        Feedback?

        --         Atenciosamente / Sincerely,
        Guilherme ("n2liquid") Vieira

    How is it better then built-in language feature? This works just fine:
       void main()
       {
    //they can't be scope  and compiler enforces this (+ scope is
    deprecated)
    //actually, the orignal code is unsafe - what hapens if adapted
    delegate escapes current scope?
           auto s = new Switch();
           auto b = new ToggleButton();


           s.watch = (Switch.State a){ b.toggled = cast(bool)a; };

           s.trigger(); // prints `ToggleButton.toggled(true)`
           s.trigger(); // prints `ToggleButton.toggled(false)`
           s.trigger(); // prints `ToggleButton.toggled(true)`
           s.trigger(); // prints `ToggleButton.toggled(false)`
       }

    --     Dmitry Olshansky
-- Dmitry Olshansky
Jan 12 2011
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 13.01.2011 2:16, Guilherme Vieira wrote:
 No sh*t..?!  __  That's so cool! But is it smart enough to know the 
 stack frame doesn't need to go to heap in this case? (since it returns 
 a heap object referecing another heap object, i.e. can it untangle `b' 
 from the stack?)
Ehm, it can optimize certain cases but for the moment it doesn't. Still, it needs to store b somewhere, right? and delegate is 2 pointers in fact, so b should go on heap anyway. So it narrows down to if it can save only parts of the stack frame ...
 -- 
 Atenciosamente / Sincerely,
 Guilherme ("n2liquid") Vieira


 On Wed, Jan 12, 2011 at 11:49 AM, Dmitry Olshansky 
 <dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>> wrote:

     On 12.01.2011 16:07, Guilherme Vieira wrote:

         Ah, I totally missed that. But what if `s' went out of the
         scope and the scope ended? Wouldn't the scope reference (the
         one containing `b') be lost and cause memory corruption?

         E.g.:

            Switch make_switch()
            {
                auto s = new Switch();
                auto b = new ToggleButton();

                s.watch = (Switch.State state) { b.toggled =
         cast(bool)(state); };


                return s;
            }


     That's the main point of built-in delegates - the compiler detects
     them and places the enclosing stack frame on heap, so it's all
     sort of cool magic that just works :)

         -- 
         Atenciosamente / Sincerely,
         Guilherme ("n2liquid") Vieira

         On Wed, Jan 12, 2011 at 10:57 AM, Dmitry Olshansky
         <dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>
         <mailto:dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>>>
         wrote:

            On 12.01.2011 15:41, Guilherme Vieira wrote:

                Hi,

                I'm wondering if a delegate adapter template like isn't
         handy
                for Phobos (it may be especially useful for std.signal):

                   class Switch
                   {
                       enum State { ON, OFF }

                       void trigger()
                       {
                           switch (mState)
                           {
                               case State.ON: mState = State..OFF; break;
                               case State.OFF: mState = State.ON; break;
                               default: break;
                           }

                           if (watch !is null) watch(mState);
                       }

                       void delegate(State s) watch;

                       private State mState;
                   }

                   class ToggleButton
                   {
                        property toggled(bool toggled)
                       {
                           writeln("ToggleButton.toggled(", toggled, ")");
                       }
                   }

                   void main()
                   {
                       scope s = new Switch();
                       scope b = new ToggleButton();

                       s.watch = &b.toggled; // error: invalid conversion
                       s.watch = adapt!("obj.toggled = cast(bool)(a)",
                Switch.State)(b);

                       s.trigger(); // prints `ToggleButton.toggled(true)`
                       s.trigger(); // prints `ToggleButton.toggled(false)`
                       s.trigger(); // prints `ToggleButton.toggled(true)`
                       s.trigger(); // prints `ToggleButton.toggled(false)`
                   }


                Yes, it urges to be polished. Particularly, it doesn't
         support
                multiple arguments. I also wanted to place the argument
         type
                tuple somwhere else (actually wanted to hide it completely,
                but I think that's not possible).

                Feedback?

                --         Atenciosamente / Sincerely,
                Guilherme ("n2liquid") Vieira

            How is it better then built-in language feature? This works
         just fine:
               void main()
               {
            //they can't be scope  and compiler enforces this (+ scope is
            deprecated)
            //actually, the orignal code is unsafe - what hapens if adapted
            delegate escapes current scope?
                   auto s = new Switch();
                   auto b = new ToggleButton();


                   s.watch = (Switch.State a){ b.toggled = cast(bool)a; };

                   s.trigger(); // prints `ToggleButton.toggled(true)`
                   s.trigger(); // prints `ToggleButton.toggled(false)`
                   s.trigger(); // prints `ToggleButton.toggled(true)`
                   s.trigger(); // prints `ToggleButton.toggled(false)`
               }

            --     Dmitry Olshansky



     -- 
     Dmitry Olshansky
-- Dmitry Olshansky
Jan 12 2011
parent Guilherme Vieira <n2.nitrogen gmail.com> writes:
On Thu, Jan 13, 2011 at 5:30 AM, Dmitry Olshansky <dmitry.olsh gmail.com>wrote:

 On 13.01.2011 2:16, Guilherme Vieira wrote:

 No sh*t..?!  __  That's so cool! But is it smart enough to know the stack
 frame doesn't need to go to heap in this case? (since it returns a heap
 object referecing another heap object, i.e. can it untangle `b' from the
 stack?)
Ehm, it can optimize certain cases but for the moment it doesn't. Still, it needs to store b somewhere, right? and delegate is 2 pointers in fact, so b should go on heap anyway. So it narrows down to if it can save only parts of the stack frame ...
Since it only uses something the size of a pointer (`b'), it might as well do some trickery and use `b' as `this' and turn the delegate into (Switch.State state) { this.toggled = cast(bool)(state); } (or something of similar effect). -- Atenciosamente / Sincerely, Guilherme ("n2liquid") Vieira
Jan 14 2011