7 ms·
Why is F# code robust and reliable?
- p4bl0 2y agoWhy are algebraic data types called "discriminated unions" here? Is there a subtle difference between the two or is it just that F# calls the same feature differently than OCaml?
- Jtsummers 2y agoDiscriminated unions are one type of algebraic data types (sum and product types being the most common). The section discussing them is specifically calling out a feature related to discriminated unions (sum types) in F#, and is not about algebraic data types broadly.
- AdieuToLogic 2y agoThe short answer - F# and similar languages provide confidence in correctness due to being strongly typed. The long answer - https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/ https://bartoszmilewski.com/2014/10/28/category-theory-for-p...
- OptionOfT 2y agoAlso Option types which enforce explicit null / None checking.
- two_handfuls 2y agoI feel that shortened it too much.
- AdieuToLogic 2y ago> I feel that shortened it too much. No worries, here's a slightly longer description. Languages such as F# have static type systems which can catch logic errors during compilation. The kind of defects type systems can catch are often "low hanging fruit" issues such as logic errors and typo's. In many ways, programming languages with a sufficiently mature type system provide the same benefit as pair programming. When they are used in conjunction with mathematically sound constructs, such as immutability, Functors, Monads, Monoids, etc., these languages can be a productivity/correctness force multiplier.
- lispisok 2y agoImmutability by default contributes just as much if not more
- snorremd 2y agoThis is the number one thing that made Clojure work for me despite being dynamically typed. Having confidence that values did not change under my feet after sending them into functions or across thread boundaries was so refreshing. In immutably valued languages even if you technically might be sending a reference to an immutable value type, you can at least practically think about it as pass by value instead. I never really got into F# or Haskell (more than some tutorials) so can't really comment on the type safety part.
- deleted 2y ago[deleted]
- iLemming 2y agoApologies for being pedantic here, but Clojure is too - strongly typed, dynamically typed language. This means types are inherent to the values, not the variables that hold them, providing both safety and flexibility - even though variables don't have fixed types, every value in Clojure has a type. In contrast, Javascript is weakly typed. Yet, Clojurescript, which compiles to JS, retains Clojure's strong typing principles even in the Javascript (weakly typed) runtime. That (to certain degree) provides benefits that even Typescript cannot. Typescript's type checking is limited to the program's boundaries and often doesn't cover third-party libraries or runtime values. Typescript relies on static type analysis and type inference to catch type errors during development. Once the code is compiled to JS, all type information is erased, and the JS engine treats all values as dynamic and untyped. Clojurescript uses type inference, runtime checks, immutable data, and dispatch mechanisms, optimized by its compiler, to achieve strong typing for the code running in the JS engine.
- funcDropShadow 2y agoThe value of static typing depends very much on the application domain. In a closed-world application domain where you can be reasonably sure that you know upfront all entities, their attributes, their valid ranges, etc, static typing is extremely valuable. That applies to domains like compilers, system software, embedded systems, and more. In open-world domains, like business information systems, static typing is often an obstacle to fast adaptation. Whereas immutability provides value in every domain, unless the performance requirement cannot be met.
- manusachi 2y ago*Statically typed ;)
- AdieuToLogic 2y agoNice catch, thanks :-). I was thinking of the benefit statically typed languages offer and not the difference between them and dynamically typed ones.
- bazoom42 2y agoStrict dependency order is independent of the type system, so strong typing is definitely not all of it.
- xiaodai 2y agoHaskell, Ocaml, scala anything else?
- genter 2y agoRust, ReasonML
- chx 2y agoRust doesn't apply. You need a functional language for the kind of robustness we are talking about. Rust got some influences from there but it's not one.
- __s 2y agoWhat are "we" talking about? - Immutability by default. Check - Discriminated unions with exhaustive check. Check - No nulls by default. Check - No exceptions in the business logic. Check - Strict dependency order. Rust doesn't have this - Warnings on unused expression results. Check - Typed primitives. The level of ergonomics this is implemented with in F# I'll say Rust doesn't have this - Explicit conversions. Check - Functional approach to concurrency. I think Rust's compile time safety against data races gives this a check. I've used channels for concurrent server processes, it's nice. Check - Explicit dependency injection. I've never understood what this means 7/10
- Jtsummers 2y ago> - Explicit dependency injection. I've never understood what this means The article seems to mean what's described in this other article as "dependency parameterization" where the dependency is explicitly passed to the function (and every function it calls that also needs that same dependency). This is as opposed to, in OO languages, setting the dependency (typically) during construction (however the object is constructed). Or it's otherwise set in some larger scope than the functions which make use of it (global, module, object instance, whatever is appropriate to the language and task). https://fsharpforfunandprofit.com/posts/dependencies/ https://fsharpforfunandprofit.com/posts/dependencies/ https://fsharpforfunandprofit.com/posts/dependencies-2/ https://fsharpforfunandprofit.com/posts/dependencies-2/
- GiorgioG 2y agoAlso because Microsoft spends relatively little on it and so it’s not changing at a fast pace.
- fluidwizard 2y agoKudos to Don Syme for not getting the language too bloated btw, it's hard to imagine it is almost 20 years old.
- agarren 2y agoRecords, tuples, pattern matching, immutability, error handling with Result<‘a>, distaste for nulls, it’s got everything that Microsoft is trying to shoehorn into C# today, without all the baggage that C# brings with it. It seems like F# (fortunately) does have many reasons /to/ change.
- GiorgioG 2y agoAgreed - the tooling and advocacy needs changing. How many times has VS shipped with broken F# functionality.
- chenzhekl 2y agoMicrosoft explained why we love Rust so much ;)
- DeathArrow 2y agoExcept F# is far more pleasant to use than Rust.
- akkad33 2y agoIs it? There is a lot of uphill battle on using DotNet librairies that are mainly developed with C# in mind. So all the nice things about F# like currying, no nulls etc go out the door because you're interacting with C# code. Rust is a first class citizen in its own ecosystem, so you never have to compromise on the strictness of your codebase
- neonsunset 2y agoIn practical terms it's mostly source-generators-based functionality and nullability that are an issue. F# 9 gains the ability to transparently understand nullable annotations emitted in C# by Roslyn and expresses them as `T | null` unions, or just as T if the T is non-nullable. Currying and other F#-specific features are simply syntax, there is no inherent limitation for defining a simple curried expression that ends up calling into a method implemented in a different .NET language. The bigger issues are non-technical where it's just very few companies use F# in production. As for the technical ones - there are not that many and most of them are known (like mentioned above - code generation related, so the criticism usually mentions the same limited set every time, like code-first model definition in EF Core).
- AndriyKunitsyn 2y ago>Strict dependency order >In F#, all variables, functions, types and files can only depend on variables, functions, types and files defined earlier. The benefits of this are the fact that a circular dependency is not possible by default and extra clarity with “what depends on what”, which helps during code analysis and PR reviews Ehm. So it's like C... with no forward declarations?
- veber-alex 2y agoI don't understand how this is called an advantage. Dealing with cycles in Python is a total pain full of cryptic error messages, while in Rust cycles are fine as all top level items "come to exist" at the same time so they can depend on each other without any issues, and it makes refactoring a breeze. Sounds like a compiler limitation touted as a feature.
- p4bl0 2y agoNo it's not the same thing as in C. What they try to explain but quite badly phrase is that F# (or OCaml, on which it is based) is lexically scoped, values of non local variables are captured in definitions (so they must exist at that time, but also and more importantly they cannot be changed later because of the immutability by default). In C you can have a function using a global variable, and change to this global variable will affect the function behavior.
- pjtr 2y agoThis seems fine within a file, but isn't this problematic across files? Now the file order is significant, so not only is the Visual Studio XML project file is an essential part of the language semantics, you also can't organize your files in subdirectories freely? Or did they fix that at some point? How does that scale to larger projects?
- neonsunset 2y agoMore expressive nature of F# means you don't have that many files. C# is luckily and finally moving into that direction too. There was no reason for "one file per class" policy anyway, but it was still widely adopted historically. Here's an example of a worst-case scenario (GUI frameworks and the extensions have notoriously huge amount of code): https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/Avalonia.FuncUI.fsproj#L31-L187 https://github.com/fsprojects/Avalonia.FuncUI/blob/master/sr... But realistically an average project would look closer to this instead: https://github.com/DiffSharp/DiffSharp/blob/dev/src/DiffSharp.Core/DiffSharp.Core.fsproj https://github.com/DiffSharp/DiffSharp/blob/dev/src/DiffShar... Once you have enough files, it might be a good idea to factor out separate concerns into different projects.
- brikym 2y ago> No nulls by default ...While many modern languages added some control for doing more null checks to prevent NullReferenceException, F# avoided them from the inception. This means such exceptions are nearly impossible A great feature that Golang couldn't get right years later.
- topspin 2y agoThe fact that golang was designed with the "billion dollar mistake" as recently as it was is pretty astonishing.
- brikym 2y agoYes! And people will defend this awful language!
- topspin 2y agoI don't go that far. Mistakes were made, but golang has great properties as well. I'm just amazed that, given that golang's inception is relatively recent, somehow this old lesson had not been learned by the designers. Accomplished and learned people created this language. How did that happen?
- veber-alex 2y agoGo's design is laser focused on fast compile times at the expense of everything else.
- fire_lake 2y agoWhich is crazy. Even at Google scale the bottleneck to delivery is human reasoning about code changes, not so much build times.
- topspin 2y agoWhile it's true that fast compilation was probably the primary asperation of golang's design, it wasn't the only concern, and there is nothing about eliminating nullability that would have compromised compile time. So I'm left to imagine that they just didn't know.
- 6gvONxR4sf7o 2y agoComputational expressions [0] seem like a really cool language feature, but i’ve never used f#. Has anyone used them or seen them go well/poorly? Also curious what other languages’ alternatives there are, besides just do notation. [0] https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
- fire_lake 2y agoThey are used everywhere in the codebases. I think the main complaint is they are not as powerful as Haskell (you don’t get monad transformers).
- moi2388 2y agoF# is wonderful. And every iteration of C# I see it go more and more in F#’s direction and this makes me incredibly happy.
- DeathArrow 2y agoThey were discussing bringing discriminated unions in C# since at least 10 years ago. Still didn't happen and they are still discussing it and making commitees that hold talks about how it should be implemented.
- neonsunset 2y agohttps://github.com/dotnet/csharplang/blob/main/proposals/TypeUnions.md https://github.com/dotnet/csharplang/blob/main/proposals/Typ...
- moi2388 2y agoTrue. It will happen eventually. Probably in 5-10 more years :p
- foretop_yardarm 2y agoIf you’re a python user, F# is an excellent next step to making your code safer, easier to maintain and more performant.
- akkad33 2y agoThe functional syntax puts people off and the DotNet libraries are an uphill battle
- aksss 2y agoAnything new or different is an uphill battle, but I have a hard time believing that anyone who has spent even the slightest amount of time with pip and conda, getting their python execution house of cards built.. just.. so.. is going to struggle with .net libraries and packages. Edit: or do you mean the comparative lack of libraries?
- aksss 2y agoPlug for csnakes.. https://tonybaloney.github.io/CSnakes/ https://tonybaloney.github.io/CSnakes/
- akkad33 2y agoYes the comparative lack of libraries and also the roughness of existing ones. I've only toyed a bit with F#, but getting libraries to work that were designed for C# were a bit of a struggle unlike Python, were the resistance to get something to work the first time is low. The inconsistencies would turn up but usually much latter