After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 672555 - Deprecate lambda functions in libsigc++
Deprecate lambda functions in libsigc++
Status: RESOLVED FIXED
Product: libsigc++
Classification: Bindings
Component: general
2.2.x
Other All
: Normal minor
: ---
Assigned To: libsigc++ maintainer(s)
libsigc++ maintainer(s)
Depends on:
Blocks:
 
 
Reported: 2012-03-21 14:05 UTC by Kjell Ahlstedt
Modified: 2015-07-28 15:20 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
patch: Add SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH for C++11 lambda expressions. (33.30 KB, patch)
2012-07-20 17:45 UTC, Kjell Ahlstedt
committed Details | Review
patch: Add track_obj() and test_track_obj. (26.05 KB, patch)
2013-02-08 13:06 UTC, Kjell Ahlstedt
committed Details | Review
0001-C-11-Avoid-the-need-for-SIGC_FUNCTORS_DEDUCE_RESULT_.patch (10.46 KB, patch)
2015-07-09 21:00 UTC, Murray Cumming
needs-work Details | Review
patch: C++11: Avoid the need for SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE (16.64 KB, patch)
2015-07-12 17:53 UTC, Kjell Ahlstedt
committed Details | Review
0001-Remove-deprecated-sigc-lambda-API-that-is-only-in-he.patch (48.02 KB, patch)
2015-07-14 08:38 UTC, Murray Cumming
none Details | Review

Description Kjell Ahlstedt 2012-03-21 14:05:56 UTC
Lambda functions (anonymous functions, closures) are part of the C++11
standard. When most C++ compilers support those lambda functions, there's
little or no reason to continue using any other type of lambda functions.

I suggest that libsigc++'s lambda functions are deprecated.

Copied from bug 669128 comment 3 by Murray Cumming:

> I'm all for deprecating anything that is now provided by regular C++. It's
> obviously easier to maintain libsigc++ when it is smaller. Any examples or
> tests, if any, would have to be updated to show people how to change their
> code.

The syntax of the standardized C++ lambda functions is very different from
the syntax of libsigc++'s lambda functions.

---- Useful links
Wikipedia:
  http://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B
Bjarne Stroustrup's homepage:
  http://www2.research.att.com/~bs/C++0xFAQ.html#lambda
The C++ Standards Committee:
  http://www.open-std.org/jtc1/sc22/wg21/
  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

n3242.pdf is a draft of the C++11 standard. The approved standards document is
not available for free, only for a fee.
Comment 1 Kjell Ahlstedt 2012-04-01 08:28:40 UTC
There are some posts on libsigc-list showing that some C++11's lambda functions
can't be assigned to a sigc::slot.

http://mail.gnome.org/archives/libsigc-list/2011-July/msg00000.html

There's a long thread on libsigc-list starting at
http://mail.gnome.org/archives/libsigc-list/2011-August/msg00000.html

and continuing at
http://mail.gnome.org/archives/libsigc-list/2012-January/msg00000.html
where there's a suggested solution to the problem.

Here's an interesting comment at the end of the thread:
http://mail.gnome.org/archives/libsigc-list/2012-January/msg00012.html
  "At least one case where the std::class is binary incompatible is std::list,
  which apparently gets a data member added so that size() becomes O(1). This
  change is apparently in GCC 4.7."

This would mean that it's not safe to build a library file with -std=c++98 and
use it in an application built with -std=c++0x or vice versa. (Options as in
gcc 4.6.3.) ABI incompatibility between C++98 and C++11 can be a concern for
all C++ modules (libsigc++, glibmm, gtkmm, etc.) during a transition period of
perhaps a couple of years, before everyone uses only C++11.
Comment 2 Kjell Ahlstedt 2012-07-20 17:45:23 UTC
Created attachment 219339 [details] [review]
patch: Add SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH for C++11 lambda expressions.

This patch adds a preprocessor macro with a template specialization of the
struct sigc::functor_trait. To use this macro you need a compiler which has
the C++11 keyword decltype or a keyword with the same meaning (such as typeof
or __typeof__).

Why not add a configure-time check instead of letting the application
programmer decide whether to use this functionality?

1. The compiler capabilities depend on which options are specified at compile-
   time. E.g. if the libsigc++ library is configured on a system with gcc 4.6.3
   using the default value of option -std, the result of a configure check is
   that decltype is not available. (__typeof__ is available, but I don't know
   about other compilers.) An application program may be compiled with
   -std=c++0x, and then decltype is available.

2. SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH can't be combined with
   SIGC_FUNCTORS_HAVE_RESULT_TYPE. If the functionality in
   SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH is activated by a configure check,
   it will break code that calls the old macro SIGC_FUNCTORS_HAVE_RESULT_TYPE.

The patch also adds some documentation, mentioning that C++11 lambda
expressions are often an alternative to libsigc++'s lambdas, and showing
examples of C++11 lambdas. A test case with C++11 lambdas is added.

This is meant as a preparation for a future deprecation of libsigc++'s
lambdas. It's perhaps too early to deprecate them now. C++11 compilers are
not yet available everywhere.
Comment 3 Kjell Ahlstedt 2012-08-28 17:48:20 UTC
I've pushed the patch in comment 2 with some added comments in
tests/test_cpp11_lambda.cc.
http://git.gnome.org/browse/libsigc++2/commit/?id=41cf46e0fca8128abab298f54209d427a5a6c1b9
Comment 4 Murray Cumming 2012-09-15 12:31:38 UTC
So, in general, the change here is that you can now use C++11 lambda functions if you first add this line?
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(decltype)

What other possible things might someone use there instead of decltype?
Comment 5 Kjell Ahlstedt 2012-09-16 13:15:33 UTC
(In replay to comment #4)
> So, in general, the change here is that you can now use C++11 lambda
> functions if you first add this line?
> SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(decltype)

Yes.

> What other possible things might someone use there instead of decltype?

gcc also understands the keywords typeof and __typeof__ which, I suppose,
preceded the standardized decltype. Other compilers may define the same or
similar non-standard keywords.

Do you think it would be better to ignore all non-standard keywords, and
replace SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(keyword) by
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE?
Is such a replacement allowed as long as SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(
keyword) has not been included in a stable release?
Comment 6 Murray Cumming 2012-09-17 20:10:27 UTC
(In reply to comment #5)
> gcc also understands the keywords typeof and __typeof__ which, I suppose,
> preceded the standardized decltype.

Do we use these normally instead of this new thing?

> Other compilers may define the same or
> similar non-standard keywords.
> 
> Do you think it would be better to ignore all non-standard keywords, and
> replace SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(keyword) by
> SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE?

Well, does anybody want anything else?

> Is such a replacement allowed as long as SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(
> keyword) has not been included in a stable release?

Yes.


I assume that we need this strange macro because later versions of g++ might be used for an app, but libsigc++ might have been built with an earlier ABI-compatible g++ version, so we can't just test for it in the libsigc++ configure, right?
Comment 7 Kjell Ahlstedt 2012-09-19 08:55:28 UTC
(In reply to comment #6)
>> Do you think it would be better to ignore all non-standard keywords, and
>> replace SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(keyword) by
>> SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE?
>
> Well, does anybody want anything else?

I have replaced SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(keyword) by
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE. I see no good reason to start
supporting non-standard keywords, synonymous with decltype.

> I assume that we need this strange macro because later versions of g++ might
> be used for an app, but libsigc++ might have been built with an earlier
> ABI-compatible g++ version, so we can't just test for it in the libsigc++
> configure, right?

Whether the compiler accepts decltype or not may depend on the compiler version
or on the compiler parameters. g++ versions 4.6.3 and 4.7.0 accept decltype
if invoked with the parameter -std=c++0x (or for g++ 4.7.0 -std=c++11).
With the default value of -std (gnu++98), decltype is not accepted.

Let's assume we replace the macro
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE by a configure check.

If libsigc++ is configured with the default value of -std and
--enable-warnings=fatal, a configure check would find that the compiler does
not support decltype. If an application program is compiled with -std=c++11,
it would be possible to use the template class specialization in
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE, but the configure check has
hidden it from the compiler.

It's possible that we can replace
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE by a compile-time check, like in
tests/test_cpp11_lambda.cc. Something like the following code could be put in
sigc++/functors/functor_trait.h.

#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
  Expansion of SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
#endif

An additional problem is that it would break application programs that use the
old macro SIGC_FUNCTORS_HAVE_RESULT_TYPE. Possibly that macro can be changed to
something like

#define SIGC_FUNCTORS_HAVE_RESULT_TYPE \
  #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) \
    // Nothing \
  #else \
    Present expansion of SIGC_FUNCTORS_HAVE_RESULT_TYPE \
  #endif

It's still possible that this trick would break some obscure application
program. SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE does not support
functors with overloaded function call operators, but I think
SIGC_FUNCTORS_HAVE_RESULT_TYPE can do that. (Those are hand-written functors,
not lambda expressions.)

A compile-time check in functor_trait.h instead of a strange macro has its
merits, of course. What do you think? Shall I implement the compile-time check
despite the small risk that it will break some application program?
Comment 8 Kjell Ahlstedt 2013-02-08 13:06:59 UTC
Created attachment 235504 [details] [review]
patch: Add track_obj() and test_track_obj.

The patch contains a new adaptor, track_obj(), that mitigates a disadvantage
of the C++11 lambda expressions. By using track_obj() a slot can be auto-
disconnected, if it contains a C++11 lambda expression that contains a
reference to a sigc::trackable derived object, and the trackable object is
deleted.

It would be great if someone could test it with other compilers than gcc.

If I get no objections within a few weeks or so, I'll push the patch.
Comment 9 Kjell Ahlstedt 2013-02-26 08:44:19 UTC
I have pushed the patch in comment 8 with some insignificant changes.

When is a good time to actually deprecate libsigc++'s lambda expressions?
Now? Soon? I'll ask on libsigc-list too.
Comment 10 Kjell Ahlstedt 2013-03-19 14:31:28 UTC
I have pushed a patch that deprecates everything in directory
sigc++/adaptors/lambda: libsigc++ lambdas, sigc::group() and sigc::var().
https://git.gnome.org/browse/libsigc++2/commit/?id=ec27025f0ec5718c94427ea1fb51e968fba15d9e
Comment 11 Murray Cumming 2015-07-09 20:57:13 UTC
I'd like to do a libsigc++ 2.5/2.6 soon that actually removes them, if nobody objects. It seems to all be in header files, so it will be an API change, not an ABI change.
Comment 12 Murray Cumming 2015-07-09 21:00:15 UTC
Created attachment 307177 [details] [review]
0001-C-11-Avoid-the-need-for-SIGC_FUNCTORS_DEDUCE_RESULT_.patch

Also, if we can know require C++11, can't we avoid the need for the application code to use SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE ? I've tried just turning the macro into a declaration, but make check fails with this patch:

g++ -DHAVE_CONFIG_H   -I.. -I..  -pedantic -Wall -Wextra -Werror -Wall -g -O0 -std=c++11 -MT test_bind_return.o -MD -MP -MF .deps/test_bind_return.Tpo -c -o test_bind_return.o test_bind_return.cc
In file included from ../sigc++/adaptors/adaptor_trait.h:7:0,
                 from ../sigc++/adaptors/bind_return.h:5,
                 from test_bind_return.cc:7:
../sigc++/functors/functor_trait.h: In instantiation of ‘struct sigc::functor_trait<{anonymous}::foo, false>’:
../sigc++/adaptors/adaptor_trait.h:314:58:   required from ‘struct sigc::adaptor_trait<{anonymous}::foo, false>’
../sigc++/adaptors/adaptor_trait.h:388:59:   required from ‘struct sigc::adapts<{anonymous}::foo>’
../sigc++/adaptors/bind_return.h:20:8:   required from ‘struct sigc::bind_return_functor<int, {anonymous}::foo>’
test_bind_return.cc:47:51:   required from here
../sigc++/functors/functor_trait.h:140:88: error: decltype cannot resolve address of overloaded function
   typedef typename functor_trait<decltype(&T_functor::operator()), false>::result_type result_type;
                                                                                        ^
In file included from test_bind_return.cc:7:0:
../sigc++/adaptors/bind_return.h: In instantiation of ‘typename sigc::unwrap_reference<T_type>::type sigc::bind_return_functor<T_return, T_functor>::operator()(T_arg1) [with T_arg1 = int; T_return = int; T_functor = {anonymous}::foo; typename sigc::unwrap_reference<T_type>::type = int]’:
test_bind_return.cc:47:54:   required from here
../sigc++/adaptors/bind_return.h:40:7: error: no matching function for call to ‘sigc::adaptor_functor<{anonymous}::foo>::operator()(int&)’
     { this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<typename type_trait<T_arg1>::pass>
       ^
../sigc++/adaptors/bind_return.h:40:7: note: candidates are:
In file included from ../sigc++/adaptors/bind_return.h:5:0,
                 from test_bind_return.cc:7:
../sigc++/adaptors/adaptor_trait.h:88:3: note: template<class T_arg1> typename sigc::adaptor_functor<T_functor>::deduce_result_type<T_arg1>::type sigc::adaptor_functor<T_functor>::operator()(T_arg1) const [with T_arg1 = T_arg1; T_functor = {anonymous}::foo]
   operator()(T_arg1 _A_arg1) const
   ^
../sigc++/adaptors/adaptor_trait.h:88:3: note:   template argument deduction/substitution failed:
../sigc++/adaptors/adaptor_trait.h:107:3: note: template<class T_arg1, class T_arg2> typename sigc::adaptor_functor<T_functor>::deduce_result_type<T_arg1, T_arg2>::type sigc::adaptor_functor<T_functor>::operator()(T_arg1, T_arg2) const [with T_arg1 = T_arg1; T_arg2 = T_arg2; T_functor = {anonymous}::foo]
   operator()(T_arg1 _A_arg1, T_arg2 _A_arg2) const
   ^
../sigc++/adaptors/adaptor_trait.h:107:3: note:   template argument deduction/substitution failed:
Comment 13 Kjell Ahlstedt 2015-07-10 15:04:10 UTC
Deprecation of libsigc++ lambdas was discussed on libsigc-list in February and
March 2013, starting at https://mail.gnome.org/archives/libsigc-list/2013-February/msg00000.html.

How about a notice on libsigc-list before they are deleted? There will probably
not be much objections.


> Also, if we can know require C++11, can't we avoid the need for the
> application code to use SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE ?
> I've tried just turning the macro into a declaration, but make check fails
> with this patch:

The informative part of the long compiler error message is

  test_bind_return.cc:47:51:   required from here
  ../sigc++/functors/functor_trait.h:140:88: error: decltype cannot resolve
    address of overloaded function
  typedef typename functor_trait<decltype(&T_functor::operator()), false>
    ::result_type result_type;

The foo struct in test_bind_return.cc has overloaded function call operators.

I think it would be difficult or impossible to have the template class
specialization

  template <typename T_functor>
  struct functor_trait<T_functor, false>
  {
    typedef typename functor_trait<decltype(&T_functor::operator()), false>
      ::result_type result_type;
    typedef T_functor functor_type;
  };

defined unconditionally. There are two problems with that, both mentioned in
comments.

1.
Functors with overloaded operator()() are not supported.

2.
You can't use both SIGC_FUNCTORS_HAVE_RESULT_TYPE and
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE in the same compilation unit.

I don't know if anyone uses SIGC_FUNCTORS_HAVE_RESULT_TYPE, except for
libsigc++2/tests/test_compose.cc.
Comment 14 Kjell Ahlstedt 2015-07-12 17:53:19 UTC
Created attachment 307315 [details] [review]
patch: C++11: Avoid the need for SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE

Perhaps it's possible after all. With a new template parameter in
struct functor_trait<> and a new class can_deduce_result_type_with_decltype<>,
it seems to be possible. Both 'make' and 'make check' succeed with g++ 4.9.2.

As far as I can see, the added template parameter in functor_trait<> does not
break ABI. There's no trace of functor_trait in the library files (.so files),
neither in libsigc++ nor in gtkmm.

SFINAE (Substitution Failure Is Not An Error) is a useful but obscure feature
of C++. It tells the compiler to shut up and search for an alternative instead
of reporting a compilation error. The substitution must fail in the
declaration of an overloaded function.
Comment 15 Murray Cumming 2015-07-14 07:52:18 UTC
Great. Would it be simpler if we remove the deprecated code first?
Comment 16 Kjell Ahlstedt 2015-07-14 08:36:54 UTC
It doesn't matter what we do first, apply the patch in comment 14 or remove
the files in sigc++/adaptors/lambda. The patch just changes a few comment lines
in those files.

I have tested the patch with clang++ 3.6.0. No problem.
It would be fine if someone could test it with MSVC++, but even without such a
test. I think it's reasonably safe to push it. I suppose I shall make a
libsigc-2-4 branch before I push it to master.
Comment 17 Murray Cumming 2015-07-14 08:38:22 UTC
Created attachment 307397 [details] [review]
0001-Remove-deprecated-sigc-lambda-API-that-is-only-in-he.patch

This removes as much as (I think) can be removed while still allowing the code in the .cc file to build.
Comment 18 Murray Cumming 2015-07-14 08:39:25 UTC
Sure. Please go ahead. Thanks.
Comment 19 Kjell Ahlstedt 2015-07-14 14:50:42 UTC
Review of attachment 307315 [details] [review]:

Pushed the patch in comment 14.

How do you change the status of an attached patch without at the same time making a new comment?
I could do it before the latest Bugzilla upgrade.
Comment 20 Murray Cumming 2015-07-14 15:01:21 UTC
(In reply to Kjell Ahlstedt from comment #19)
> How do you change the status of an attached patch without at the same time
> making a new comment?
> I could do it before the latest Bugzilla upgrade.

By clicking "Details" next to the patch and then "Edit Details" at the top-right. I always forget how.
Comment 21 Kjell Ahlstedt 2015-07-16 08:12:45 UTC
I played a bit with your patch in comment 17, removing lambda API.
If it weren't for the sigc::_1 .. sigc::_7 objects in lambda.cc, the whole
adaptors/lamba directory could be removed. Probably it can be removed anyway.

sigc::_1 .. sigc::_7 are unusual objects. They have no member data, and all
member functions are templates. The symbols sigc::_1 .. sigc::_7 (with mangled
names) exist in libsigc-2.0.so.0.0.0, but none of them exists in test_lambda or
lt-test_lambda, although sigc::_1 .. sigc::_3 are used in test_lambda.cc.

Test steps:
1. make check
   Result: test_lambda is built and executed. Test passes.
2. Remove sigc++/adaptors/lambda/lambda.cc and references to it in other files.
   make && make install && make test
   Result: test_lambda is built and executed. Test passes.
3. Remove the whole sigc++/adaptors/lambda directory and references to files
   in it (except references from test_lambda.cc).
   Result: test_lambda still executes correctly, but it can't be rebuilt.

Although sigc::_1 .. sigc::_7 exist in the .so file, it's as though they are
not part of the ABI, only part of the API.
Comment 22 Murray Cumming 2015-07-17 10:57:58 UTC
Ah, that's good news. Thanks. I'll get rid of it completely then. If we are wrong then we'll hear about it and can add it back, I guess.
Comment 23 Murray Cumming 2015-07-17 11:18:50 UTC
Done in git master.
Comment 24 Kjell Ahlstedt 2015-07-28 15:20:35 UTC
Lambdas and sigc::group() are mentioned in libsigc++'s website,
http://libsigc.sourceforge.net/.
It looks like libsigc++2/docs/website contains the source of that website.
I don't know how it can be changed. It looks like incomplete html code.
Firefox won't show it. (It does not show libsigc++2/docs/website/index.shtml.
It does show libsigc.sourceforge.net.)