17 ms·
The Convergence of Modern C++ on the Lisp Programming Style
- Daishiman 12y agoAt the risk of getting downvoted for what could be a humongous display of ignorance, although the theoretical grounding of the article seems interesting, I fail to see how any of this can get applied to "real-life" applications when this is basically ten pages of content to get to apply this to addition operation and for other problems which are, for most day-to-day practice, already solved quite succintly. Perhaps it's just me, but it seems like an awful lot of conceptual baggage to do things that can be expressed with much greater simplicity and without resorting to concepts that need multiple years of expert knowledge of the language to get this "elegance". And i understand the theoretical elegance, it's just that I have to ask myself if this truly makes an actual difference in code style, simplicity, and clarity of language.
- lisper 12y agoNo, you are exactly right. The C community and its progeny has, over the years, dug itself into a deep, deep syntactic and semantic hole. It is now coming to realize that the Lisp folks had some good ideas after all, but because of the sunk cost fallacy the C folks are unwilling to just back out of the hole. Instead, they keep digging the hole deeper and deeper in the hopes that some day it will emerge into the light. C++11 is interesting in the same way that Brainfuck is interesting: it's remarkable that you can take such a horrible mess and make it do cool things. But it's just a parlor trick, kind of like escaping from a straightjacket while handcuffed. It's challenging, and it requires skill, but at the end of the day you're in the exact same place as if you'd never put the handcuffs and straightjacket on to begin with.
- nickbauman 12y agoHere I was thinking that they finally read the memo.
- hdevalence 12y ago> at the end of the day you're in the exact same place as if you'd never put the handcuffs and straightjacket on to begin with. Do you have any suggestions on what tools the people doing 'parlor tricks' with C++11 should be using to accomplish them, then? That is, what would you suggest to get to that place without the straightjacket? Note that at a bare minimum, these supposed tools should give the ability for fine-grained manual resource control, zero-(runtime)-cost abstractions, and performance roughly on-par with C++. As evidence that these hypothetical tools work well for the purpose, we could look for some complex and high-performance software written in them: say, a browser engine, a 3d engine, a kernel, etc., but wait a minute -- these are all things that tend to be written in C++ or plain C. Instead of glibly dismissing the language that's used to implement, say, every major browser engine, wouldn't it be more productive to ask questions about why people use it? Bonus points if the answer is something more realistic than "They don't know Lisp". That way, you end up trying to figure out how to make a replacement for it that is an actual replacement -- Rust is a fantastically exciting example of this. It'll be great when we can all move away from C++, since it's a colossal clusterfuck of counterproductive complexity, but "C++ is a bad language" misses the point in a really uninteresting kind of way.
- betterunix 12y agoMy best guess about why people are still using C and C++ is this: there is a massive, valuable ecosystem of software written in these languages. It is hard to write software in one language that links with software written in other languages, especially where performance is a concern. The fact that all commonly used commercial OSes are both written in C and expose C APIs has kept C and C++ alive more than anything else. Performance? Lisp can give you that, as can OCaml, Haskell, and other better languages. Real time system? There is a mountain of research on real-time garbage collection and on using HLLs for real-time systems. Operating system kernel? OSes were once written in Lisp, and OSes could conceivably be written in other HLLs. Throw in a requirement to interoperate with a C library and suddenly things get ugly. Yeah, sure, you have an FFI, but debugging across a language barrier is difficult (I have had to do it, it is agony). Suddenly you need to worry about pinning objects so that the garbage collector won't move them while some C library expects them to stay still. In some cases your code basically becomes C but with the syntax of an HLL, and you start to wonder why you did not just write that routine in C to begin with (it would have made your life easier). Performance matters but your compiler needs to set up a trampoline so that your code can provide some kind of callback, and now that is a bottleneck that kills all that other optimization work. Then some joker writes some C++ code, and the rest of your week is spent writing wrapper functions because your FFI cannot deal with the name mangler. At the end of the day there is no particular technical reason for C or C++ to remain so popular, and a big pile of technical reasons to stay away from such languages. C made a bit of sense in the 1970s when computers were small and the understanding of compilers and programming languages was less well developed. At this point C and C++ are a liability that we are all stuck with. Maybe some day the expense of sticking with C and C++ will outweigh the expense required to switch to better languages, but I am not holding my breath.
- jasonzemos 12y agoThe problem I have with this class of critical analogies is that they don't recognize the underlying goal of all this lipstick on the pig. The parlor tricks being done here combine the benefits of other language concepts with the strict efficiency and deterministic overhead of traditional C. Contrast with other languages that might provide a more elegant interface- but with what kind of indirection? And what sacrifices over full-stack control of that indirection? That's why what gets added to the C++ standard -- specifically the philosophy of that process -- has tangible value and purpose that shouldn't be dismissed by simply saying it's better to throw it all away.
- austinz 12y agoTo be fair, the C community doesn't see the relative simplicity of C as a liability, and believes that there's an argument to be made that, in the hands of a competent and careful engineer, C is a good choice of language for certain specific problem domains. There's a related but distinct community that believes that stuffing as many features into their language of choice as possible can only make it better.
- comex 12y agoThat may be true, but the article certainly doesn't prove it. The article repeatedly mentions C++11, but as mentioned elsewhere [1], C++11 has lambdas; even if you want to do the partial binding thing, there is no need for a struct, and obviously a static "add one" function can just be declared as a regular function. So what's the point of the struct declaration other than making C++ look bad? Another sign of the lack of coherence of the article is that it displays unoptimized assembly output for the C++ example, then goes on to praise Lisp for being around as good. The optimal assembly is actually two instructions: 0000000000000000 leal 0x1(%rdi), %eax 0000000000000003 ret Not that it really matters, since it will be inlined into any hot loop in both cases. [1] https://news.ycombinator.com/item?id=7619116 https://news.ycombinator.com/item?id=7619116
- nkurz 12y agoSorry to quibble about details, but doesn't "leal 0x1(%rdi), %eax" actually add one to the address %rdi and not to the contents of (%rdi)? It's usefulness for trick additions is because of its origins as "Load Effective Address": it doesn't actually access memory. Their stack gymnastics are silly, but I think you may be stuck with "mov (%rdi), %eax; add $1, %eax; ret" or some other 3 instruction equivalent.
- pbsd 12y agoYou're right, it does add 1 to RDI, but this is exactly what we want. This is x86_64 calling convention, where arguments come on registers, not the stack. On 32-bit x86 you'd do something like mov eax, 1 add eax, [esp + 4] ret
- piokuc 12y agoAs a Lisp enthusiast who earns a living coding in C++ I can only say one thing: there's still a long way to go for C++. Very long, indeed.
- deleted 12y ago[deleted]
- pbsd 12y agoThe latest revision to the C++ standard, including polymorphic lambdas, makes the xplusone definition much terser: auto xplusone = [](auto x){ return x + 1; }; While at it, here's how Paul Graham's accumulator generator looks in C++14: auto foo = [](auto n){ return [=](auto i) mutable { return n += i; }; }; This does not affect the point of the article in any major way; just a curiosity.
- username223 12y agoThis is just embarrassing. Modern C++ is moving toward intricate types like Haskell, not parser and compiler mods like Lisp.
- AnimalMuppet 12y agoThat's because, despite the article, C++ is not actually trying to become Lisp. And, for all the smug superiority of the Lisp crowd, the niche that C++ is trying to occupy does seem to be significantly bigger than the Lisp niche...
- vinkelhake 12y agoThe terminology appears to be somewhat mixed up. xplusone<int> is not a specializaton, just an instantiation of the template. Specialization is when you tell the compiler to use a separate implementation of a template when some or all of the template arguments match something. Template specialization is used in the type traits section of the post.
- nly 12y agoSaying it's converging on a Lisp is flexing a little bit of artistic license. It's fair to say C++ is becoming increasing accommodating to whatever you want to make of it if you're willing to compromise and roll with it. For sure, it's one of the very best and most practical languages for writing extremely efficient implementations of algorithms. I highly recommend watching Alex Stepanovs A9 lecture series, "Efficient Programming with Components" [0], where he covers the humble min() function, and variants thereof, for at least ~20 hours. During this time he also takes a minor digression in to writing a memory pool for linked-list nodes, while pointing out similarities in the design to a Lisp. It's extremely 'instructive', as he would say, in understanding how he writes C++ code. The sheer amount of code will horrify you, it may even seem unproductive, but I think his objective was really to get everyone thinking about the beauty of the algorithms and the details rather than the objective. His concern for performance, correctness of code, and composition of algorithms is interesting and something I haven't seen presented in real time, in C++, in such a manner before. One example for instance, are occasions where he insists on writing functions backwards, from the return statement up. If you want a higher level overview on his opinions of C++ and programming etc. The less intense series, "Programming Conversations" [1], is worth a more casual watch. [0] https://www.youtube.com/playlist?list=PLHxtyCq_WDLXryyw91lahwdtpZsmo4BGD https://www.youtube.com/playlist?list=PLHxtyCq_WDLXryyw91lah... [1] https://www.youtube.com/playlist?list=PLHxtyCq_WDLXFAEA-lYoRNQIezL_vaSX- https://www.youtube.com/playlist?list=PLHxtyCq_WDLXFAEA-lYoR...
- userbinator 12y ago> It's fair to say C++ is becoming increasing accommodating to whatever you want to make of it if you're willing to compromise and roll with it. It's also one of the few languages in common use that allows using a wide range of abstraction levels, whatever is desired - I'm not aware of any other language that lets you write inline Asm, procedural, OOP, and functional-style code, all conceivably in the same source file.
- betterunix 12y agoNow you are aware of another, Common Lisp (as implemented by SBCL): http://www.sbcl.org/sbcl-internals/index.html http://www.sbcl.org/sbcl-internals/index.html
- reikonomusha 12y agoThis article seems to put Lisp on a bit of a pedestal when it comes to types, but languages like Haskell blow Lisp out of the water with respect to expressiveness. There's also a lot in this article that's plainly implying the wrong things about what Lisp is capable of doing. If we are to talk about types, I'd hope people would look at languages like Haskell or Standard ML—or maybe even ATS, Agda, or Coq—for future direction, not Lisp. Unlike Lisp, C++ lets one write efficient, generic algorithms that can operate on several types of data. Lisp cannot, and falls back to dynamic type testing, which makes for slower code[1]. Basically your only option in Lisp is to specialize everything manually, or inline everything. Both approaches are extremely poor. As I hinted, Haskell and Standard ML do an even better job than both C++ or Lisp. This is talked about a good bit in this article [2]. (Also, for the record, Lisp has no concept of information hiding, interfaces, or APIs. And no, Lisp's packages are just convenient structures for grouping somehow related symbols together.) The article talked about declaring function types in Lisp. Many implementations plainly ignore those and they provide no value. It doesn't help that idiomatic Lisp code usually doesn't include such declarations. Lastly, a lot of the things in this article were SBCL specific, and had little to do with the Lisp language itself. Like others have said, I don't think any points demonstrate that C++ is converging to Lisp. And if it were, that's probably a bad direction anyway, given the author's initial statements about heading toward an algorithmic language. [1] No implementation of Lisp has true, flexible compile-time polymorphism or any type-algebraic structure; all inferred types must be concretely realized during the inference. [2] http://symbo1ics.com/blog/?p=1495 http://symbo1ics.com/blog/?p=1495
- cheez 12y ago> Also, for the record, Lisp has no concept of information hiding, interfaces, or APIs. And no, Lisp's packages are just convenient structures for grouping somehow related symbols together. Dude was talking about Common Lisp which has (IMO) one of the best object-oriented systems in history, from the I-get-so-happy-when-I-can-use-it perspective.
- reikonomusha 12y agoCommon Lisp's object system, CLOS, is indeed a rich and expressive system. But you'll also notice that CLOS does not provide any of the above points. It is an implicit contract between the programmer who developed the code and the programmer consuming the code to (1) not use information that is supposed to be hidden, (2) understand that exported methods are those that make up the "interface" to a class, and (3) understand that the API is that which is written in documentation.
- frozenport 12y agoFeels more like Python because now we have lambdas and I can write auto everywhere.
- adw 12y agoFor someone who wants to learn "modern C++", particularly for number-crunching, without a strong C background (say... someone who develops predictive models who mostly writes Python and Java, not that I resemble that or anything...) – where would be a good place to start?
- en4bz 12y agoBjarne Stroustrup has a new book that came out with the C++11 standard called 'A Tour of C++'. For someone who is just starting I think its a great starting point as it is literally a tour of C++11 (less than 200 pages). It basically gives a very high level overview of everything C++ has to offer as well as some best practices for 'Modern C++'. While it will take a lot more that just this book to get anywhere I think its a good starting point for anyone with experience with other programming languages who want to see what C++ has to offer.
- charlieflowers 12y agoI am not the best person to ask, but probably with Stroustroup's recent book on Modern C++. From what I hear, he discusses the philosophy behind C++ and presents things from the perspective of, "Here's how I suggest you use C++ today." (FWIW, I happen to mostly agree with the comments elsewhere in this thread about C++ being a colossal clusterfuck of complexity ... but still thought I'd answer your question best I could).
- adw 12y agoYeah, I have that suspicion too, and I secretly hope a language like Julia makes all of this moot: but the question I'm trying to find an answer for is "what language should I use for large-scale-but-not-distributed matrix factorization" without giving up and resorting to Fortran.
- iopq 12y agoI wouldn't even bother. Most people just use C for number crunching.
- 12y ago
- laichzeit0 12y agoI last worked with C++ 10 years ago and never looked at it since then, it looks like it's some beast going through various stages of evolution. Perhaps in another 5 or 10 years it will emerge as something beautiful without any vestigial appendages. What's interesting from a language perspective is that the C++ folks seem to take the approach of "ugly is better" by essentially not breaking backwards compatibility like Python 3 and Perl 6 did. The "clean break" approach seems to create a new species and hope that the old one goes extinct (didn't happen with Perl, probably won't). But C++ just keeps evolving.