I had the same complaint with Rails: There's too many libraries injecting things into various places, and it's hard glancing at the documentation for any library to see what the rules of the game are.

To give one example, the documentation for just about every function seems to say that it returns 'Object'. What kind of object? You have to dig through the source to find out.

I typed 'image' into rubygems.org and here's the first example:
http://www.rubydoc.info/gems/fastimage/2.0.0/FastImage

It doesn't seem hard to use, but notice that all the attributes are listed as returning 'Object'. If I look at the 'type' method, I wonder a few things:

* What is a uri exactly? Is it any old string? Is it an object returned by parsing a string using some standard Ruby library?

* What can be returned? They give some examples of symbols that can be returned. What is the full list?

Contrast that with the types listed in this image library I just looked up on Hackage:

https://hackage.haskell.org/package/JuicyPixels-3.2.7/docs/C...

I've never used this library before, and I can see roughly how I would use it just looking at the types:

readImageWithMetadata :: FilePath -> IO (Either String (DynamicImage, Metadatas))

"readImageWithMetadata takes a filename, and reads the file returning either an error message or an image together with its metadata"

What exactly is an image? You can click through and see it's one of 13 things:

https://hackage.haskell.org/package/JuicyPixels-3.2.7/docs/C...

What exactly is an image's metadata? You can click through and see it's an abstract type that can be manipulated using operations like you'd find on a map(a dictionary). In particular, see the 'lookup' function to see how to access things.

Here's a more complex example:

encodeGifImages :: GifLooping -> [(Palette, GifDelay, Image Pixel8)] -> Either String ByteString

"encodeGifImages takes a number of times to loop and a list of palettes, delays, and images of 8-bit pixels, and returns either an error message or a sequence of bytes representing the .gif"

I feel like it would be less clear what needs to be done to call this function with the Ruby equivalent. I'd probably end up looking through the source.

Just as important with the signatures is what the functions are not doing: encodeGifImages isn't rewriting any symbol tables, monkey-patching new methods into existence, changing global variables, writing to a database, opening a file, or printing a log message. I can say all of this because its type doesn't allow it to. I could run encodeGifImages in an interpreter or test without needing any setup.

The Ruby library here wouldn't give anyone trouble either. The examples are probably sufficient to use it. I think with Ruby as long as you can find examples close enough to your specific case you can usually make it work.

But if you're debugging something that doesn't have an example readily handy, the static type system makes it much easier to see what something is doing.

I used Haskell here, but C# or C++ would probably work just as fine for this purpose. Well, unless you're the type who likes to cast everything to void* so he doesn't have to worry about the types.