Delegates ,smart pointers and GUI

V

Vincent R

Hi,

I am currently analyzing some GUI architecture and during my research I
found some implementations of delegates(closures) in C++.
Would it be something interesting to use in a GUI framework and in
particular for events ? If not could you give some explanations.


Another question is about smart pointers, I didn't see lots of GUI
frameworks using it ? Is there any reason ? Is it because generally
developpers use easy paradigm and prefers to use traditional methods or
is it more complicated than that?

Thanks
 
P

Phlip

Vincent said:
I am currently analyzing some GUI architecture and during my research I
found some implementations of delegates(closures) in C++.
Would it be something interesting to use in a GUI framework and in
particular for events ? If not could you give some explanations.

Closures absolutely rock for GUIs. Look at Shoes:

http://shoooes.net/tutorial/

Shoes.app {
@push = button "Push me"
@note = para "Nothing pushed so far"

@push.click {
@note.replace "Aha! Click!"
}
}

You don't need a callback or a function pointer or an override to implement the
effect of clicking the button. You just write what you need inside a block.

Expect C++ to get blocks like that any decade now...
Another question is about smart pointers, I didn't see lots of GUI
frameworks using it ? Is there any reason ? Is it because generally
developpers use easy paradigm and prefers to use traditional methods or
is it more complicated than that?

Ogre3d, for example, lets you call 'new' to create a scene element, but when you
add it to the scene object that object assumes ownership, and will destruct the
element for you when it destructs. Because Views are always trees of owned
elements in container relationships. hiding the smart pointers inside the
container objects is more DRY.
 
V

Vincent R

Stefan Ram a écrit :
Thanks for your resources but all I can find describe what exists in
Java/.NET ... and how it works.
What I want is some feddback and experience, not just a theroy that
describes me how it works.
For instance I have found this article :
http://www.codeproject.com/KB/cpp/FastDelegate.aspx

And I wanted to know if it would be relevant to use it.
 
P

Phlip

Vincent said:
Thanks for your resources but all I can find describe what exists in
Java/.NET ... and how it works.
What I want is some feddback and experience, not just a theroy that
describes me how it works.
For instance I have found this article :
http://www.codeproject.com/KB/cpp/FastDelegate.aspx

A system that uses "smart" member function pointers _might_ be called a
"closure". I don't know exactly what the word means!

A member function pointer is really a "smart offset". It stores the location
and type of a member function so you can pick at runtime which one to call
on what object. Such an offset cannot "own" its target, so it can't be
"smart" in the meaning that "smart pointers" use.

The article then procedes to find a use for "delegates" implemented as
member function pointers. I can't read it, because I'm too spoiled by
dynamic languages that make all this plumbing much more easy!

But, yes, in general a View and a Model must decouple and communicate, using
a Controller as the "patch board" between them. Think of the Controller as
an old fashioned telephone operator, using big cords and plugs to finish
calls. The Controller must plug this or that data channel in, so the View
and Model can communicate. If a connection must change at runtime, you need
a pointer to re-point, so I can see how the FastDelegate system can help!

If you insist on writing your GUI in C++!
 
V

Vincent R

Phlip a écrit :
A system that uses "smart" member function pointers _might_ be called a
"closure". I don't know exactly what the word means!

A member function pointer is really a "smart offset". It stores the location
and type of a member function so you can pick at runtime which one to call
on what object. Such an offset cannot "own" its target, so it can't be
"smart" in the meaning that "smart pointers" use.

The article then procedes to find a use for "delegates" implemented as
member function pointers. I can't read it, because I'm too spoiled by
dynamic languages that make all this plumbing much more easy!

But, yes, in general a View and a Model must decouple and communicate, using
a Controller as the "patch board" between them. Think of the Controller as
an old fashioned telephone operator, using big cords and plugs to finish
calls. The Controller must plug this or that data channel in, so the View
and Model can communicate. If a connection must change at runtime, you need
a pointer to re-point, so I can see how the FastDelegate system can help!

If you insist on writing your GUI in C++!

Why are you denigrating C++ if you follow a c++ newsgroup ... ;-)
 
S

Stefan Ram

Phlip said:
A system that uses "smart" member function pointers _might_ be called a
"closure". I don't know exactly what the word means!

A closure is a dynamic function object that contains the
dynamic environment from the time of its creation.

In Pseudo-C++:

int( * )( int const x ) makeinc( int const step )
{ return new int( * )( int const x ){ return x + step; }; }

This is a function, returning another function.
The inner function returned has a reference to a parameter
of the outer function.

We now can call »makeinc« twice to get two »incrementor« functions:

int( *inc0 )( int const x )= makeinc( 0 );
int( *inc1 )( int const x )= makeinc( 1 );

Then,

::std::cout << inc0( 0 )<< '\n';
::std::cout << inc1( 0 )<< '\n';

will print

0
1

. In C++ one can get quite close to closures using function
objects (»functors«): »return new incrementor( step );«.
This is nearly as good as a closure.

What we do not have in C++ are function literals, also known
as anonymous functions as used in the Pseudo-C++ above.

These are another feature than closures, but often languages
either have both or have none of these two features, so that
some people might confuse closures with function literals.

The point of the closure is that the lifetime of the parameters
from each incarnation of »makeinc« is extended to the lifetime
of the closures. Some people say, thus, that closures are
»closed« over their environment: They carry the dynamic
environment from the time of their creation with them.
 
P

Phlip

A closure is a dynamic function object that contains the
dynamic environment from the time of its creation.

In Pseudo-C++:

int( * )( int const x ) makeinc( int const step )
{ return new int( * )( int const x ){ return x + step; }; }

Someone on the Moderated forum just got thru telling me closures _weren't_
that.

Maybe he just had a big Woodrow going for Ruby or something...

(In which language your complete example is like 2 lines of code...)
 
J

James Kanze

I am currently analyzing some GUI architecture and during my
research I found some implementations of delegates(closures)
in C++. Would it be something interesting to use in a GUI
framework and in particular for events ? If not could you give
some explanations.

It would depend on the implementation. C++ doesn't support
closures in the strictest sense; the local stack frame always
ceases to exist when you leave the function. On the other hand,
it's pretty simple to define a class with everything which needs
to remain life, and allocate it dynamically.
Another question is about smart pointers, I didn't see lots of
GUI frameworks using it ? Is there any reason ?

Probably because they create more problems than they solve. Who
"owns" the object is generally quite clear, most pointers are
only used for navigation, and cycles are the rule, not the
exception.
Is it because generally developpers use easy paradigm and
prefers to use traditional methods or is it more complicated
than that?

The basic reason is the same reason you don't use smart pointers
in general. They're good solutions for a few specific problems,
but used systematically, they cause more problems than they
solve, and are symptomatic of bad design. GUI's don't usually
encounter the type of problems smart pointers solve.
 
J

James Kanze

A closure is a dynamic function object that contains the
dynamic environment from the time of its creation.

That's one definition.

Traditionally, at least, a closure automatically includes all
necessary context, extending its lifetime if necessary. In C++,
you can't extend the lifetime of local variables and function
parameters---if your dynamic function object needs them, your
stuck. You have to copy them into the memory you've dynamically
allocated for the closure. Once you've done that, there's
really no difference between what you've done and any other
dynamically allocated object with class type.

The next version of C++ will support lambda expressions;
according to the draft standard, "The evaluation of a
lambda-expression results in a closure object, which is an
rvalue." That "rvalue" bit, however, means that they don't have
the effects on lifetime that one usually expects from a closure.
If you're passing it (by value?) to a function which just uses
it during the function call (an algorithm, for example), fine,
but if the function wants to store its address, for later use
(the usual case for GUI events), it doesn't work.
. In C++ one can get quite close to closures using function
objects (»functors«): »return new incrementor( step );«.
This is nearly as good as a closure.

As long as you don't need any local context (other than for
initialization).
What we do not have in C++ are function literals, also known
as anonymous functions as used in the Pseudo-C++ above.

We will have shortly.
 
J

James Kanze

Someone on the Moderated forum just got thru telling me
closures _weren't_ that.

I suspect that it's like a lot of other things, the exact
definition depends on who's using it. The draft C++ standard
calls its lambda objects "closures". They certainly have some
of the characteristics of a closure---the object encapsulates
the surrounding context, for example. On the other hand, such
lambda objects are "rvalues", whose lifetime ends at the end of
the full expression in which they are created. You don't get
the dynamic extension of lifetime that you get from most other
languages implementing closures.
 
J

James Kanze

Closures absolutely rock for GUIs.

Agreed. Also for some mathematical uses---calling functions
like integrate, for example.
Look at Shoes:

Shoes.app {
@push = button "Push me"
@note = para "Nothing pushed so far"

@push.click {
@note.replace "Aha! Click!"
}
}
You don't need a callback or a function pointer or an override
to implement the effect of clicking the button. You just write
what you need inside a block.
Expect C++ to get blocks like that any decade now...

The current draft for the next version of the C++ standard
includes lambda expressions, which do implement a form of
closures---enough, at least, for use with algorithms. The
problem in the context of a GUI is that they don't extend the
lifetime of anything, so you have to take explicit steps to do
so. It's still not that difficult, however---I do it rather
regularly. It does involve a bit more typing than I'd like,
mainly because of the necessity of creating a constructor to
copy the context I need. (I'm not sure how much the new lambda
expressions will help here. On first reading, they seem fairly
limited, however.)
 
S

SG

The current draft for the next version of the C++ standard
includes lambda expressions, which do implement a form of
closures---enough, at least, for use with algorithms.  The
problem in the context of a GUI is that they don't extend the
lifetime of anything,

You can choose to capture objects by value or by reference to get any
desired behaviour you want. This is probably as general as it could
get. In other (more) high level languages this "extension of life-
time" might be handled by copying "garbage collector controlled"
references to objects. In C++ you could do this by capturing by value
(copying objects, including smart pointers, etc).

IMHO this design is quite flexible. If you know that the function
object won't "espace" (outlive the scope it was created in) it's safe
to use "reference closures". In other cases (i.e. worker thread that
wants to notify the GUI thread) you may want to enqueue
(queue<function<void()>>) function objects which capture some
variables by value.


Cheers!
SG
 
K

KjellKod

Something very similar as 'delegates' are in fact commonly used in C++
(GUI) frameworks.
Check out signals by
Boost (http://www.boost.org/doc/libs/1_38_0/doc/html/signals.html)
and Qt (http://doc.trolltech.com/4.5/signalsandslots.html)

Other not so famous examples but still open source examples of signals
are also available
(KSignals http://kjell.hedstrom.googlepages.com/signalandslots and
SigSlot http://sigslot.sourceforge.net/)

Using signals you have type safe function callback (i.e. similar to
delegate) encapsuled
in signals (and slots) making it easy to use for anyone without
requiring too much information
about how they work in detail.
 
P

Phlip

KjellKod said:
Something very similar as 'delegates' are in fact commonly used in C++
(GUI) frameworks.
Check out signals by
Boost (http://www.boost.org/doc/libs/1_38_0/doc/html/signals.html)
and Qt (http://doc.trolltech.com/4.5/signalsandslots.html)

Signals and slots are not "in C++". Trolltech provides them by adding two new
keywords to C++. You can't do what they did without their language extension.

Oh, and the keywords provide dynamic typing and a kind of closure. Go figure!
 
S

SG

Signals and slots are not "in C++". Trolltech provides them by adding two new
keywords to C++. You can't do what they did without their language extension.

It's my understanding that a similar feature can be more or less
emulated with C++ language features. IIRC, Trolltech didn't do it that
way because they started development early and C++ compilers were not
very mature w.r.t. templates back then.

I'm not much of a GUI programmer but I did check out gtkmm a little
bit. They also have signals and slots but they're implemented as a C++
library.

The only experience with GUI programming I have is with Java/Swing.
The talk about closures reminded of the need to write something like

SwingUtilities.invokeLater(new Runnable(){
public void run() {
// do something
}
});

in Java if you're in another thread and want an action to be performed
in Swing's event loop thread. In C++0x you'd be able to do something
similar:

// called from event loop thread as result of
// a user action, for example
void foo::eek:n_click() {
MyGuiFramework::perform_async(
[] { calculations(); }, // async job
[this] { this->ready(); } // when done
);
}

// called from event loop thread
// (after calculations are complete)
void foo::ready() {
// ...
}

where most of the magic is hidden behind the fictional
"MyGuiFramework::perform_async". This is just one idea that comes to
mind. ;-)


Cheers!
SG
 
B

boltar2003

in Java if you're in another thread and want an action to be performed
in Swing's event loop thread. In C++0x you'd be able to do something
similar:

I don't understand why you'd want threading built into the core C++ language.
Threads are an OS facility with many different attributes across many
different systems. Is the language going to support every single one of
these including low level tweaking or will it just have a common subset
making it useless for anyone who needs something a bit more specialised?

And if its going to support threading natively as opposed to being in
a system library why stop at threads - why not add multiprocess while
they're at it? Perhaps finally Windows could finally get a half decent
implementation of fork()!

B2003
 
S

SG

I don't understand why you'd want threading built into the core C++ language.

I suggested nothing of that kind. MyGuiFramework::perform_async is a
fictional function that just "magically" works. So, it *could* use
some form of OS specific threading library.

If you're working with some GUI framework (typical event loop thingy)
and want to stay responsive while loading a file or computing
something, you *have* to use threads. I'm sure that most of the GUI
toolkits that are available for C++ come with some sort of threading
support and synchronization primitives just for that reason.

By the way, C++0x will support threading directly.

Cheers!
SG
 
K

KjellKod

Signals and slots are not "in C++". Trolltech provides them by adding two new
keywords to C++. You can't do what they did without their language extension.

Actually you CAN. Boost, SigSlot and KSignals are all examples of how
that
can be achieved using normal C++. I haven't checked the Boost
implementation
but SigSlot and KSignals are quite straightforward & easy to
understand.

The reason I mentioned Qt is because they made the FIRST
implementation of
signal-slot,. but it's by far not the only one.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top