Anonymous functions in C
github.comThis is basically a way of obfuscating your C code. If you want to write obfuscated code, C++ has extensive support for this. I think it's actually a strength of C to not have many features. It ultimately makes code more readable and reliable.
I don't think I can agree more with your comment.
C++ in fact is only usable (in a team) if its features are pruned and limited in a team. Really
Throw in some fine preprocessor magic and you'll end up with completely unmaintanable and impossible to understand code.
Yeah. C is a boring language that barely ever changes. But I'm not sure there isn't wisdom in being dull.
Compound literals in C are awesome like it's 1999:
Assuming you have this:
You can do this:struct point { float x, y, z; }; void do_something_with_point(struct point *p);do_something_with_point(&(struct point){.x = 1.5, .y = 1.5, .z = 3.5});You can take the address of a literal?
Being able to specify a literal for a struct is useful. You can, for instance, put the literal in a macro and use the macro to initialize or reset a struct. It's better than having to write additional functions to do something trivial.
Yes, you can. You can use it to create an approximation of named parameters, because struct members that don't have an initializer will default to zero. It's still not nearly as compact as, say, Ruby, but for C it's pretty awesome and fast.
That's interesting. You know you can pass structs by value, too, so I'm not sure how necessary it is to take the address.
It can be useful for an API that expects pointers for whatever reason.
Anonymous functions are a way of de-obfuscating code that is heavy in callbacks. Instead of having the logic flow indirectly to some external method that might be far away, the logic can live within one function body.
Callbacks are inherently going to make a program harder to follow. Without seeing the code, it's hard to suggest other solutions.
Some possible examples include qsort() and iterators. You could also use them for event handlers, but those are probably clearer as separate methods.
I haven't used LambdaPP, but I'm guessing you can get around the lack of closures the same way you do with callbacks, by passing a void* with necessary data.
I'm sure that there are a lot of cases where you could make code look neater and sleeker with this kind of syntax extension, but my thesis -- and this is inherently hard to prove -- is that the uglier code you may have to write in C is nonetheless more robust and maintainable code in the end. A lot of very good software has been written in C, and what I suspect contributes to C's impressive record of robustness is its spare syntax and the fact that there is almost no room for ambiguity and subtle, invisible side effects. What you see is what you get.
Adding simple, inline anonymous functions like these is a fairly modest proposal, of course, and I can't tell you exactly what damage they'd cause. They could turn out harmless. But they are redundant, because C already has a syntax for functions, and that redundancy now forces the programmer to have to make a choice about which syntax to use every time the situation permits them. Reading code becomes a bit more complicated, because there are more kinds of syntactic elements to recognize and know the consequences of. You end up splitting your time between two ways of writing functions, and that works against developing consistent practices and conventions for writing functions.
Is there a trade-off? Probably. It may be too onerous to write some types of code in C, and a little syntactic sugar might be able to make it tractable. But maybe you're better off writing that code in a different language, anyway. C has a good thing going, so why risk messing with it?
...almost no room for ambiguity and subtle, invisible side effects. What you see is what you get. [emphasis mine]
The key word there is "almost." C does have lots of undefined behaviors.
If you don't hedge your statements about programming, you will invariably be wrong. There are always counter-examples.
The kind of ambiguity and side-effects I'm alluding to are ones programming languages explicitly support and encourage, like overloaded operators and overloaded methods in C++. In C, the effects of a segment of code are comparatively predictable just by looking at the code itself. In quite a large number of languages, you can't draw many conclusions about what a segment of code does without looking in multiple other places.
That's neat, but without closures I don't really see how you could do much with it outside of toy examples. Going off the examples -- how often do you write something like a foreach or a map or reduce that doesn't reference its enclosing scope?
As long as the stack frame is still active, the local variables are still alive and valid. So you could pass a local function as a parameter, but you could not return it. I think jwz called these "downward funargs".
GCC supports it http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
GCC's nested functions are implemented with trampolines, so there will be a performance penalty. For the amount that you gain, they seem like a bad idea. Tying your code to GCC for the sake of a small amount of convenience is a bad idea.
With things like PaX the trampoline method won't work, gcc now creates thunks, which are essentially heap allocated thunks of memory (hence the name) with PROT_EXEC.
The question to which I responded did not inquire about performance nor about portability
My comment was about GCC's local functions. It wasn't really about your comment, so I regret if you took it personally.
Thank you. Much respect, sorry if I was harsh.
You could do closure conversion, but then you run into problems with the lifetimes of things, oh and then you're basically reimplementing lisp.
Not really; C++ now has closures and I'm not going to say it's ideal, but it's not that awful either. The whole "reinventing lisp" argument really only applies to macros at this point (ie: something that fundamentally would require a Lisp to do properly), the other features have been scavenged by other languages without being a lisp just fine.
"C++ now has closures and... [they're] not that awful"
Some high praise, that. C++ closures: they're not that awful.
If you look at Redroid (a project which makes extensive use of lambdapp) you'll see how map/list/etc can take advantage of this https://github.com/graphitemaster/redroid hashtable.c and list.c look for [hashtable|list]_foreach. Another good example is config_save in config.c.
A closure is syntactic sugar for a function plus a struct. Sometimes I think they would be a useful addition to C. But these kinds of things never turn out to be as useful as they seem at first.
That's true in a hand-wavey sense, but it ignores that function+struct means you have to define new types, include those types everywhere your closure is used, manage the lifetime and scope of those types, etc. etc.
I would argue the opposite: these things are actually way more useful than they seem at first. The fewer things the language makes you think about, the more you can focus on what you're trying to actually do.
It's true literally.[1] If the language was designed around closures that's one thing. In C, it would be one language paradigm too many.
If you want a language with closures, and all you have is C, the time-honored solution is to write an interpreter and give the interpreted language closures. That is a good way to go.
You wouldn't need full blown closures. Inner procedures that can't escape their scope, like they had in Pascal are already useful but don't come with the extra memory management requirements of closures.
Yeah, those would be nice to have in C.
Anonymous (or inner) functions aren't really valuable per se but syntactic sugar for writing the code into a static function somewhere in the same file: closures give anonymous (or inner) functions the power which is what makes them useful.
If you use clang, blocks are another approach.
[0] http://en.wikipedia.org/wiki/Blocks_(C_language_extension)
The problem with clang blocks is they're represented as a Objective-C object, this makes them unusable in APIs that expect a function pointer, the only way you can cast them to a function pointer is to define the structure which represents the block and mmap executable code pages to marshal the call. Such a library exists that binds them to libffi here https://github.com/mikeash/MABlockClosure This feat alone makes blocks essentially useless unless your entire API is also block-based, as in T (^foo)(...) vs T(*foo)(...).
I don't think they could be an ObjectiveC object, because they're described as C, not ObjectiveC.
I think the problems you're describing are ones that are going to be faced in any attempt at C closures. Closures have memory attached, that's the appeal of them and also the source of all the problems.
Nope, they're an ObjectiveC object with some specialties at the compiler level. Google how they're implemented.
An objective-c object is just a pointer to a struct. You don't need the objective-c runtime to call a block.
Block_copy etc are implemented in libclosure which iirc does not require libobjc either. But of course if you ARE writing objc, they are valid objects and can be treated as such
Correct, the problem is to call the function you cannot treat it as a standard function since it's pointing to a struct, the struct does contain the actual function pointer but there is an implicit `this' first argument to that function pointer which has to be that struct itself. This means you cannot use the block in an API that explicitly requires a function pointer, instead the API must specifically be aware of the block and would need to support it.
Of course, there's no way around that except to write block variants for those functions. stdlib on osx for example has block variants of most functions that take function pointers (`man qsort_b` for an example)
But if you write your program to use blocks from the start, that's not a big problem.
It sounds like you could say it's ObjectiveC-compatible, not ObjectiveC per se. But it's an unimportant distinction.
I thought those were only available on OSX and iOS.
Nope, clang can be used on BSD, Linux, and Windows as well.
I'm aware of that, but do you get blocks?
Eg on Debian: apt-get install libblocksruntime0 libblocksruntime-dev
Indeed, I don't think you do:
http://en.wikipedia.org/wiki/Blocks_(C_language_extension)Blocks are supported for programs developed for Mac OS X 10.6+ and iOS 4.0+,[1] although third-party runtimes allow use on Mac OS X 10.5 and iOS 2.2+.[2]That page does mention Linux in one section: https://en.wikipedia.org/wiki/Blocks_%28C_language_extension...
That's really annoying; the headline claims one thing and the later text clearly contradicts.
Regardless, both of you appear to be correct:
http://compiler-rt.llvm.org/BlocksRuntime - a target-independent implementation of Apple "Blocks" runtime interfaces.
You do, I've used them on Linux myself.
Wondering how a debugger would react to this code?
Lambdapp inserts #line directives into the source code, compilers are required to respect those directives and utilize them when producing debug sections in the binary. For instance in the case of gcc/clang on *nix the compiler will produce .debug_line sections as part of the DWARF debug format. Debuggers like gdb and even valgrind utilize this information to provide correct output. So to answer your question, a debugger would react to this code exactly how it should react, as if the lambda was called via a function and the file / line should be correct.
I'm more asking as in debugger integration with versioning system (p4, git, etc.) - Say you've got a crashdump, and was able to track it down to some specific source code release - now you should've also saved the intermediate generated files somewhere - but this means that these might have to go back in p4/git/svn/etc. or find alternative place for them... Generating them again won't be the same.
Similar problem is with say Qt's generated moc_Xxx source, Ui_xxx source, etc. files - unless you make the effort of storing these generated files somewhere you might have problems debugger later.
This is in general my "arrgh" against code generation, and "aargh" is not against it - it's simply when you had forgot to keep the files somewhere and the crashdump snaps fingers at you...