
Emulating Swift's “defer” in C, with Clang or GCC+Blocks - vuo
http://fdiv.net/2015/10/08/emulating-defer-c
======
Animats
C++ supports this sort of thing directly. It says something about C++ takeup
that anyone would bother adding this kludge to C. Many people are scared of
C++. The language has become incredibly complex.

C++ templates are Turing-complete. You can do arbitrary computation at compile
time. Once this was discovered, ever-fancier templates became a basic part of
C++. (Take a look at the huge templates that implement "max" and "min".) Then
the C++ standards committee went off into template la-la land, focusing on
adding features to make the template system more powerful. After a decade of
this, many standard templates are now at the "you are not supposed to
understand this" level.

This has scared people off of C++, which is why there's still much work in
standard C. So now we're seeing features added to C to solve specific
problems, but without an architecture.

"Defer" is troublesome, because dealing with errors in deferred statements is
hard. C++ has the same problem with destructors. A "with" clause, which LISP
introduce as "with-open-file" and Python also supports, is a better way to do
this. Python's combination of "with" and exception handling can handle an
error when closing out a resource, and get all the nested resources closed out
properly. Few other languages even try to get that right.

~~~
conistonwater
Not touching on the rest of what you said, but what's so bad about min? Apart
from some internal clang stuff, like odd names and macros, it looks okay - I
can see what the function is doing.

    
    
        // min
    
        template <class _Tp, class _Compare>
        inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
        const _Tp&
        min(const _Tp& __a, const _Tp& __b, _Compare __comp)
        {
            return __comp(__b, __a) ? __b : __a;
        }
    
        template <class _Tp>
        inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
        const _Tp&
        min(const _Tp& __a, const _Tp& __b)
        {
            return _VSTD::min(__a, __b, __less<_Tp>());
        }
    
        #ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
    
        template<class _Tp, class _Compare>
        inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
        _Tp
        min(initializer_list<_Tp> __t, _Compare __comp)
        {
            return *__min_element(__t.begin(), __t.end(), __comp);
        }
    
        template<class _Tp>
        inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
        _Tp
        min(initializer_list<_Tp> __t)
        {
            return *__min_element(__t.begin(), __t.end(), __less<_Tp>());
        }
    
        #endif  // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS

~~~
Animats
It used to be

    
    
        #define min(x,y) ((x) < (y) ? (x) : (y))

~~~
pjmlp
Which is anything but safe.

~~~
azinman2
Can you explain more please?

~~~
copascetic
Because a macro in C/C++ is just text expansion, the given implementation will
evaluate its arguments more than once, which will not be obvious at the "call"
site and could have unintended consequences if the expressions have side-
effects.

~~~
azinman2
Is there another way to do it as a macro that avoids this? How do you have
temporary variables potentially in the middle of a larger expression, e.g. if
(min(a,b) == 3) {...}

------
pcwalton
Not the same semantics, as least compared to Golang. This is block-scoped, but
"defer" in Go is function-scoped and has highly dynamic semantics—for example,
call it in a loop and the compiler may not be able to statically prove how
many times it will run.

(Note that, IMO, the semantics of the feature as implemented in the article
are preferable to those of Golang, so I wouldn't personally go to the effort
of trying to duplicate Go's behavior.)

~~~
cthrowappp
Unless I'm mistaken, `__attribute__((cleanup))` is function-, not block-,
scoped. The cleanup attribute is actually declared on the Block, which is kind
of cute.

Instead, I'd suggest just making regular use of `__attribute__((cleanup))` in
C under GCC or Clang and avoiding C blocks entirely. In this case you could do
something like:

    
    
      #define AUTOCLOSE_FILE(n) __attribute__((cleanup(autoclose_file))) n = NULL
      
      void
      autoclose_file(FILE *f)
      {
        if (f)
          fclose(f);
      }
      
      int
      main(...)
      {
        FILE AUTOCLOSE_FILE(*a), AUTOCLOSE_FILE(*b);
      
        a = fopen("foo");
        if (!a)
          return;
    
        b = fopen("bar");
        if (!b)
          return;
      
        ...
      }

------
gorena
This isn't really C, though. It's "Clang C" \- which is arguably better than
C, and I wouldn't want to be stuck writing non-Clang C, but it should be
represented correctly.

~~~
cthrowappp
The headline has since been fixed to mention Clang or GCC with Blocks.

------
vezzy-fnord
The canonical method in C is to jump to a named label which hosts some
functions to unwind/close any open descriptors or operations. As it involves
the use of a goto statement, it drives certain people mad.

I wasn't aware of C Blocks.

~~~
geocar
Clang's blocks produce atrocious code. Look at the disassembly for:

    
    
        int main(){ __block int (^foo)(int x) = ^ int (int x) { if(x<100) return foo(x+10); return x; }; return foo(69); }
    

versus the GCC:

    
    
        int main(){ int foo(int x) { if(x<100) return foo(x+10); return x; }; return foo(69); }
    

if you want to see what I'm talking about.

CLANG: [http://pastebin.com/37A9by4V](http://pastebin.com/37A9by4V)

GCC: [http://pastebin.com/RMEDnwxi](http://pastebin.com/RMEDnwxi)

However, defer does look interesting, and implementing it for GCC is very
easy:

    
    
        #define defer_(x) do{}while(0); \
                auto void _dtor1_##x(); \
                auto void _dtor2_##x(); \
                int __attribute__((cleanup(_dtor2_##x))) _dtorV_##x=69; \
                void _dtor2_##x(){if(_dtorV_##x==42)return _dtor1_##x();};_dtorV_##x=42; \
                void _dtor1_##x()
        #define defer__(x) defer_(x)
        #define defer defer__(__COUNTER__)
    

You don't have to use the stupid block-syntax either, just:

    
    
        in = fopen("whatever", "r");
        defer { fclose(in); }

~~~
raimue
What purpose does the empty do{}while(0); statement serve here?

~~~
gp7
It puts the whole #define code into a single expression so you can do

    
    
      if (cond)
        MACRO;
    

and the macro won't expand incorrectly to

    
    
      if (cond)
        foo;
      bar;
    

I personally just go the anal retentive route and use brackets everywhere.

~~~
cthrowappp
Not in this case it doesn't.

------
plorkyeran
`defer` in a nonstandard extension to C implemented by a single compiler.

~~~
micampe
I like how Hacker News is all about exploring new things and playing with
technology.

~~~
duaneb
I don't think that hacker news is all about one thing.

Furthermore, it's fun to play with this, but it is undeniably not c. If you
have access to clang everywhere (or gcc w/ blocks) and you're OK with the
tradeoffs, have at it. :)

------
pjmlp
If it is not available in the ISO/IEC 9899 ANSI C document, it is not C.

