Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I was reading the article here: http://www.paulgraham.com/avg.html and the part about the "blub paradox" was particularly interesting. As someone who mainly codes in c++ but has exposure to other languages (mostly Haskell) I'm aware of a few useful things in these languages that are hard to replicate in c++. The question is mainly to people who are proficient in both c++ and some other language, is there some powerful language feature or idiom that you make use of in a language that would be hard to conceptualize or implement if you were writing only in c++?

In particular this quote caught my attention:

By induction, the only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one. (This is probably what Eric Raymond meant about Lisp making you a better programmer.) You can't trust the opinions of the others, because of the Blub paradox: they're satisfied with whatever language they happen to use, because it dictates the way they think about programs.

If it turns out that I am the equivalent of the "Blub" programmer by virtue of using c++ this raises the following question: Are there any useful concepts or techniques that you have encountered in other languages that you would have found difficult to conceptualize had you been writing or "thinking" in c++?

For example the logic programming paradigm seen in languages like Prolog and Mercury can be implemented in c++ using the castor library but ultimately I find that conceptually I am thinking in terms of Prolog code and translating to the c++ equivalent when using this. As a way of broadening my programming knowledge I'm trying to find out if there are other similar examples of useful/powerful idioms that are more efficiently expressed in other languages that I might not be aware of as a c++ developer. Another example that comes to mind is the macro system in lisp, generating the program code from within the program seems to have many benefits for some problems. This seems to be hard to implement and think about from within c++.

EDIT: This question is not intended to be a "c++ vs lisp" debate or any sort of language-wars type debate. Asking a question like this is the only way I can see possible to find out about things that I don't know I don't know about.

share|improve this question

migrated from stackoverflow.com May 10 '11 at 5:18

This question came from our site for professional and enthusiast programmers.

13  
Why on Earth do you want to close this question? There's nothing wrong with it! It's a good question, it's interesting, it's fun, it brings insight. Are you scared of any of these? –  wilhelmtell May 10 '11 at 4:04
2  
I voted to close it because it's a better fit for Programmers SE, not SO. –  JUST MY correct OPINION May 10 '11 at 4:20
4  
To the people voting for a close, can you please give some reasons why? –  shuttle87 May 10 '11 at 4:23
3  
I wholeheartedly hate this blind deletionism. Very much like wikipedia. Did it work for them? –  Tamás Szelei May 10 '11 at 8:57
2  
@Tamás - well, they are the #7 website in the world for traffic, so yes, I would actually say that it has been working very well for them indeed. –  Carson63000 May 10 '11 at 11:05

8 Answers 8

Well, since you mentioned Haskell:

  1. Pattern Matching. I find pattern matching to be much easier to read and write. Consider the definition of map and think about how it would be implemented in a language without pattern matching.

    map :: (a -> b) -> [a] -> [b]
    map f [] = []
    map f (x:xs) = f x : map f xs
    
  2. The type system. It can be a pain sometimes but it is extremely helpful. You have to program with it to really understand it and how many bugs it catches. Also, referential transparency is wonderful. It only becomes apparent after programming in Haskell for a while how many bugs are caused by managing state in an imperative language.

  3. Functional programming in general. Using maps and folds instead of iteration. Recursion. It's about thinking at a higher level.

  4. Lazy evaluation. Again it's about thinking at a higher level and letting the system handle evaluation.

  5. Cabal, packages, and modules. Having Cabal download packages for me is much more convenient than finding source code, writing a makefile, etc. Being able to import only certain names is much better than essentially having all the source files dumped together then compiled.

Edit: formatting

share|improve this answer
1  
A note on pattern matching: I wouldnt say its easier to write in general, but after you read a bit on the expression problem it becomes clear that things like if and switch statements, enums and the observer pattern are all inferior implementations of Algebraic Data Types + Pattern Matching. (And lets not even get started on how Maybe makes null pointer exceptions obsolete) –  hugomg May 22 '12 at 19:44
    
What you say is true, but the expression problem is about limitations of algebraic data types (and about the dual limitations of standard OOP). –  Blaisorblade Oct 28 '13 at 0:15

C++ is a multiparadigm language, which means it tries to support many ways of thinking. Sometimes a C++ feature is more awkward or less fluent than another language's implementation, as is the case with functional programming.

That said, I can't think off the top of my head of a native C++ language feature that does what yield in Python or JavaScript does.

Another example is concurrent programming. C++0x will have a say about it, but the current standard doesn't, and concurrency is a whole new way of thinking.

Also, rapid development -- even shell programming -- is something you'll never learn if you never leave the domain of C++ programming.

share|improve this answer
    
I can't even begin to think how difficult it would be to create generators in C++ given C++2003. C++2011 would make it easier, but still non-trivial. Working routinely with C++, C# and Python, generators are easily the easily the feature I miss the most in C++ (now that C++2011 has added lambdas). –  Nathan Ernst May 10 '11 at 4:12
    
I know I'll get shot for this, but if I absolutely had to implement generators in C++, I'd have to use ... setjmp and longjmp. I have no idea how much that breaks, but I guess exceptions would be the first to go. Now, if you'll excuse me, I need to go reread Modern C++ Design to get that out of my head. –  Mike DeSimone May 10 '11 at 4:29
    
@Mike DeSimone, can you elaborate (breifly) on how you'd attempt a solution with setjmp and longjmp? –  shuttle87 May 10 '11 at 4:47
1  
Coroutines are isomorphic to functors. –  GManNickG May 10 '11 at 4:55
1  
@Xeo, @Mike: xkcd.com/292 –  Mehrdad May 10 '11 at 6:05

Memoize!

Try writing it in C++. Not with C++0x.

Too cumbersome? Okay, try it with C++0x.

See if you can beat this 4-line (or 5-line, whatever :P) compile-time version in D:

auto memoize(alias Fn, T...)(T args) {
    auto key = tuple(args);                               //Key is all the args
    static typeof(Fn(args))[typeof(key)] cache;           //Hashtable!
    return key in cache ? cache[key] : (cache[key] = Fn(args));
}

All you need to do for calling it is something like:

int fib(int n) { return n > 1 ? memoize!(fib)(n - 1) + memoize!(fib)(n - 2) : 1;}
fib(60);

You can also try something similar in Scheme, although it's a bit slower because it happens at run time and because the lookup here is linear instead of hashed (and well, because it's Scheme):

(define (memoize f)
    (let ((table (list)))
        (lambda args
            (cdr
                (or (assoc args table)
                    (let ((entry (cons args (apply f args))))
                        (set! table (cons entry table))
                        entry))))))
(define (fib n)
        (if (<= n 1)
            1
            (+ (fib (1- n))
                (fib (- n 2)))))))
(set! fib (memoize fib))
share|improve this answer
1  
So you love APL where you can write anything in a single line? Size doesn't matter! –  Bo Persson May 10 '11 at 7:13
    
@Bo: I haven't used APL. I'm not sure what you mean by "size doesn't matter", but is there something wrong with my code that makes you say that? And is there some advantage to how you would do this in a different language (like C++) that I'm not aware of? (I edited the variable names a bit, in case that was what you were referring to.) –  Mehrdad May 10 '11 at 7:15
    
@Mehrdad - My comment is about the most compact program isn't a sign of the best programming language. In that case APL would win hands down, because you do most things with a single char operator. Only problem is that it is unreadable. –  Bo Persson May 10 '11 at 7:22
    
@Bo: Like I said, I wasn't recommending APL; I've never even seen it. Size was one criterion (although a significant one, as can be seen if you try this with C++)... but is there anything wrong with this code? –  Mehrdad May 10 '11 at 7:26
    
How I memoized a function in c++ –  Matt Ellen May 10 '11 at 7:33

Coroutines are an immensely useful language feature that underpin a lot of the more tangible benefits of other languages over C++. They basically provide extra stacks so functions can be interrupted and continued, providing pipeline-like facilities to the language that easily feed the results of operations through filters to other operations. It's wonderful, and in Ruby I found it very intuitive and elegant. Lazy evaluation ties in to this as well.

Introspection and run-time code compilation/execution/evaluation/whatever are massively powerful features that C++ lacks.

share|improve this answer
    
Coroutines are available in FreeRTOS (see here)‌​, which is implemented in C. I wonder what it would take to make them work in C++? –  Mike DeSimone May 10 '11 at 4:32
    
Co-routines are a nasty hack to emulate objects in C. In C++, objects are used to bundle code and data. But in C, you can't. So you use the co-routine stack to store the data, and the co-routine function to hold the code. –  MSalters May 10 '11 at 8:39
    
Coroutines in C++: crystalclearsoftware.com/soc/coroutine –  Ferruccio Jun 2 '11 at 17:48
    
@Ferruccio: Thanks for the link... there are a few in the Wikipedia article too. @MSalters: what makes you describe co-routines as "a nasty hack"? Seems a very arbitrary perspective to me. Using a stack to store state also done by recursive algorithms - are they hackish too? FWIW, coroutines and OOP came on the scene about the same time (early 1960s)... to say the former's a hack for objects in C seems bizarre... I'd imagine few C programmers back then were interested in emulating objects, >15 years before C++. –  Tony Jun 2 '11 at 18:09

Having implemented a computer algebra system in both Lisp and C++, I can tell you that the task was much easier in Lisp, even though I was a complete novice to the language. This simplistic nature of everything being lists simplifies a great many algorithms. Granted, the C++ version was zillions of times faster. Yeah, I could've made the lisp version faster, but the code wouldn't be as lispy. Scripting is another thing that is always going to be easier is lisp, for example. It's all about using the right tool for the job.

share|improve this answer
    
What was the difference in speed? –  quant_dev May 10 '11 at 5:51
1  
@quant_dev: a multiple of a zillion, of course! –  Matt Ellen May 10 '11 at 7:28
    
I never really measured it but I had a feeling the big O's were different. I originally wrote the C++ version in a functional style and it had speed problems also until I taught it to modify the data structures instead of creating new, changed ones. But that also made the code harder to read... –  da code monkey May 10 '11 at 16:00

What do we mean when we say that one language is "more powerful" than another? When we say that a language is "expressive?" Or "rich?" I think we mean that a language gains power when its field of view narrows enough to make it easy and natural to describe a problem -- really a state transition, no? -- that lives within that view. Yet that language is considerably less powerful, less expressive, and less useful when our field of view widens.

The more "powerful" and "expressive" the language, the more limited its use. So maybe "powerful" and "expressive" are the wrong words to use for a tool of narrow utility. Maybe "appropriate" or "abstract" are better words for such things.

I started out in programming by writing a whole bunch of low-level stuff: device drivers with their interrupt routines; embedded programs; operating-system code. The code was intimate with the hardware and I wrote it all in assembly language. We wouldn't say that assembler is in the least abstract, yet it was and is the most powerful and expressive language of them all. I can express any problem in assembly language; it's so powerful that I can do anything I please with any machine.

And all of my later understanding of higher-level language owes everything to my experience with assembler. Everything I learned later was easy because, you see, everything -- no matter how abstract -- must in the end accommodate itself to the hardware.

You might want to forget about higher and higher levels of abstraction -- that is, narrower and narrower fields of view. You can always pick that up later. It's a snap to learn, a matter of days. You'd be better off, in my opinion, to learn the language of hardware1, to get as close as you can to the bone.


1 Perhaps not quite germane, but car and cdr take their names from the hardware: the first Lisp ran on a machine that had an actual Decrement Register and an actual Address Register. How 'bout that?

share|improve this answer
    
You find that choice is a double edge sword. We all seek it, but there is a dark side to it and it makes us unhappy. It's better to have a very defined view of the world and defined boundaries that you can operate in. People are very creative creatures, and can do great things with limited tools. So to sum it up, I'm saying its not the programming language but having talent people who can make any language sing! –  Chad May 10 '11 at 8:22
    
"To suggest is to create; to define is to destroy." Thinking you could make life easier with another language feels good, but once you make the jump, then you have to deal with the new language's warts. –  Mike DeSimone May 10 '11 at 10:11
2  
I would say that English is way more powerful and expressive than any programming language, and yet the limits of its usefulness expand every day and its utility is immense. Part of the power and expressiveness comes from being able to communicate at the appropriate level of abstraction and the ability to invent new abstraction levels when nedded. –  molbdnilo May 10 '11 at 11:49
    
@Mike then you have to deal with communicating with the previous language within the new one ;) –  Chad May 10 '11 at 16:43

Associative Arrays

A typical way of processing data is:

  • reading the input and construct a hierarchical structure from it,
  • creating indexes for that structure (e.g. different order),
  • creating extracts (filtered parts) of them,
  • finding a value or a group of value (node),
  • re-arrange the structure (delete nodes, add, append, remove sub-elements based on a rule etc.),
  • scan thru the tree and print out or save some parts of them.

The right tool for it is associative array.

  • The best language support for associative arrays I've seen is MUMPS, where associative arrays are: 1. always sorted 2. they can be created on disk (so-called database), with the very same syntax. (Side effect: it's extremly powerful as database, the programmer has access to the native btree. Best NoSQL system ever.)
  • My second prize goes to PHP, I like foreach and easy syntax, like $a[] = x or $a[x][y][z]++.

I don't really like JavaScript's associative array syntax, because I can't create, say a[x][y][z] = 8, first I have to create a[x] and a[x][y].

Okay, in C++ (and in Java) there are nice portfolio of container classes, Map, Multimap, whatsoever, but if I wanna scan through, I have to make an iterator, and when I wanna insert a new deep-level element, I have to create all the upper levels etc. Uncomfortable.

I don't say that there're no usable associative arrays in C++ (and Java), but typeless (or non-strict typed) script languages beats compiled ones, because they're typeless script languages.

Disclaimer: I'm not familiar with C# and other .NET languges, AFAIK they have good associative array handling.

share|improve this answer
1  
Full disclosure: MUMPS is not for everyone. Quote: To give a little more “real world” example of the horror that is MUMPS, start by taking one part International Obfuscated C Code Contest, a dash of Perl, two heaping measures of FORTRAN and SNOBOL, and the independent and uncoordinated contributions of dozens of medical researchers, and there you go. –  Mike DeSimone May 10 '11 at 10:17
    
In Python, you can use either the built-in dict type (e.g. x = {0: 5, 1: "foo", None: 500e3}, note that there is no requirement for keys or values to be the same type). Trying to do something like a[x][y][z] = 8 is hard because the language has to look into the future to see if you're going to set a value or create another level; the expression a[x][y] by itself doesn't tell you. –  Mike DeSimone May 10 '11 at 10:23
    
MUMPS is originally a Basic-like language with associative arrays (may directly stored on the disk!). Later versions contain procedural extensions, which makes it very similar to core PHP. One afraid of Basic and PHP should find Mumps frightening, but others don't. Programmers don't. And remember, it's a very old system, all strange things, like one-letter instructions (altough, you may use full names), L-R evaluation order etc. - as well as non-strange solutions - have only one goal: optimization. –  ern0 May 10 '11 at 12:57
    
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%." -- Donald Knuth. What you describe sounds to me like a legacy language whose emphasis is backward compatibility, and that's okay. Personally, in those applications, I consider maintainability more important than optimization, and a language with non-algebraic expressions and one-letter commands sounds counterproductive. I serve the customer, not the language. –  Mike DeSimone May 11 '11 at 1:36
    
@Mike: very entertaining links you posted, I had a good laugh while reading them. –  shuttle87 May 11 '11 at 5:18

I learn't Java, C\C++, Assembly, and Java Script. I use C++ to make a living.

Though, I would have to say I like Assembly programming and C programming more. This is inline mostly with Imperative programming.

I know that programming Paradigms are important to categorize data types, and give higher programming abstracted concepts to allow powerful design patters and formalization of code. Though in a sense, each Paradigms is a collection of pattern's and collections to abstract the underlying hardware layer so you don't need to think about the EAX, or IP internally within the machine.

My only problem with this, is it allow's peoples notion and concepts of how the machine work to be turned into Ideology's and ambiguous assertions of what is going on. This bread's all kinds of wonderful abstractions on top of abstracts to some ideology goal of the programmer.

At the end of the day, its better to have a good clear mindset and boundaries of what the CPU is and how computers work under the hood. All the CPU cares about is executing a series of instructions that move data in and out of memory into a register and performs a instruction. It has no concept of data type, or any higher programming concepts. It only moves data around.

It becomes more complex when you add programming paradigms into the mix because our view of the world are all different.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.