This 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.
Interesting! 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.
> 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).
We 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.
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.
Seconded, 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.
Agreed, "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.
I 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.
Oh 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...
Gtk+ 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.
I 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.
Was 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.
I've looked somewhat at both, and my impression is that Gtk+ tried to do a similar thing as the Xt Intrinsics, but didn't do it in a really better way.
The problem with both is that you still have to write a lot of boilerplate by hand. Of the Xt Intrinsics I know that the things you could do with it were pretty advanced for their time, just too much annoying work.
What the Gtk+ people should have done is design some nice notation for objects and generate the Xt Intrinsics object boilerplate from that. Or in fact that should have been done soon after creating Xt.
The way it was intended? You mean by K&R? Seems like you are making a subjective judgement because I hardly doubt the majority of C hackers use C "as it was intended" in 1973.
I'll postfix this by saying I actually don't consider the code snippet as ugly but that's because I like C. Most people consider C ugly because they use stuff like Python or C++ which hides some details. Macros can hide details too, they are just difficult to use. Therefore, for most people C will always be "ugly", but then again, beauty is in the eye of the beholder.
I've noticed a lot of people like to end their types in _t, maybe because it looks cool, but POSIX actually says all those names are reserved for the system. Oh well.
I too hate typedef except for integer/FP types where the new name would carry semantics, like, for example, `pid_t` or `time_t`.
`point_t` instead of `struct point`, `color_t` instead of `enum color` or worse, `pint` instead of `int *` is stinky because it hides the actual operations which are only applicable to a struct, an enum, or a pointer, respectively.
I 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].
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.
Plenty 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).
The 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.
So based on one project's misuse of a technique (OO in C) you dismissed it as "bad" idea, "stay away from this", it's "attempting to be clever", and the rest?
I think that's why I'm not following you. You've dismissed OO in C in its entirety, and advised others to do the same, based on your experience in one project which misused/overused the feature.
You've said it is a bad technique no matter how it is used, and you have said it is an ok technique if used at some levels (like the Kernel) but not others (like the WTF project).
So you can see how I'm confused about what your opinion really is, I hope.
In the same spirit, I wrote some functionally-flavored extensions for GLib a few months back. 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.
I 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.
I 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.)
I 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.
Viable 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.
VS2015 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.
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-funct...