9 ms·
Functional programming in C (2013)
- vardump 10y agoUgly and unportable code. I can't see practically any benefit. #ifdef __GNUC__ value = c->kind == Volvo ? ({ struct Volvo* it = &c->Volvo; itoa(it->x, temp, 10); }) : c->kind == Ferrari ? (void)c->Ferrari.model, c->Ferrari.brand : c->kind == Fiat ? c->Fiat.model : union_fail("Not a valid car type"); testCar(c, value); #endif // __GNUC__ }
- bluetomcat 10y agoAgreed, "functional" code in C is when you write pure functions with no side effects and nest them like `f(g(h(x)))`. Everything else is an abomination.
- theprotocol 10y agoI love this style. I accidentally "discovered" that pure functions were good through trial and error in my younger days, before I'd looked into functional programming. However, while I'm not necessarily a gigantic fan of functional languages, I think functional principles should be taught to everyone.
- noobermin 10y agoMacros can clean this up a little. Still, all C is ugly.
- bluetomcat 10y agoC can be beautiful if you use it in the way it was intended. Code that mimics OO or functional patterns from other languages is certainly not.
- jonathankoren 10y agoOh god, flashbacks to Gtk+, and it's "objected oriented C". C is the easiest to bind to, and anyway, C++ is just syntactic sugar! Now, let's define class by creating a struct that will hold your vtable and static properties, and another that will hold your instance data... Such bullshit.
- spriggan3 10y agoGtk+ is nice as long as you don't have to define your own classes with GObject . But in that case, there is Vala which compiles to C which makes more sense. To bad this project doesn't get more traction, it's actually well designed and the generated C code is quite readable. I personally prefer Vala to D from a design perspective.
- jonathankoren 10y agoI actually liked Gtk+ when I used it. It's layout managers were easy to use (if Java AWT like), and I rather liked playing with Glade and being able to use scripting languages to build apps. Alas, the greater GNOME attitudes that began to copy the worst aspects of Windows after the fateful (and correct) Sun Microsystems of user experience study in the late 90s of GNOME 1.x [0], which came back with "You literally have five different clocks, including one named 'Another Clock' [1], are asking people to identify video cards by chipset, and have odd settings that are explained solely by acronyms. Get your house in order." to then mean "No options at all!", and the bad copying of the worst ideas of windows to the bad copies of the worst ideas of Apple (e.g. undiscoverable keypresses and file choosers without directory path inputs) turned me off to the whole mess. [0] https://web.archive.org/web/20010725052737/http://developer.gnome.org/projects/gup/ut1_report/summary_recs.html https://web.archive.org/web/20010725052737/http://developer.... [1] http://www.linuxselfhelp.com/gnome/users-guide/clock-applets.html http://www.linuxselfhelp.com/gnome/users-guide/clock-applets...
- arethuza 10y agoWas Gtk+ a descendant of things like Xt Intrinsics? I seem to remember having to work with "object oriented C" in the mid '90s and not liking it at all.
- kbart 10y agoNice experiment, but anyone writing such code in production should get his fingers chopped.
- agumonkey 10y agoWho can write such code will find a way to type without fingers.
- Xophmeister 10y ago$ chgrp sane_c_devs /usr/bin/gcc $ chmod 0770 /usr/bin/gcc Of course, the following scenario is not impossible ;) $ getent group sane_c_devs | cut -d: -f4 | tr , "\n" | wc -l 0
- ricksplat 10y agoSorry, I hope nobody minds a humorous posting (a quote from meet the parents): Dina Byrnes: I had no idea you could milk a cat! Greg Focker: Oh, you can milk just about anything with nipples. Jack Byrnes: [He reacts] I have nipples, Greg, could you milk me?
- Bromskloss 10y ago> I hope nobody minds a humorous posting Not at all. Please go ahead and post it.
- ricksplat 10y agoOkay here goes: > your mom
- PieterH 10y agoOn Windows one compiles C99 code as C++, that's all.
- david-given 10y agoC99 and C++ aren't compatible, unfortunately. For example, C99 designated initialisers aren't in C++ at all, which is a shame as they're fantastically useful: struct foo { int i; double j; }; struct foo f = { .j=9.1, i=4 }; See http://stackoverflow.com/questions/18731707/why-does-c11-not-support-designated-initializer-list-as-c99 http://stackoverflow.com/questions/18731707/why-does-c11-not....
- xvilka 10y agoSince VS2015 MSVC should have most of C99 support already. So there are no reasons to avoid C99 usage nowadays at all.
- xvilka 10y agoMoreover, now you can install just compiler/build tools without Visual Studio: https://blogs.msdn.microsoft.com/vcblog/2016/03/31/announcing-the-official-release-of-the-visual-c-build-tools-2015/ https://blogs.msdn.microsoft.com/vcblog/2016/03/31/announcin...
- pjmlp 10y agoVS2015 MSVC supports C++14, which requires C99 library support, hence why Microsoft updated the support. Likewise MSVC will support C11 libraries when they get around to be fully C++17 compliant. For any newer C standard the official Microsoft position is to use clang with the Visual C++ backend, called C2 which Microsoft is turning into a backend to be shared between clang, Visual C++ and .NET Native.
- norswap 10y agoI wonder how the "discriminated union" thing is better than an enum + a structure for each type + a structure with a field for the discriminator (the enum) and an union of all structures. It certainly is much more readable, and idiomatic. And this doesn't add any benefits that I can see.
- dllthomas 10y agoThat's exactly what it's doing. There's no benefit to using these macros except that it's shorter and maybe (?) therefore clearer.
- jonathankoren 10y agoIt's certainly not clearer if we have to guess.
- dllthomas 10y agoGuess what?
- jonathankoren 10y agoI was wondering that same thing. He's hiding a bunch of stuff behind his lutils.h macros, to make it "literate". Using preprocessor macros to try to create new language constructs is pretty much always Bad News(tm). Almost as bad as using C++ operator overloading to completely change the semantics of an operator. (Bitwise or? Yeah, that's some sort of weirdo automatic function nesting thing now, but only here, and 6 lines down.)
- nathell 10y ago(2013)
- machuidel 10y agoI did the following experiment a while ago (map and flatmap in C): https://gist.github.com/machuidel/d7cc099ddc4970c6ddf4 https://gist.github.com/machuidel/d7cc099ddc4970c6ddf4 By adding more abstractions it should even be possible to support semigroups, monoids etc. Of course this was just for fun.
- pornel 10y agoI'll be that guy who mentions Rust. It's linkable with C. It has first-class support for discriminated unions. Very powerful automatic cleanup. Library of minimal-overhead common data structures. Plus immutability, and a few more things heavily inspired by functional languages. So instead of a bit odd, not-quite-portable C macros I wholeheartedly recommend using a bit odd, not-quite-portable Rust instead.
- kartD 10y agoSeconded, I think Rust is an excellent choice for writing new code in large C code bases. The compiler catches so many memory bugs, I think it's a worth using. I think it'll help more people contribute to open source as well. They're less likely to add new bugs or security risks.
- TickleSteve 10y agoThis is as bad an idea as 'OO' C. having had to deal with the grief that was a late-90s attempt at OO C.... stay away from this. Tooling is designed for idioms of the language. Attempting to be 'clever' means you have to throw away all the benefits of that tooling as well as reducing your maintainability and confusing the optimiser.
- jjnoakes 10y agoPlenty of successful projects use some form of 'OO' C. The Linux kernel is probably one of the most successful. I'm not saying all C programmers should use OO techniques, and I'm not saying all OO programmers should reach for C, but I don't think blanket statements like "OO C is a bad idea" and "stay away from [OO C]" are useful without context (and with context they are almost meaningless).
- TickleSteve 10y agoThe linux kernel is an extremely mild form of OO. Mild to the extent that is effectively idiomatic C code. What I'm referring to is the manual creation of virtual pointer tables and dereferencing everything through it. This completely defeats the optimiser as it can't see thru the pointers. The case I'm referring to was a complete WTF in hindsight.
- jjnoakes 10y agoWhat is the difference between what you are calling virtual pointer tables and what the kernel does in a lot of places? http://lxr.free-electrons.com/source/fs/ext4/symlink.c#L93 http://lxr.free-electrons.com/source/fs/ext4/symlink.c#L93
- TickleSteve 10y agoIts the extent to which it is done. virtual pointer tables are an age-old 'C' mechanism of providing runtime configuration for drivers and such like. the WTF project, took that idea and had virtual pointers for everything methods, data, superclasses, etc. Every line consisted of something like the following: obj->vptr->methodA(obj, objB->vptr->methodB()); it very rapidly becomes a readability and maintainability nightmare.
- jonatack 10y agoI was initially hoping this would be about the book "Functional C" (Hartl & Muller, 1997). https://www.amazon.com/dp/0201419505/ https://www.amazon.com/dp/0201419505/
- toomanythings4 10y agoI know things can go downhill quickly when I read things like this: >There is one irritating thing about C as a viable programming language. Given its history, I don't see where this guy comes from that he can declare whether C is a viable programming language or not. Especially when his real complaint is not about C at all. >Microsoft’s compiler support is not good. While some may complain that I'm making a minor quibble, my point is, when you make statements like this, your credibility falls a notch or twelve and I have to look at the rest of the article with suspicion.
- MichaelGG 10y agoViable in this case means for FP, I'd guess. MS's C compiler support has been crap. In 2013 they didn't have C99 support, right? Just like he says. Even now it seems their C support is driven by the C++ requirement.
- naasking 10y agoI don't like the approach here, and the fact that it's gcc-specific. Many years ago I wrote a small macro library for discriminated unions/sums which I think is much cleaner and looks like actual C [1]. With some fancier variable macros + C11, you can even make closures in C viable [2]. [1] https://github.com/naasking/libsum https://github.com/naasking/libsum [2] Incomplete, but both curried and uncurried closures are possible: https://github.com/naasking/cclosures https://github.com/naasking/cclosures
- pmarreck 10y agoRelated: Here is a really good blog post by John Carmack after forcing himself to code functionally in C++ for a month: http://www.gamasutra.com/view/news/169296/Indepth_Functional_programming_in_C.php http://www.gamasutra.com/view/news/169296/Indepth_Functional... Some really choice quotes in there.
- kartD 10y agoAnd here's one by Jonathan Blow as well (references Carmack's post as well) http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inlined-code.html http://number-none.com/blow/blog/programming/2014/09/26/carm...
- michaelmior 10y agoThis is an interesting idea. For one of the first year programming courses here at UWaterloo, we start by teaching students Racket. To ease them into C, we use a subset we refer to as "functional C."[0] This is really just C with a few restrictions. The main ones are that all "variables" and parameters must be const and all branches of an if statement must return a value. While these restrictions may seem silly to the HN crowd, it leads to an interesting way of thinking about solving problems. [0] https://www.student.cs.uwaterloo.ca/~cs136/handouts/03-functional-c-post.pdf https://www.student.cs.uwaterloo.ca/~cs136/handouts/03-funct...
- jrajav 10y agoInteresting! On the other side of the world, those are precisely the main two restrictions we follow in JavaScript in our React projects right now in order to make our components more functional and predictable. It's amazing how much maintainability mileage you can get out of a few simple rules.
- e12e 10y ago> and all branches of an if statement must return a value. Is indeed a bit strange. I guess I can see the reasoning, though. "const by default" doesn't seem all that unreasonable to me - isn't that one of the major driving forces we're seeing in "new" languages - that based on years of experience, "accidental" mutability should be avoided -- mutability should not be the default? How does this subsetting of C affect the error messages the students are (most) likely to see? Does -Wall typically catch treating a const as mutable? (I assume so, I'm just curious about this, as I'll soon be teaching a beginning programming course - and a sub-set of C might be an interesting option).
- michaelmior 10y agoWe are pretty liberal with the warnings. -Wall will catch trying to mutate const variables. We also use address sanitizer[0] with clang which helps a lot with common memory errors. All this makes the code run (relatively) quite slow but since anything they're testing should complete in a few seconds regardless, it's not a problem for us in practice. [0] http://clang.llvm.org/docs/AddressSanitizer.html http://clang.llvm.org/docs/AddressSanitizer.html
- 0xmohit 10y agoAlso worthwhile mentioning is functionalC [0]. The blog mentioned on the Github page is down but the relevant URLs can be accessed from the wayback machine at [1] and [2]. GCC also supports nested functions [3] (as a GNU C extension). Unrelated, but [4] specifies a pure C implementation of Go channels and libmill [5] is a library that introduces Go-style concurrency to C. [0] https://github.com/cioc/functionalC https://github.com/cioc/functionalC [1] https://web.archive.org/web/20160406001106/http://blog.charlescary.com/?p=95 https://web.archive.org/web/20160406001106/http://blog.charl... [2] https://web.archive.org/web/20160304120857/http://blog.charlescary.com/?p=150 https://web.archive.org/web/20160304120857/http://blog.charl... [3] http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html [4] https://github.com/tylertreat/chan https://github.com/tylertreat/chan [5] https://github.com/sustrik/libmill https://github.com/sustrik/libmill
- rabz 10y agoI'll piggyback on your comment to add another functional version of C to the discussion, Single Assignment C. http://www.sac-home.org http://www.sac-home.org http://en.wikipedia.org/wiki/Single_Assignment_C http://en.wikipedia.org/wiki/Single_Assignment_C
- kensai 10y agoI so much adore the fact that you can do all paradigms with C relatively easily.
- Retra 10y agoI'm confused... what do you mean 'easily'?
- djcb 10y agoIn the same spirit, I wrote some functionally-flavored extensions for GLib a few months back. https://github.com/djcb/gxlib https://github.com/djcb/gxlib, taking a bit of inspiration from Rust and SRFI-1. It's fun to get some of the functional flavor, while still being very near the bare pointers.