I'm happier writing Typed FP because the system is very concrete in my head as I work with it. In a dynamic language, there is always a nagging uncertainty about the system - if you're using dictionaries to pass data around, you don't have certainty in what keys it'll have, and what data will be available inside it, and what could possibly be null.
When you add a new kind of a domain object (a Guest user in a user management system for example), you have no idea where all you need to handle it. You fix the obvious places, and do a text search, and find a few more. And the rest you fix over time.
The runtime robustness of untyped systems in my experience generally is a function of time. The more it sits in production, the more bugs we discover in the most commonly trafficked codepaths. We fix them - duct tape works - and then it sits and chugs along. (Robustness to change is another matter altogether).
But if you use a Typed Functional language, when you introduce a new domain object the compiler will tell you exactly where they are being used and will refuse to compile till you've made sure you're handling it in all the right places.
Value-based programming (ala Immutability) lets you write code as if you were writing mathematical definitions (high-school mathematics; no category theory or monad). While we can be disciplined about not writing mutating code, there is a real difference between 99% confidence and the second-guessing it entails, and just not having to worry about it at all. Everything is a value. There are no objects/references.
All this adds up to a state of clarity when you program. You don't have to keep second guessing yourselves; you don't have to do defensive checks that makes you feel a little bit ugly inside; you don't have to deploy worrying about the unknown unknowns that can break your system.
So my point is; it all depends on how you code something, the language may do it at compile time to prevent runtime assertions, but that also comes with extra baggage (I assume you need to write more code to define your types, function call conditions and mappings)
Is it possible to seamlessly integrate a user managment system in f# into existing c# code? I guess, it's not that simple.
It also reminds me of an experience I had in a former job with C++. There was a very, very experienced senior who wrote a very clever library which allowed us to add varous metadata to domain objects in a a compile-time checked, type-safe and very performant way. When the guy left, everything went downhill and the code from then on was regarded as mysterious black box noone dared to touch.
Somehow I am reminded if this when I read about 'magic' solutions in FP. Is it possible to reach a state with FP where seeing through it all gets too troublesome?
Trivial example: what if you could do away with exceptions but still be able to "bubble up" errors in a lightweight way, so that your error handling still wouldn't get in the way of your straight-through business logic code? "Everyone knows" to never use exceptions as control flow, but it happens by accident anyway - have you hit bugs because of that? (I have). If you could avoid having them in the language, wouldn't that make things simpler?
You have less need to learn things like monads because they're just plain old library code; if need be you can click through to the function definition, just like any other function you call. That for me is one of the big things FP is about: reduce what's in the core language, push stuff out into libraries instead. There are a few language features to learn, sure, but they're language features you wanted anyway. Type classes are a small feature, and boil down to just a slight bit of extra syntax support for the strategy pattern. (Indeed I find most of the FP features come down to taking classic OO principles - SOLID, composition over inheritance, and the like - and actually following through on them).
And maybe as you get comfortable with it you'll be able to turn those 10 million lines into 5 million, or 1 million, or less (and maybe those lines are slightly more complex than the lines they replace, but that's a good tradeoff). Certainly that's what using Scala has felt like for me.
http://fsharpforfunandprofit.com/posts/is-your-language-unre...
Large projects in OO often end up as mutable monoliths which become harder and harder to work with. New features sometimes require large painful and scary changes. Hacks are irresistible. Of course you need refactoring tools because you have to change many things in many files.
OO promised modularity but the languages never delivered because of their unreasonable design.
Highly reasonable, concise and refactorable code is the answer to complex systems.
Anyway. I work in a c# shop with a large monolithic code base developed by a small team with lots of fluctuations over more than 10 years. I have no functional programming experience at all.
I love c# because we actually try to keep the code as simple and linear as possible and only introduce complexity in certain areas if performance requires it. Yes there are hacks and dirty code passages, but if you stick to basic code constructs they are easy to decipher.
If your facing more than 10 million lines of code you start to appreciate simple code. Moreover if different developers, which come and go, are working on it. Living without refactoring and inspection capabilities of resharper is nearly unthinkable to me.
Now, how would you convince someone like me to try out f#?
There are only drawbacks: Obscure things we would need to learn (type classes? monads? xyz?). Probably hard to read, 'clever' code. A mixture of c# and f#. Unknown library, build and deployment issues. And I guess, f# developers are rare around here.
Even after reading this post, there's unfortunately no convincing reason for me and management to give f# a try...