4 ms·
"...realize that the types of bugs that hold them back can be reduced by using a more powerful language." I hear this a lot with FP but would love to see some
by rottyguy 9y ago
"...realize that the types of bugs that hold them back can be reduced by using a more powerful language."
I hear this a lot with FP but would love to see some real world examples of this if anyone has any links.
- phillipcarter 9y agoIt's often very difficult to come up with one, because there isn't really a silver bullet here. The draw to F# for me, when I was learning it, was I needed to build a DSL in a large system I was working on (side note: there must be a law somewhere stating that any large system will have a DSL in it somewhere). I didn't know about libraries like FParsec or anything (or a C# equivalent), so I just googled "how to write a DSL C#" and ended up somewhere showing F# code. I was curious. A week later, I wrote the whole thing in F#, with tests, and all requirements were fulfilled. Upon re-writing in C# (because reasons...), I had to re-think the problem. I used F# types and pattern matching everywhere, and Active Patterns to make stuff really concise and readable. A lot of the branching logic in my C# rewrite didn't really exist in F# because of this, and it was really hard for me to track down how everything worked in C#. I'm still convinced that someone unfamiliar with F# could understand the F# version better than the C# version because of how much less code and branching logic was involved. For a more professional case study, Microsoft Security Risk Detection is a fuzz testing service written in F#: https://blogs.msdn.microsoft.com/dotnet/2016/12/13/project-springfield-a-cloud-service-built-entirely-in-f/ https://blogs.msdn.microsoft.com/dotnet/2016/12/13/project-s... We blogged about their experience, and they do have practical examples there.
- dep_b 9y agoI can't give you any examples in F# from the top of my head, haven't touched it for a few months but I did ship software with it. I can give an example in Swift: C#: ResultObject MyFunction(SomeObject some, AnotherObject another) You have no idea if every value you pass in is required, or if you would always get a ResultObject or also need to expect null. Could possibly throw an Exception as well. Swift: func myFunction(some: SomeObject, another: AnotherObject?) throws -> ResultObject Forces you to give SomeObject, but you can pass nil to AnotherObject if you would like to, and the code inside this function will be forced to deal with it. Also it will always return ResultObject unless it throws an Error. You will have no surprises using Swift while C# forces you to guess unless you know the inside of the function. F# works the same as Swift in that regard. You need to be explicit about nullability and mutability, and if it is nullable you are forced to deal with it it before you use it. Immutable and non-nullable is just easier to use. The leap between C# and F# is much bigger because C# is really good and F# is a real functional language where Objective-C was older and Swift is less functional. Same goes for Java vs. Kotlin. Android Java is terrible compared to C# while Kotlin is much more similar in syntax.
- brianberns 9y agoIs your programming language unreasonable? or, why predictability is important http://fsharpforfunandprofit.com/posts/is-your-language-unreasonable/ http://fsharpforfunandprofit.com/posts/is-your-language-unre...
- tome 9y agoHow many times have you had the runtime exception AttributeError: 'NoneType' object has no attribute 'foo' (or its equivalent in your favourite language)?
- earthtolazlo 9y agoThat's something addressed by static typing though. I'm pretty sure any dynamic language has that issue, functional or not.
- tome 9y agoIt's fair to say that the boundaries of "functional programming" are pretty amorphous and I certainly didn't mean untyped functional programming. In any case, if you want to prevent null/None errors in a way that gives the programmer his/her own access to create similar new abstractions then you need * sum types * parametric polymorphism * pattern matching at which point you may as well also add * first class functions and then if you don't describe your language as "typed functional" then how do you describe it?
- yawaramin 9y agoUnits of measure. So in C# you can do something like this (using floats for convenience): class Power { public static HoursUsed( float totalBillDlrs, float deviceWattage, float rateDlrsPerkWh) { return 1000.0 * totalBillDlrs / (deviceWattage * rateDlrsPerkWh); } } Then call it like this: var totalBillDlrs = 10.95; var deviceWattage = 100.0; var rateDlrsPerkWh = 0.15; Power.HoursUsed(deviceWattage, totalBillDlrs, rateDlrsPerkWh); But, oops! that was actually supposed to be: Power.HoursUsed(totalBillDlrs, deviceWattage, rateDlrsPerkWh); In F# you can use units of measure to prevent this kind of thing at compile time: [<Measure>] type dollar [<Measure>] type watt [<Measure>] type kilowatt [<Measure>] type hour module Power = let hoursUsed (totalBill : float<dollar>) (deviceWattage : float<watt>) (rate : float<dollar/(kilowatt hour)>) : float<hour> = 1000.0<watt/kilowatt> * totalBill / (deviceWattage * rate) let totalBill = 10.95<dollar> let deviceWattage = 100.0<watt> let rate = 0.15<dollar/(kilowatt hour)> // Compile error Power.hoursUsed deviceWattage totalBill rate And, yes, in C# you can use things like named parameters to reduce the chances of something like this, but you can't eliminate it at compile time, which is what F# does.