C. I work in this for the most part every day. I'm good at it. I also realize it's crusty, it's old, and I hate having to write complex makefiles and sort out other peoples complex makefiles. The vast majority of my time is not spent making cool stuff with C, it's debugging an expert language that has way too many pitfalls to get to the good part- which is creating cool features.[/li][/list]
Yea, C has lots of gotchas, and its minimal sanity checking also means it is very easy to mess things up and not know about it for a long time. Also, its single, unified namespace can be a big pain in the but
C++ has many of the same gotchas as C does plus like 3 times as many on top of it. C++ is very powerful though.
Functional programming languages. It doesn't match the way I think. All of them.
They certainly are quite the paradigm shift. However, one language I work with some, Scala, is a object-oriented functional programming hybrid. Basically, functions (and more generally, blocks) are objects. That is a handy way to think of it when trying to "wrap your mind around" it
Java, and its hellspawn. While it cleans up a lot of the deficiencies of C, it ruins your productivity by being so incredibly verbose. The object model is both a blessing and a curse, requiring huge rewrites if your project requirements change. Their excuse is to do a better job in the design phase, but people who say that have never worked for real-life, non-technical stakeholders.
The developers of Java wanted to keep the language simple. So they went with a nominative types (types are considered unique based on where they were declared and their fully qualified names), strongly typed (very few implicit conversions), statically typed (compile time type checking), manifest types (you must declare the type of variables and functions, and no type inference compromise) with very few syntactic shortcuts (no operator overloading, no formal recognition of getters and setters, etc)
While this made for a relatively simple language specification (which has its merits), it does have the unfortunate side effect of making developers do lots of things by hand. Also, as it does not give much leeway with its types, this can make refactoring class hierarchies a pain, especially with interfaces have to change.
The few but very visible "warts" in the Java library that came with poor design decisions when it was first created don't help thing either. Also not helping things is that most major implementations of the Java Runtime Environment are memory hogs.
C# has a very similar language properties in regards to its overall paradigm typing, except they did offer some syntactic niceties (like operator overloading, formal support for getters and setters, and in C# 3 and up, some type inference), plus it fixes some of the design oddities that Java had (like primitives can be treated like immutable structs, unlike in Java where primitives are their own thing)
So it can be much nicer to code in, but the strict typing system still makes refactoring class hierarchies a pain.
There are also some nice language features in Java that C# does not have yet (formally recognized typesafe enums, a flexible class lookup system)
Also, there aren't as many implementations of it.
Python has nominative types, strongly typed (seems strange, but a string will remain a string regardless of where you use it, thus making it strongly typed), dynamically typed (the "duck typing"), inferred types (you don't have to declare types, in fact, it is recommended you don't), with lots of "syntactic sugar"
The duck typing does some interesting things. While Python does have nominative types (types themselves are unique based on name), when it comes to semantics checking, it acts quite a bit like it has structural types (in a language with full fledged structural types, types are unique based on their structure, regardless of where they were declared or defined).
The duck typing does wonders for refactoring class hierarchies, as even if top level types change, as long as the method signatures are still compatible, most if not all of the surrounding code can still compile.
However, sometimes this can be a pain. If you give a function a type it can't work with (like giving a function that subscripts its input a type that cannot be subscripted), there is no guarantee you will find out until runtime.
Also, even if a function can work with a type, sometimes the type has changed so radically that the function no longer makes sense with it, and is thus a bug to use that function on it.
I have to say I love their collections API. Especially nice is their list comprehensions framework, gracefully unifying (at least to the end developer) the tasks of iteration, filtering, and "sorting requests". And they even have a great system of "comprehension literals" to easily construct very nice looking but very descriptive comprehensions.
I also have to say I am very wary of the whole whitespace blocking thing. IMO, that sounds brittle.
I can go into detail on the other languages to if you want, but I think I have rambled enough for now.