Any Rubyist or Python developer will be caught off-guard with C++. Dynamically typed languages are intrinsically easier, and languages like Python and Ruby do garbage collection for you, resulting in a lot less work for the developer.
C++ does none of that. It's a slightly higher-level modification of C with object-oriented features, and C is still a lower-level language closer to, say, ALGOL or Simula rather than higher-level like Java or Smalltalk. Adding OOP still retains the hardware control and all of the bad stuff that comes with it (segfaults, buffer overflows, etc.), but adds complexity.
C++ is complex. Twisted. Mangled. But it's powerful, and you can do things in it that you could never dream of doing in C, Java/Jython/Mono, Python, Ruby, or Go.
It's like a Mitsubishi Lancer Evolution. It's a pain in the ass to deal with on a daily basis, but its potential is simply unmatched by any other vehicle in its price range. There are others that are more comfortable. But none reach the capability and sharpness of the Evo.
>Dynamically typed languages are intrinsically easier
I don't think this is necessarily true. Dynamic typing moves an entire class of bugs from compile time to run time. And, I am not aware of what benefits it brings (other than minor expressiveness) that can not be had in a static type system. For the most part, you will right code assuming a variable has a given type. If that is not the case, you will get a runtime error instead of a compile time error. In the cases where the variable can be multiple types, doing so in a static type system can be as simple as declaring the type to be polymorphic (or as horrible as java generics, or as hacky as void*). The other advantage of dynamic type systems is that they often come with autocasting.
While both of these do provide some expressiveness, working around them in statically typed isn't really complicated, just a minor amount of boiler plate.
The main awesomeness of Python's type system (and maybe Ruby's, I've never used it) isn't dynamic typing, but duck typing. The idea hear is that you almost never care what type an object is, only if it supports a given method. For example, if I define a new object, and define a method 'read()', I can pass it into a function that was expecting a file, so long as it only calls the 'read()' method.
Of course, avoinding garbage collection is still a big advantage.
I'd be hard pressed to name a popular dynamically typed language that does not offer duck typing. Technically there may be a distinction, but it is not one that matters.
The thing that I find creates the most boilerplate for me with static typing is useless helper classes that only exist to get around the fact that class A owns object of type B, so you don't want to allow an object of type B have a method that requires its parent A. Instead you create a class C owned by A which everything that B needs for that call can move into, and then let B know about C. (It does not much matter whether you make A inherit from C, or make C owned by A. Though I stylistically strongly prefer the second.)
Yes, you can set up mutual recursion between two classes in C++, but this involves some gymnastics and is frowned on.
In a dynamically typed language you'd just pass objects of type A into a method for type B.
Refactoring out a whole new class out of an existing one is not "a minor amount of boiler plate" in my books. But that is what C++ pushes you to do.
I'm not entirely sure I understand your example.
You have a class A, with a member of type B
You want B to have a method which takes an object of type A as a parameter.
I do not see why static typing causes difficulty with this. The only gymnastics I have seen in C/C++ do accomplish this is forward declarations. These are not needed because of the type system, but rather because C/C++ requires things to be defined before they are used. For example, java does not have this requirement.
Also, I believe that Go has something simmilar to duck typing, and its a static type system.
Go's "duck typing" is basically Java-style interfaces that don't have to be explicitly declared: if a type has all the properties to fulfill an interface, it automatically fulfills it.
This sounds similar to duck typing, but it's significantly less powerful because you pass values into functions with a particular declared type, and you can only access methods available to the declared type of the value.
For example:
interface MyInterface { Bar() }
struct Foo {}
func (this Foo) Bar()
func (this Foo) Baz()
func MyFunction(arg MyInterface) {
arg.Bar() // Fine, because MyInterface has this method.
arg.Baz() // Compiler error because MyInterface does not have this method.
}
In this example, you could use reflection or the unsafe package to call arg.Baz() despite the fact that arg isn't guaranteed to have that method, but it takes some work and you're basically breaking the way the language is meant to be used.
This isn't a problem in Python or Ruby because they don't have a notion of declared type in function arguments -- the "type" is resolved at run-time by method lookup.
You can use duck typing (without losing the compile time type checking) in C++ using templates. Somehow they get a lot of bad press, but for me they're one of the key features of C++.
I've never worked with templates. Do they require you to write the function for use with templates, or can you use templates to pass an object into a function which was designed for another specific type of object.
Based on my limited understanding of compilers, I do not see how you could efficiently implement duck typing without some type of JIT compiling.
They require you to write the function for use with templates; as long as the callee is ready to use templates, you can pass anything that fits the interface needed. Everything is done at compile time.
You can use a generic type as argument (template <typename T> void method(T arg) ), or a templated one (template <typename T> void method(MyObject<T> arg) ). In both cases the method will fail to compile if the body requires a missing field or method, but in the second one you get a standard "type mismatch" error, while in the first you'll get a "type X doesn't support method Y".
C++ is the 1980's Lancer with the same frame and same engine and the rest kept up to date with the latest performance tech. Fortunately for it, all the high performance cars which have been built since then can't reuse the same parts which are currently dominating the market.
C++ does none of that. It's a slightly higher-level modification of C with object-oriented features, and C is still a lower-level language closer to, say, ALGOL or Simula rather than higher-level like Java or Smalltalk. Adding OOP still retains the hardware control and all of the bad stuff that comes with it (segfaults, buffer overflows, etc.), but adds complexity.
C++ is complex. Twisted. Mangled. But it's powerful, and you can do things in it that you could never dream of doing in C, Java/Jython/Mono, Python, Ruby, or Go.
It's like a Mitsubishi Lancer Evolution. It's a pain in the ass to deal with on a daily basis, but its potential is simply unmatched by any other vehicle in its price range. There are others that are more comfortable. But none reach the capability and sharpness of the Evo.
C++ is the Evo.