Unsettling thought
thinkdifferent767.wordpress.com
thinkdifferent767.wordpress.com
Doesn't this just show that the ability to write code in an interview situation is a poor predictor of future performance?
If people who have actually produced vital code aren't passing your interview test, your interview test is poorly conceived.
The whiteboard test may be unfair to those who melt under interview pressure, but if the greatest danger is false positives for the "can they code?" test---if it's a startup where the price of one bad hire is very possibly if not likely the failure of the entire venture---it's the best test we've got.
Note that the test doesn't have to be "tricky" or anything like that, e.g. a simple "reverse a doubly linked list" will weed out a surprising number of candidates. My three basic tests, back when C/C++ were the only choices to use, were that one (tests groking pointers), do a recursive factorial (any language will do for that), and "find the errors in this block of code".
Mistakes in doing any of the above are perfectly fine, what you're looking for first and foremost is "do they have a clue?"
Or use another higher level test from one of the best managers I ever had: if you have any doubt about the candidate, don't hire them. And if you doubt they can really code....
I suck at writing pseudo code on a whiteboard...I also suck at writing code while someone there is watching every mistake I make. If I don't know the exact answer in advance, I need to feel my way by trying something, back tracking then trying a variation etc...You can't do that process effectively in an interview at a whiteboard with a pen. Also, I don't bother carrying around advanced algorythms in my head for doing this and that. What I do have is an effective strategy and skill for discovering the algorythms I need just - in - time. Who's got time to memorize arbitary algorythms so they can pass whiteboard interviews anyway?
Instead, I spent a long time erasing what I had written, running out of room on the edge of the board, staring at the board, thinking about off by one errors, etc. Just looking at code on a computer screen is a lot easier. You're used to seeing code in a nice monotype font with syntax coloring, not some scribbles on a board. And if the interviewer had just left the room for 10 minutes and let me write it on the board by myself I think I would have done a lot better.
If you did have your preferred development environment in front of you, your interview questions would likely be harder.
I see two possible solutions to this problem:
1. Interviewers: Change the interview process so that candidates are expected bring their own computers to write code on. Increase the difficulty of the questions.
2. Candidates: Practice interviewing, including writing code on a whiteboard. Have a friend pretend to be the interviewer.
BTW if you ever interview at Google again, I suggest reading http://steve-yegge.blogspot.com/2008/03/get-that-job-at-goog... . It definitely helped me. Actually, I suggest reading that before you interview anywhere.
I don't understand why people don't practice interviewing. It's worth your time to spend a few hours practicing something that could determine your future for years. Employers will change their interview process some day, but until then, if you want a good job you sometimes have to jump through stupid hoops.
Of course, I'd like interviewers to practice as well. When I interview someone, I want to get some idea of the candidate's skills. I seriously doubt my hastily-thought-up questions are anywhere close to optimal at achieving that goal.
send your best people to startup weekend and similar events. It should take only a few hours to identify the top people and establish a rapport that may lead to a successful hire.
I once asked an interviewer to leave the room and come back in 5 mins. Another time I asked him to just continue doing his work while I work away at the code. Both times I produced near perfect code. On other occasions, the result was somewhat disappointing.
I think (may be because it applies to me) an interview is not quite an accurate predictor of performance on the job. I for one, have no interest in remembering arcane sorting algorithms or how to implement a red black tree. Yes, I've done it in school and when I need them, it usually only takes an hour tops to figure it out and write at least the skeleton code for them. I consider myself a good s/w engineer, perhaps not great, but good.
I personally know people at Google (friends from college, more than a few) who were average at best in college or grad school. But they seem to do well in interviews (much of it I attribute to preparing well) and hence are now Googlers.
I know I suck at interviews but have performed very well in my job working on distributed systems software. I think the worst part I hate about interviews is some guy sitting there judging my capability. Perhaps, that is why I need to be my own boss (I'm usually very harsh on myself) =)
tl;dr; Paper/Whiteboard is just a different IDE you have to get used to.
For decades ordinary computer scientists wrote algorithms on pen and paper, translated them to punch cards or switches, and ran them on computers with no screens. Is it really so inconceivable that a company might expect you to understand and write code on a whiteboard?
That sort of "coding by accident" is exactly what interviews like that are designed to exclude. No doubt some very few people can successfully code that (wrong) way but the vast majority who do so are simply incompetent.
The people who built my house likely never took Strength of Materials during their civil engineering undergads, they just follow the building codes and nail together pre-made pieces (sometimes very large pieces) of house.
Would I prefer a PhD in EE to do the electric and a 6 year civil engineer to nail together the boards, just to be sure everything is done right? Perhaps, but I'm sure not willing to pay the extra it would take to make that happen. I still get a decent house with those professionals working a few levels upstream from the builders.
When I was in school, I saw my classmates fail to grasp basic concepts and abstractions. They had no deeper understanding. They managed to regurgitate the things they'd heard for a test, work together and manage to get an okay project together, and pass by by the skin of their teeth. They'd complain about how C was too hard, how badly they'd failed an assembly assignment, and that they couldn't wait to get back to Eclipse and Java. Of course, they'd only have one huge, giant class.
It's incredibly unfortunate. I'm not sure how to fix this. Maybe my standards are just too high.
What I'm not entirely sure of is that decent financial/industrial/important software can't be written by someone who can't write an algorithm to sort an array. You don't need to know much CS to call array.sort(), only that you want the array to be sorted. Now this level of engineer might not know what to do if it doesn't work (or worse, works but badly) but if he's got enough domain knowledge otherwise, he'll know to spend some money on a few high dollar hours with someone who can fix it.
I'd rather have someone who's a very good EE who didn't quite grok recursion working on my power grid software than a very good programmer who can't tell an amp from a volt. At least the EE can tell when its broken.
The author was surprised that candidates came to him with actual accomplishments on their resumes but didn't seem to know the basics of CS. My counterpoint was that its probably possible to accomplish quite a lot without knowing the basics these days, and if you do it cheaply, that might be just fine.
I don't think that message will get through with those distracting frameworks everywhere.
A great deal of terrible, buggy, unmaintainable software has been written due to exactly this type of sentiment. I have maintained, re-written, built on top of this type of software. The correct way to build power grid software (or any science/engineering-related software) is by having very smart software engineers (who do understand or can quickly figure out things like recursion), working closely with electrical engineers (or biologists/chemical engineers/etc). As in, they should be in constant (at least weekly) contact with each other. The software engineers learn about electricity, and the electrical engineers learn a little about software architecture.
This is based on my experience developing software for engineering applications. I currently work on software in the Aerospace industry, and I communicate regularly with other engineers. My software team is full of brilliant software engineers. Smart people can learn about other fields on-the-job. If you accidentally hire one that can't, don't fret: there is always work that doesn't require an intimate knowledge of electronics, such as build scripts, support software, utilities, etc.
That being said, I do think there is a place for a software engineer with a passion for other types of engineering. My degree is in Bioengineering, but my greatest experience (and greatest interest) is in software engineering. So, while I grok differential equations, control systems, and metabolism, I also understand recursion and polymorphism. And deterministic finite automaton. And closures. And I'm not the only one.
My point is this: If you have a really hard engineering problem that requires really smart software, hire really smart programmers, really smart engineers, and a couple really smart people who understand both sides. Like me!
The problem with this kind of analogy is that a builder starts with a set of well-defined plans drawn up by some architect or engineer and then executes the house to those specs. The only design document that lives up to that standard when it comes to programming is the full source itself. The part the homebuilders do is what the compiler/linker/toolchain do.
There's a classic essay about this called "What is software design?"
http://www.bleading-edge.com/Publications/C++Journal/Cpjour2...
I've worked in construction, and a handful of my good friends work in construction of various types. We often laugh at the comparisons between software development and construction. I've certainly never seen a job where the plan worked without modification from beginning to end, and many projects begin with a pile of change orders.
Many projects don't need to worry about some low levels aspect of the design (if at all): memory management, for instance, can mostly be left to compilers and linkers. When we really need to, we can locally use really low level languages, like C.
And in properly written C++, it is.
The only memory that is automatically managed in C++ is the stack. (If you disagree, please know that I will be very difficult to convince.) So, "properly written C++" literally means "C++ code which doesn't uses the heap at all". That's probably not what you meant.
Relaxing this rule a bit, you could code in a RAII fashion. That way, the users of properly written objects won't manage the memory themselves. The implementation of those, however, still have to. A prime example is the STL.
Plus, I'm not sure RAII all the way down is "properly written". See, such logic is quite copy-prone, affecting the code's efficiency. You use C++ for it's performance, right? So you have to manage the memory manually at some point.
Or you could use smart pointers. They mitigate the need for manual memory management, and allow sharing. But even then, you might want to (manually) pay attention to loops in the pointing chains.
Which is exactly my point: between the standard library and smart pointers, many projects will never have to touch any details of memory management.
The implementation of those, however, still have to. A prime example is the STL.
Of course. But you only need one standard library, and many projects can use it. Don't forget your original claim, which I quoted in my previous post: "Many projects don't need to worry about some low levels aspect of the design (if at all)." It's absolutely true that many sizable projects written in modern C++ never have to consider the low-level details of things like memory management, since those details have been pushed into the libraries they use.
Plus, I'm not sure RAII all the way down is "properly written". See, such logic is quite copy-prone, affecting the code's efficiency.
There are ways to mitigate that impact, if it becomes a performance issue, but it rarely does.
Or you could use smart pointers. They mitigate the need for manual memory management, and allow sharing. But even then, you might want to (manually) pay attention to loops in the pointing chains.
That's only a problem for self-referential data structures, of which there are few not already implemented for you in the standard library.
Ah. So you don't really care about performance. In that case, the only justification left to C++ is legacy code. (Knowing Ocaml and Haskell makes me quite certain of it.)
That was my original point: C++, even when you try to use a wisely chosen subset of it, remains very complicated and error prone. I blame it's design choices. I agree that those choices were precisely what made C++ popular, but popularity is hardly a criterion for me. And on all other fronts, C++ really sucks.
Did I say that?
That was my original point: C++, even when you try to use a wisely chosen subset of it, remains very complicated and error prone.
Your original point, which I've now quoted twice, was that C++ is inappropriate because many programs don't need to deal with low-level details like memory management. My counterclaim, which you have yet to refute, is that C++ is no obstacle to that end.
I blame it's design choices.
The vast majority of people who blame C++'s design choices don't understand them. Have you read Stroustrup's D&E?
And on all other fronts, C++ really sucks.
Stating a claim is no defense of it.
> Did I say that?
Yes, by saying that copy prone RAII is rarely an issue. Meaning, performance is rarely an issue. So, you rarely care about performance. That's fine: performance rarely matters, anyway. When it does, we can still locally optimize.
> > And on all other fronts, C++ really sucks.
> Stating a claim is no defense of it.
You're right. This is: http://yosefk.com/c++fqa/ The writing is quite fun, and the whole thing is actually informative. To sum up, the guy says that for a new project with few dependencies, C++ is almost never the best choice. Meaning, (almost) no niche is best filled by C++. Each one is better served with another language.
> Your original point, which I've now quoted twice, was that C++ is inappropriate because many programs don't need to deal with low-level details like memory management. My counterclaim, which you have yet to refute, is that C++ is no obstacle to that end.
You're right (again). I can't refute that point. Now my point is, that doesn't make C++ appropriate. See, when you don't need to do low-level stuff, many programming languages are vastly simpler, safer, more terse, and more flexible than C++. All at the same time. And you can learn them in no time (you were able to learn C++, after all). So, in that case, C++ isn't the best option. Why bother with it?
But still, I wonder how a significant project could avoid to implement some sort of data structure itself (which would mean worry about memory). Do you have any example?
> The vast majority of people who blame C++'s design choices don't understand them. Have you read Stroustrup's D&E?
I didn't. As I understand it, Stroustrup had some goals, and C++ achieved them. One such goal was to bring Object Orientation to C programmers (the "masses"). So I won't say that C++ didn't achieve it's purposes. It did. I just say those purposes weren't worth the behemoth that C++ is.
Object Orientation for instance, is a mistake. As seen by C++ (and Java), OO encourages high coupling and side effects more than is healthy. And that's before you need to apply one of the baroque design patterns from the GoF book.
You need to do some work on correcting your faulty interpreter. Saying that copying rarely causes performance problems is not at all saying that I don't care about performance.
You're right. This is: http://yosefk.com/c++fqa/ The writing is quite fun, and the whole thing is actually informative.
Not really. Yosefk, like many C++ detractors, very clearly does not understand the rationale for a number of C++ features. But this isn't the place for me to spend hours refuting a link that too you mere seconds to dig up.
See, when you don't need to do low-level stuff, many programming languages are vastly simpler, safer, more terse, and more flexible than C++.
That's not actually the case, though. For a lot of simple (e.g., scripting) tasks, writing them in C++ results in a program a few small lines longer and orders of magnitude faster. In one case I had billions of integers on which I needed to calculate some simple satistics; while the Python program was running, I was able to write, compile, and run to completion a C++ version that was a mere four lines longer (mostly empty-brace lines).
Some more complex tasks are actually easier in C++ than in other languages. I had to write a parser and virtual machine for an assembly language in college. Doing the bit-level operations in Python would have been a pain, in large part due to the automatic promotion of integers to longs; doing them in C++ was simple and preserved the semantics that I required. I didn't need to manage any low-level allocation in that program; all my "new" calls went straight into smart pointers (auto_ptr actually worked fine in my situation and didn't require a non-standard library) and they handled all deallocation. Valgrind confirmed that there were no memory leaks, with no effort at all on my part.
The vast majority of people who consider C++ difficult to write are unaware (commonly through willful ignorance) of how to write C++ for this the frequently cited issues never arise in the first place.
And you can learn them in no time (you were able to learn C++, after all).
It's not a matter of learning other languages; I'm competent in Python, OCaml, Perl, and a number of other languages I've worked with over the years. C++ is actually a rather late addition to my bevy of languages.
So, in that case, C++ isn't the best option. Why bother with it?
Just because I can learn other languages doesn't mean C++ isn't the best option. Sure, I could similar speed in OCaml, but then I'd be the only one who could work on it, and my employer would be in a tight spot if I were hit by a bus. I could write it in Python or Perl a little bit faster, but it would be an order of magnitude slower, and I'd have to throw tons more hardware at the problem to process the same amount of data.
Object Orientation for instance, is a mistake.
Ah. I see now that I'm arguing with an ideologue. Good day.
> [Yosefk don' get it]. But this isn't the place for me to spend hours refuting a link that too you mere seconds to dig up.
Actually, I've read the whole thing. And a good deal of the FAQ as well. Also, I think there is a good chance that Yosef did understood the rationale behind C++, but was challenging it nonetheless.
> Ah. I see now that I'm arguing with an ideologue.
I know my statement contradicts 99% of the industry. But I don't have much choice. Basically I believe 2 things: (1) side effects, like assignment, should be avoided or isolated, and (2) coupling between modules should be minimized. OO as I see it violates both principles: objects are state-full by default, and coupling is often high (many methods per class, inheritance). The conclusion is inevitable: either I don't "get" OO, or my beliefs are false, or 99% of the industry is making a mistake.
Now I don't believe that OO is always a mistake. I just believe that for most problems, it is a mistake to apply an OO solution.
(Note that I say "believe", not "think". Actually, I am still full of doubts).
But I'm the guy who figured out how to fix the auto-updating mechanism in a client to reduce the update time of 60 days to 7 days for over 6 million installs. I'm the guy who wrote an XML stream parser before RSS readers became embedded in every framework out there. I'm also the guy who wrote a web-front end to a manufacturing forecasting system that sat on an AS400 system and designed the entire middle layer architecture to support the transactions.
I'm not the greatest programmer in the world, but I think I've done some really cool stuff; even cooler that I have an BSEE and not a BSCS.
Oh yeah, I work at a bank now cause I wanted to improve something tangible.
He's more than happy and joined the company because they gave him hard, interesting challenges.
Not all good people end up at "trendy" places.
I think this is part of why there is so much process and quality control at these sort of companies.
and then many, like me, don't have a software engineering background and don't exactly speak the same language (don't even know UML).
I discovered recursion and binary search algorithms as I programmed, but if you asked me about either topic, I would not have known what you meant even though I had experience with them, until much later.
Or switch not from C/C++ to Java, but from Scheme to Python?
MIT's EECS department panicked when enrollment crashed after the dot.com bubble burst (for the previous quarter century or so they had 2/5ths of the undergraduates (!!!)) and it was decided from on high to change the very nature of its CS foundation and to purge Scheme from the base curriculum.
You can find Sussman's comments on this here and there; here's one paraphrase: http://muckandbrass.com/web/display/~cemerick/2009/03/24/Why...
Although I can't at the moment find the sharpest direct quote of him, very roughly, it's a change from understanding what's really going on to patching together libraries.
Now, this is in the cause of building really interesting things, or that is my trying to put a positive gloss on it all and my impression of what it's actually accomplishing. If you're a pure CS type this is an unmitigated disaster ("So the reason, basically, is that software today is a train wreck, and you might as well embrace helplessness and random tinkering from the start? Horrifying." Andy Hefner, http://www.wisdomandwonder.com/link/2110/why-mit-switched-fr...) and you should go to one of the other top schools like Berkeley, where they still teach SICP. If you want to go out into the world and make cool stuff, it's probably still pretty good to great.
Generic programming, among other things.
The C languages are actually missing a lot of the important concepts, like lambdas,
Lambdas are functions without names. They're not important concepts, they're really just syntactical sugar.
and discourage other important things like recursion.
Just because the language doesn't require TCO doesn't mean it discourages recursion; it just discourages teaching recursion with trivial examples like factorial. Quicksort, for instance, would be an excellent place in a C or C++-based course for teaching recursion.
The proper CS name is "parametric polymorphism". This is not as special as "Generic programming". (What is special, is the abysmal C++ implementation of parametric polymorphism.)
> Lambdas are functions without names. They're not important concepts, they're really just syntactical sugar.
The transformation required to go from a higher order program to a first order one is called "lambda lifting". This goes way beyond syntactic sugar. So, a language which lack lambdas don't fully implement functions… which look like an important CS concept.
No, it isn't. You would know this if you actually bothered to understand the terms you used rather than bandying them about in an attempt to win Internet points. Generic programming is a far broader topic than parametric polymorphism: that's why languages which already have parametric polymorphism, like Haskell, have variants which support true generic programming, like Generic Haskell and Scrap Your Boilerplate.
> (What is special, is the abysmal C++ implementation of parametric polymorphism.)
Given that you obviously don't understand the difference between run-of-the-mill parametric polymorphism and the generic programming enabled by C++ templates (and no other typed implementation except perhaps GADTs, and I remain unconvinced even of that) Id say you're fairly unqualified to be assessing the quality of C++'s implementation of parametric polymorphism.
> The transformation required to go from a higher order program to a first order one is called "lambda lifting". This goes way beyond syntactic sugar.
Wow, you really seem to enjoy using terms you clearly don't understand.
No, lambda lifting doesn't "go way beyond syntactic sugar." It's actually a fairly simple syntactical transformation: the free variables in the function body are converted to arguments to a static function, and closures, when generated, are a simple data structure consisting of a pointer to this static function and the arguments to "fill in" when called.
> So, a language which lack lambdas don't fully implement functions…
It's hard to believe that you'd even say that, let alone get modded up for doing so. I find it hard to argue against, much like I would have difficulty arguing against someone who said that a country which lacked cars couldn't fully implement wheels.
You see, what lambda lifting does is convert closures (which seem synonymous, at least in your writing, with lambdas) into ordinary functions with no free variables. Functions without free variables are more basic than functions with free variables.
The fact that template are Turing complete doesn't hide the restrictions they come with (like how they interact with inheritance). I know they have others goals than mere parametric polymorphism. I even admit that I don't understand these goals. I just say that one goal wasn't met: simple parametric polymorphism.
About lambda lifting being a (simple) syntactical transformation, please stop. You're right, but in a trivial sense: every compilation process is a (less simple) syntactical transformation. That includes lambda lifting, ghc's crazy optimizer, and every static compiler on this planet.
Now, by "syntactic sugar", I meant something that could be dealt with with local macros. You know, I have done the transformation you speak of manually in C++. More than once. I know this is fairly simple. But it is not local. I still have to write something outside the definition of the function I am writing the closure in. So, to do lambda lifting, I need a more global preprocessor.
The locality of the transformation may not be important to you, but to me, it is crucial. I don't mind some noise (semicolons, curly brackets, keywords…), because when used to it, I can see the actual code beneath it. However, the code has to be there. If I have to look up elsewhere, it quickly blows up my short term memory. Also, as long as the transformation is strictly local, you could deal with it with simple macros, like this:
-- I assuume "closure" is a Lisp-like macro
let x =
let y = ... in
closure arg1 arg2 (... body ...)
So, a language without lambdas doesn't treat functions as first class citizens. That's what I meant by "doesn't fully implement functions". This is a strong wording, but I don't think it is inaccurate. Put the same restrictions on integers, and see if you can still say that they are "fully implemented".Did I overlooked something?
The STL embodies (and accomplishes) far more than parametric polymorphism. As far as I know there is no other language with as comprehensive a collection of container-independent algorithms in the standard library.
> The fact that template are Turing complete doesn't hide the restrictions they come with (like how they interact with inheritance). I know they have others goals than mere parametric polymorphism. I even admit that I don't understand these goals. I just say that one goal wasn't met: simple parametric polymorphism.
And you're still wrong. Templates achieve parametric polymorphism and more. I can write a simple, templated, singly-linked list class in C++ which can do everything the same `'a list` in ML can do.
> About lambda lifting being a (simple) syntactical transformation, please stop. You're right, but in a trivial sense: every compilation process is a (less simple) syntactical transformation. That includes lambda lifting, ghc's crazy optimizer, and every static compiler on this planet.
I was making a greater claim that you seem to understand. Lambda lifting is a simple syntactical transformation. I can explain the entire transformation in a paragraph or less. I can offer example code of the transformation off the top of my head with ease. All lambda lifting does is make explicit what closures allow to remain implicit.
Your following two paragraphs are a fairly obvious attempt to change your original, wrong statement into something defensible.
> So, a language without lambdas doesn't treat functions as first class citizens.
Ridiculous. A language without lambdas is just that: a language without lambdas. Remove lambda from Python, and you remove only the ability of a Python programmer to define unnamed functions. Functions remain first class; their binding rules remain exactly the same. The only difference is that now programmers must give a name to all their functions.
Whoops. I forgot that, sorry. People may have meant true generic programming, after all. Now, actually using STL's <algorithm> and still end up with readable code isn't easy to me. For instance, each time `for_each` or `accumulate` would be appropriate, I end up writing a `for` loop instead, because the end result is more concise and more local. So in the end, container independent algorithms rarely matter to me.
> I can write a simple, templated, singly-linked list class in C++ which can do everything the same `'a list` in ML can do.
I think we don't use "simple" in the same way. Here, such an implementation of lists takes only 12 tokens and 2 lines in ML. How many do you need to do the same in C++? My first guess is more five times that, probably ten. Still simple, but much more complicated nonetheless.
Though in that particular case, I'd rather blame the absence of inductive types. Templates really are simple here. The real problem shows when you combine them with inheritance: you have to jump through some hoops (like having to re-declare virtual methods in the derived classes).
> Your following two paragraphs are a fairly obvious attempt to change your original, wrong statement into something defensible.
It was an attempt to clarify my meaning. Yes, my statement was wrong. Lambda lifting doesn't go way beyond syntactic sugar. But, to me, it still crosses the line. To you, it doesn't. I think that's only because your definition of "syntactic sugar" is more liberal than mine.
But even then, we're not done. Before you do the actual lambda lifting, you have to parse the source code. Trivial in Lisp, but quite a feat in C++.
> […] The only difference is that now programmers must give a name to all their functions.
To me, such a restriction is sufficient to make function second-class citizen. If you can have anonymous integers, and you can't have anonymous functions at the same time, then functions are not first class. Again, we disagree on a mere definition. Beyond that, I agree that the other "first-classiness" properties of functions are far more important.
> Now, actually using STL's <algorithm> and still end up with readable code isn't easy to me. For instance, each time `for_each` or `accumulate` would be appropriate, I end up writing a `for` loop instead, because the end result is more concise and more local.
This seems to be a new complaint, again unrelated to your previous complaint. No one, least of all me, is claiming that C++ is concise. If that's a debate you want to have, you'll need to find some other patsy to have it with.
> So in the end, container independent algorithms rarely matter to me.
They matter a lot to any implementer of new containers and algorithms, because they mean that any container implementer can provide iterators and automatically support a huge library of algorithms, and any algorithm implementer can automatically support a wide array of containers without needing any specific knowledge of how those containers are implemented.
> I think we don't use "simple" in the same way. Here, such an implementation of lists takes only 12 tokens and 2 lines in ML. How many do you need to do the same in C++?
When did this debate become about conciseness? Your claim was not that parametric polymorphism was wordy in C++, it was that the implementation was "abysmal". In reality, the implementation is as optimal as it really can be in an imperative, C-derived language: a non-polymorphic data structure on some type "X" can be made polymorphic by prepending "template <typename T>" before the data structure and replacing all references to "X" with "T". That's pretty simple.
The difference you note in line counts for implementing a singly linked list is not because of any real difference in capability of the language to support parametric polymorphism, but in ML's support for algebraic data types as opposed to C++'s support for machine-based data types: now you're introducing yet another complaint which is not your original complaint.
> The real problem shows when you combine them with inheritance: you have to jump through some hoops (like having to re-declare virtual methods in the derived classes).
Perhaps, but since virtual methods and inheritance-based subtyping is something ML doesn't support at all you cannot fault C++ for its less-than-optimal support for those features in comparison to ML.
> But even then, we're not done. Before you do the actual lambda lifting, you have to parse the source code. Trivial in Lisp, but quite a feat in C++.
Introducing yet another complaint unrelated to anyone's original claims. Ignoring it, since it's not relevant to the reason why this thread originally began.
> To me, such a restriction is sufficient to make function second-class citizen.
"First class" is a well defined term in programming language design and implementation, and it's not the same definition you're trying to use here. I see no point in arguing with you about your non-standard use of the term.
Well, yes. Sorry.
> The difference you note in line counts for implementing a singly linked list is not because of any real difference in capability of the language to support parametric polymorphism[…]
Hey, I said that much!
> since virtual methods and inheritance-based subtyping is something ML doesn't support at all you cannot fault C++ for its less-than-optimal support for those features in comparison to ML
Fair enough. I'll revise my stance.
> "First class" is a well defined term in programming language design and implementation.
Not in Wikipedia: http://en.wikipedia.org/wiki/Talk:First-class_function Could you point me to an authoritative source which would clarify the issue?
I happen to think that's the right decision.