Why Use F#?
fsharpforfunandprofit.com
fsharpforfunandprofit.com
f# and also Ocaml strike for me the right balance between practicality and correctness (strict by default, no insistence on purity), but still immutable, good concurrency story, functional first with the ability to write imperative code easily, great type inference etc..
Given that so many mainstream languages are piece by piece moving into the same direction and adopting the ML family approaches I have no idea why not more people are moving directly to F# or Ocaml.
This is a sincere question and would love to find good excuses to adopt OCaml as my primary language of choice.
OCaml has quite a neat ecosystem, though. Especially in terms of quality. There are a few major and a bulk of minor groups that write libraries for different purposes, such as:
* MirageOS -- people behind a bunch of a high quality system libraries, there are tls (in pure ocaml) and various cryptography primitives, filesystem drivers, tar, zlib, full tcpip stack, http server, git (in pure ocaml, not a mere binding), irmin (a git-based key-store database with concurrent access), dns and some other [1].
* Ocsigen -- webdevs, authors of Lwt (monadic concurrency library), js_of_ocaml (ocaml to js compiler) and related stuff [2]
* Jane Street, Facebook, blumberg -- reason syntax, bucklescript (alternative npm-ecosystem-frienly javascript compiler), various libraries for serialization, containers etc.
* Others
Opam [3] has quite a comprehensive set of libraries pretty for every purpose: data serialization, interaction with other langs (python, R, beam Erlang/Elixir), servers, db bindings, stuff for system or web programming. Some stuff is absent, but it's definitely not a scorched field, and most of the time the benefits worth writing an absent binding or two.
That makes Ocaml sound pretty attractive on the portability front.
A question for anybody here regarding portability: Is it viable to maintain a portable core using a subset of Ocaml (something like Standard ML maybe - no objects) and compile that in F# using Ocaml portability mode?
For context, I've read this question on SO from 2010 [0] but I'm looking for some more 2018 perspectives from HN people.
[0] https://stackoverflow.com/questions/4239121/code-compatibili...
But for example, you'd have to avoid using async/await in F# and instead opt for some library that has surface-level compatibility with OCaml's Async or LWT and working with .NET libs would require you writing wrappers for the OCaml standard library.
>it would certainly be possible to share 90% or more of your core code.
It sounds like maintaining parallel code bases in Ocaml and F# with the same basic design and file layout might work quite well for the core.
BuckleScript and ReasonML are solid for the frontend, though. I would recommend them without hesitation. For the backend, F# could be nice but as I mentioned, you would share almost nothing between them. If you're looking for a universal (i.e. same language on BE/FE) stack there are many options today, but a classic one is https://ocsigen.org/eliom/
It certainly sounds more attractive than writing everything in Javascript and using Node!
I'm interested in writing a portable, commercial 3D CAD modeling library. F# has already been used commercially for some years for 3D CAD on Windows. So F#, when compared with Ocaml, is a relatively easy sell into that market as it doesn't add another dependency.
I didn't know there were any other attempts at a "universal" platform since Meteor. Thanks for sharing! Please let me know if there are others that you think are worth learning.
Here's one for Scala (and Scala.js): https://udash.io/ . It has a lot of cool concepts, like out-of-the-box push notification support with WebSockets. And I am more familiar with Scala than anything else so it is attractive. The only thing that gives me pause is that I've used Scala.js in the past, and its compile times are not something I want to deal with again after using faster transpilers like BuckleScript.
Finally, the one I'm keeping my eye on is https://dockyard.com/blog/2018/12/12/phoenix-liveview-intera... . The idea here is to serve static HTML with a minimal bit of JavaScript needed to maintain a live connection to the server, over a WebSocket, and drive dynamism that way. Think React+Redux, but driven from the server side. The client can be mostly a dumb client again. This one has a promising future, with lots of optimizations and benefits falling out of using the Erlang runtime properly.
Both F# and OCaml have a lot of great features and peculiarities, and it's not worth of ignoring them for the sake of portability unless you use F# and OCaml as an intermediate language, as F* people do. Just choose a more suitable language for your needs and use it.
- Indentation delimited blocks vs curlies
- CLR vs JVM
- Whitespace vs Parenthesis for function calls
- Currying by default vs currying optional
Despite all this, when you actually start coding, it's remarkably the same:
- Immutability by default, transformations rather than mutation
- Less classes with embedded implementation logic, more "dumb" records with external functions
- Structural pattern matching
- Tagged unions
- Type inference
- Convenient definition of record/struct-like data types with free copy-constructor
- Operator overloading
- Easy FFI to external libraries in a different paradigm
- Easy "dropping down" to mutable, imperative code (e.g. for performance, or interop)
- Both have lots of syntactic and semantic warts and corner cases, though few enough you can live with them
- Garbage collected, multithreaded, JITed runtime
- Both compile to Javascript
While every single feature looks totally different on the surface, starting with a totally different syntax, the two languages are more the same than different. If you look at the tutorials linked from that page, all of them can be translated almost line-for-line from F# to Scala (and vice versa: take any random Scala tutorial, and you can trivially translate it line-for-line into F#)
Scala brings with it a bigger ecosystem, both in Scala and from the JVM, and better tooling support in general (Both Scala-specific, as well as general JVM tooling which all works with Scala: profilers, debuggers, package managers, ...), and slightly more seamless platform interop (Scala <-> JVM is less jarring than F# <-> C#), which is why I ended up sticking around.
I bounce between Scala and Kotlin. But as a Linux dev I find the JVM far more forgiving.
Returns the suggestion to switch Fsac.Runtime to netcore after I get the error fs0039 HtmlProvider is not defined even though Intellisense recognises it..
...refer below
That said: it seems it's finally coming around, as .Net Core matures and gets more mature secondary tooling, a lot of the little blocking issues can finally be addressed.
[1] https://github.com/dotnet/corert/blob/master/Documentation/i...
- JVM is less efficient for generics than the CIL (casts happening at runtime underneath).
- I've read about horror stories about tailcalls in the JVM world.
- There's no way to build an iOS app with Scala (i.e.: https://stackoverflow.com/questions/13460780/any-way-to-use-... ), while you can do easily with F# thanks to Xamarin.
And there is another way paying for GluonVM.
EDIT: corrected my statements based on comment below.
You can grow the build quotas as well to support larger applications. Furthermore, you can use the open source pieces of Codename One for free without the build servers. There is no restriction on that.
Trampolines are a common technique to implement tailcalls on platforms that don't support them natively. What are the horror stories then?
Why would you bother with F# or Scala when iOS has Swift?
Precisely! because the bytecode doesn't know about generics (it's syntactic sugar in higher levels, i.e. Java), then casts need to be performed at runtime (e.g. when getting an item from a collection).
> What are the horror stories then?
https://stackoverflow.com/a/18196685/544947
> Why would you bother with F# or Scala when iOS has Swift?
Haha, thanks for agreeing with me that Scala is not good in this regard. When I choose F# over Scala is because it can run in any platform. I'm not constrained.
Regarding TCO, that's a well known limitation of the current Scala compiler. Hardly a "horror story".
Let me assure you, there are plenty of platforms where F# is nowhere to be seen. Thus, "can run on any platform [I care about]", which is a different set for different people anyway. For example, F# does not run on JVM, does it?
> As for regular objects, no casts are needed.
Are you sure? See https://stackoverflow.com/a/10126425/544947
> Hardly a "horror story".
F# doesn't have this limitation and F# does tailcalls by default instead of having to explicitly remember to decorate it with the @tailrec attribute.
Yes, you are right, I didn't consider the checkcast instruction.
Yes, F# does not have this particular limitation, but has few of its own in different places. Most notably, it lacks HKT (arguably, because of CLR awareness of generics).
BTW, alternative approaches to stack-safe recursion do exist in Scala. For example, https://github.com/slamdata/matryoshka
And guess what? it doesn't have it because F# doesn't run on the JVM! If it run in the JVM, it would have it. So your obsession with "runtime" as a platform not only not useful, it's asking for trouble! ;)
@tailrec is not necessary to enable tailcalls.
All the annotation does is error if a function is not able to be optimized for tail calls.
The (attempt at) optimization takes place either way, you don't need the annotation unless there's some doubt in your mind.
Just watched this video about Scala 3 last night and the list of features Scala pioneered in a mainstream language is fairly incredible.
Also, you haven't experienced implicit typing until you have used F#'s ridiculously powerful approach to it (relative to C# anyway).
Pattern matching, for starters. It's not just chained if-statements on steroids; F#'s decision to make partial matching emit a compiler error is a real sea change in terms of the level of compiler support you get in guarding against unintended consequences in an evolving codebase.
Type providers. They let you interact with external data sources with about the level of ceremony you get in a dynamic language, but are still statically typed. The SQL type provider is particularly impressive. Not only does it generate your DTOs for you without ceremony, even when you `SELECT *`, even when the schema changes, but, if you make a mistake in an inline SQL query, you'll get red squigglies under exactly the spot in the string where the error is, just like if it had been a syntax error in the F# or C# code.
Computation expressions. F#'s equivalent of Haskell's do notation. C# accomplishes similar levels of purpose-specific expressivity in some specific areas - LINQ, async/await, etc - by adding syntactic sugar to the compiler, which means only the C# compiler team gets to do it. Computation expressions let you roll your own.
Currying and partial application. You can achieve the same result in C# with higher order programming, but it gets messy quickly. Also, there's an argument to be made that, similar to how objects are heavyweight closures, dependency injection is heavyweight currying.
The reason is that a set of algebraic types in F# is effectively bundle of types that are collectively sealed. In C#, you can really only seal the terminal classes in a cluster of types, which means that anyone else can come along and add a new class to the type at a later date, after the initial module is compiled, possibly even at run time. That undercuts your ability to ensure that a branching statement is airtight.
I believe C# also still lacks active patterns, which are a pretty killer feature if you're looking to do data-oriented programming.
if (num.IsNotPrime(out var a, out var b))
WriteLine($"{num} = {a} × {b}");Much like how the compiler assists you when writing subclasseses so that you've implemented all the required methods, real Pattern Matching (F#) gives you the same guarantees from the compiler that you've handled all the possible cases appropriately.
Exhaustiveness checking is what elevates pattern matching to the other side of the expression problem, which is about getting feedback from the compiler to help you write programs.
a glorified switch statement does not help you do that, and so you still have to write subclasses to get compiler feedback.
This holds for a lot of C# vs F# issues... There is a fundamental difference between "it's valid, but our tooling hides it from us" and "the execution environment guarantees that it can never happen".
The single pass compiler, functional foundation, currying syntax, and other features that provide guarantees simply can't be replaced with equally robust syntactical sugar. Much in the same way that writing imperative programs that follow OOP principles in possible, but will never give you the system level guarantees that a compiled class sytem will.
It makes accidentally creating circular dependency graphs, which can be a source of technical debt, difficult to do. There is still a facility for introducing mutual recursion, but you have to do it explicitly.
But I hope I can break the trend myself: http://github.com/knocte/gwallet . If you want to learn F# by contributing to a real opensource project, you have a chance now.
Also uses MonoGame, and its all running on dotnet core. Reasonably sizable, though still more of an exercise than production quality.
Not to be rude, I just honestly want to know. There is quite a bit of hype around C#, F#. But every time there is a comparison to other languages it seems to skip over the fact that you much have a windows computer running Visual Studio which is a big disadvantage to some people. Quite honestly, they are great languages. I just don't want to buy in completely to Microsoft
.net core, which is intended to be fully cross-platform is the future of .net.
To me .net core seems more like just a buzz word to prove that they like open source and anyone can use their software. But there isn't any way to monitize it so there isn't any reason for them to focus on it.
also, on a technical point, .net core is fast, faster than .net framework and mono.
F# is fundamentally a .NET language ... It's impossible to divorce
the two, even if the target runtime environment is not necessary a
.NET runtime. Those other environments inherent language design
decisions made with .NET as a target runtime. The .NET runtime
with .NET Core is indeed minimal, is natively supported just about
everywhere, and was built with cross-platform in mind. F# is a
part of this, for better or worse.
I like F# a lot, and to me it comes across as something of a cleaner, more modern OCaml. I have zero interest in .NET and its toolchain, and I don't want the baggage of its runtime or VM.Come on, surely you can make a non-.NET dialect of F#. Sure, not every .NET F# program will be portable to it. There must be some considerable abstraction in F# that isn't tied to .NET.
Can you make F# the language meaningful on other VMs? Not really, as F# is a deep, deep, .Net language.
This isn't about abstraction or syntax, it's that every concept, feature, and element of the toolchain bases itself on .Net capabilities and considerations. From referencing libraries, to scripting, to type generation at specific points in the compile cycle to support Type Providers... Async computation blocks...
Remember, F# came from MS research based on the established working .Net framework, and was tighly tied to fundamental framework improvements (like generics and dynamics). It was built by hardcore .Netters, it's the first "true" .Net language, and it bases major language features on deep-down .Net capabilites not found in other VMs.
The point of the quote is that if you were to try this, at best you'd get "OCaml Over There", not "F#", since F# without .Net is "OCaml". It's not the syntax, it's the deeply intertwined nature of everything else.
What are "dynamics" in this context?
>and it bases major language features on deep-down .Net capabilites not found in other VMs.
Can you give some examples of that?
The differences between the two languages are primarily in the way it integrates with the .NET platform and many assumptions on it.
If you wanted something similar on say, the JVM, starting from OCaml, you would make many different design choices and the result would be a very different language.
For example, the whole type system is based on .NETs type system. interfaces, subtyping and generics, properties and indexed properties, which are quite different on the JVM and other platforms.
F# usually relies on having attributes (annotations in Java) for compatibility with other .NET languages like C# where certain features did not fit into the OCaml syntax and semantics cleanly. These also wouldn't transfer over to other platforms very well.
Some features which F# has that could transfer over to other platforms include measure types, active patterns, and type providers. I believe some of these have already made it to other languages. Gosu, for example, on the JVM had a feature similar to type providers before F# got them, so you could argue that F# borrowed that feature.
This is a F# -> Javascript compiler and environment, itself running in your browser (in Javascript, obviously).
https://github.com/kjnilsson/fez
This is a project running F# on BEAM (Erlang).
So yes, of course you _can_ write a compiler from F# to whatever platform you choose. It's just a really major effort, in no small part because F# is a way, _way_ higher-level language than C (you'll remember 'worse is better' - a big deal with C is that it's easy to write a compiler for).
We are still feverishly at it in 2018 and there is no end in sight.
> It's just a really major effort
That is neither here nor there.
To everyone else - maybe I should have asked a better question, but it's quite clear to me now that people are in fact using this in production. That's great. My only question now is, what is Microsoft's strategy here? There's no money flow with .net core as far as I know, so why put in the effort?
Plus, Microsoft wants to get back in the game on mobile, so they need at least a platform, if not an OS. If they can put .NET reliably on top of Linux, Android, iOS, they can probably find ways to monetize that.
Traditionally MS was laughed out of vast swaths of academia, research, and Enterprise solutions. Now, they're making ever more bank off of Azure, and want to get their products deeper into those markets where being Linux friendly, cross-platform, and all the rest are "must have" features. That's big money, and future growth.
At the same time: their current breed of engineers also struggles with some of the historic windows nonsense, and it's becoming ever less profitable to maintain. So it makes sense even for MS to transition a bit away from legacy MS.
SQL server runs on Linux now, MS hosts Kubernetes cluters and has Linux bundled in Windows, and Azure scaling is always cheaper when not paying OS licensing fees. MS stands to win a lot by having a relevant development platform, MS stands to win a lot being the tool provider of choice for cloud development, MS stands to win on cloud hosting and growth, and MS stands to win a lot with upselling to captive cloud customers (BI, BizTalk, OMS, Analytics, etc).
.Net Core is the free razor, everything else are the high-margin blades :)
We[1] have multiple teams working with it right now (we're strangling our netfx 4.6 monolith), and some of those teams have already pushed their work to production.
The big advantage that I've seen is that it puts teams in charge of their own destiny. I remember the upgrade from netfx 2.0 to netfx 3.0: it was awful. The entire codebase had to be upgraded. Customers had to be upgraded to netfx 3.0. If another vendor futzed with and broke the machine.config, we'd break. With netfx you are perpetually behind the curve and at the mercy of the admin, especially if on-prem is a concern. netcore is xcopy deployment, runtime and all. You can use netcore on alpine[2] (netfx only works with Windows containers).
> there isn't any reason for them to focus on it.
1. Even if nobody was using it, I bet Microsoft would use it themselves. It is so much better than netfx.
2. Azure. It does run outside of Azure, obviously, but the Azure integration in VS is a powerful bait and hook.
Plus, for something that there's no reason to focus on, they are certainly putting a lot of focus into it. Even if I haven't figured out the true reason to focus on it, there clearly has to be one.
> There just aren't many available alternatives to the frameworks and packages
That was an issue up until, maybe, a year ago. Most packages have netstandard (a build target that works with netfx and netcore) support nowadays. If they don't, they are probably unmaintained.
[1]: https://www.k2.com/ [2]: https://hub.docker.com/r/microsoft/dotnet/
We are a tiny bit miffed at some missing features, though (especially in System.Reflection.Emit).
It's definitely not just buzz, it just takes time for a company to begin adopting a radically new platform with so many differences to it.
I also have many friends in other .net based orgs and they've each got similar things happening in their companies.
Release of core happen on a pretty regular basis and we've not seen any issues with Microsoft not putting time and effort into it.
I've been using TypeScript as my main language for the last couple of years since leaving Microsoft. However, I often find myself really missing how well organized C# was. The reason I don't switch back is the ability to deploy code in a web browser.
What more do you need? :)
Today, the old "run visual studio on Windows" constraint is more of a "you probably want to code in something that understands the language well, so Visual Studio, VS Code or Rider – but you really don't have to".
1. Release an easy to use web framework that deploys easily. (Rails clone)
2. Release an IDE which can graph from the command line (R studio or Spyder clone)
If you already have these (say a subset of .Net or visual studio / vscode) then the tutorials are misleading because they don’t seem the same.
https://github.com/giraffe-fsharp/Giraffe <- thin layer on top of ASP.NET Core
https://safe-stack.github.io/docs/intro/ <- slightly more opinionated but also .NET Core based.
I tend to mix F# and C#, Giraffe is great for sticking a slim web API or interface in front of .NET Core applications that use a combination of F# and C#.
I'm not a web developer, but I have found it extremely simple to write some basic web apps using this.
After going through a dozen languages, and listening in/reading scads of debates on languages, I think the author here misses the point.
Don't get me wrong: the points he makes are valid, and they make for a great language. Where I think the problem is when discussing languages is that languages are an ecosystem. They're groups of people, tools, message boards, IDEs, meetups, and so forth.
F# is great on the things he mentions, but the real strength is the way F# can take a bunch of dotnet guys and slowly move them towards pure functional programming without there having to be a huge learning curve. Like C#? Like your objects and classes? Fine. Do that. Like you FooBar .NET libary? We've got that too.
From your favorite IDE to the places you hang out, it's all the same. Just now with functional programming.
F#, in my mind, is first and foremost a training language, and I don't mean that in a bad way. It exists in an ecosystem where it naturally helps a bunch of devs learn new stuff. (As opposed to most languages that do some core things, then keep adding crap on top year-after-year)
Which brings me to my only criticism of the language: we're growing a community of wannabe Haskell/Erlang guys who are frustrated doing hook-the-wire-up C# in their day jobs. That can lead to language elitism and frustration on everybody's part. I'm not sure how to solve that. It's probably a good thing to have devs interested in upping their game. I think that if you want to move on to a more pristine language, you probably should do that. Understanding F# as an intermediate/training language for those interested in programming in general is a good way to keep needed context. If you expect it to be something that it's not, it's going to lead to frustration.
My biggest technical frustration with F# is just what you pointed out: they started down the OCAML route, then pulled back immediately after somebody figured out it would lead devs away from MS. Now all I hear about is how F# will integrate better into existing MS stuff and complaints about how the C# guys are copying F# stuff (and badly). None of that I'm interested in. None of that helps devs.
And I believe your and my observation are related: the more MS tries to keep F# in the fold, the more tension it's going to build between devs who want to branch out and those who don't.
Two years later.. and very recently the .NET Core story started to work well, tooling improved to quite workable state, and in combination with C# it's very strong mix of practicality/performance + complex flexible abstractions and correctness.
Over that time F# has added quite a lot of low-level performance features (on par with C# - Span/Memory<T>, ref structs, struct tuples/unions, voidPtr, etc) and they just work. Build time is probably the main concern now, I have to disable building F# projects when they are in a solution but not touched because even on i7-8700/16GB it's very noticeable.
Two weeks ago I needed text parser and picked familiar FParsec. It's one of the fastest one in .NET (including C# ones) and is a mix of C# for low-level stuff and F# for powerful abstractions. I refactored it quite substantially and tooling was finally nice. But my attempts to micro-optimize it yielded only in substantially reduced GC due to the support of value structs and Span<T>, throughput was already quite optimal from .NET perspective (only c.<5% gain probably due to GC), so if used with care F# could be as fast as C# (which BTW is native-like fast when also used with care).
I believe such mix is the winning combination: C# is best for low-level high performance stuff, F# is best for complex things such as recursive data structures, analytics and so one.
My big concern is that F# community is great but often F#-only focused, e.g. reinventing existing C# libraries just because it's not F#. This isolationism from .NET as a uniform platform led for example to things such as F#'s `async` is better than Task Parallel Library (C#'s async/await machinery) in theory/design, but TPL is so much superior is usability, performance and deep platform integration but F# cannot use it directly. Without native TPL `task{}` F# is not a fully-featured .NET Core citizen but a niche language for specific tasks where it shines, e.g. to write a AST parser for a new query language. Sad that MSFT invests so little in F#, but the language is definitely is alive, is improving and is worth using.
Anyhow I am with you that this is one of the problems I have with F#. Interop from F# to C# is generally pretty bad.
I am with you in thinking, that there should be only one mechanism and that C#s async is superior...
Let's agree on "replicating some of its great features". If you look at what C# makes of them, more often than not, it's a hack. Maybe one that's better than what C# had beforehand, but a hack nonetheless.
Example:
`async` in F# is not only amazing because of async IO, but its integration is really elegant, too: `async` is basically just a computation expression (if you used haskell: read "do notation"). C# OTOH built in a whole new class of functions that's hardcoded into the language (the same techniques also differentiate C#'s iterator blocks vs. F#'s `seq`).
Another example:
F# has pattern matching, which is tremendously useful because it is exhaustive (there are squigglies if you forget a case). C# 8 introduces switch expressions that aren't, but will throw an exception at runtime instead (i.e.: the detection code is there anyway[1], it's just used the wrong way).
[1]: AFAIK, the autogenerated `default:` IL code is omitted if the compiler can prove that it will never be called. Someone mentions that in the latest "What's new in C#8" videos.
However, since in C#, async functions also seem to boil down to monadic continuations, I see no obvious reason the F# way couldn't be optimized to the same degree (given enough determination and resources).
If there's anyone here with insight into the `async` implementation that knows otherwise, I'd really appreciate a comment on this :)
Edit: Andrei Alexandrescu had a nice latin phrase on this in a talk at DConf 2018[1]: «Quod licet iovi non licet bovi». There, he's basically arguing the same thing: It is very often more desirable to give the language user a tool they can use themselves instead of reserving it only for the language implementers.
[1]: https://dconf.org/2018/talks/alexandrescu.pdf Page 4
Since it's launch C# has reversed itself on fundamental language decisions and requirements to go ever closer towards F#s capabilities.
Unfortunately, thanks to F#s functional heritage and compiler, there are huge swaths of capabilities that can't be completely realized by C#. That leads to "almost but not quite" convenience features in C#, without any of the reductions of cognitive load or any of the systematic guarantees you get with a functional language.
C# is easily one of the best languages out there, but it's also accumulating a lot of ways to skin various cats.
Is this a good thing? It feels like saying "It's English without the periods or line breaks or capital letters."
Semicolons - If that's the main thing telling you where an expression ends, it's time to start taking your code formatting more seriously.
Parentheses - Still exist, but only for expression grouping and tuples. It's just that they aren't used as a function application operator. This admittedly takes some getting used to, but starts feeling easy and natural surprisingly quickly.
Importantly, function application without parens feels a lot nicer in F# than it does in Scala or Nim. I think the difference is that, in F#, adding parens around a function's argument list would actually change the meaning of the expression, and likely cause a compiler error.† In Scala or Nim, they're (sometimes) optional, which just creates this unnecessarily confusing situation, not entirely unlike optional semicolons in JavaScript.
† - If it's a 1-ary function, you'd be fine, because it would interpret the parens as grouping operators around the argument. If it's a 2-ary function, then it would probably cause a compile error, because parens around a space-delimited list are (I'm pretty sure - it's been a while since I last worked in F#) not valid syntax. If you add commas, so that it looks like a C# method call, it would then interpret it as a tuple, which would probably mean a compile error, unless the function has an overload that accepts a tuple of that arity as its first argument, and, even then, only if applying that version of the function doesn't somehow lead to a type error.
(Edited for clarity and extra babbling.)
Everyone indents anyway. So why need braces?
Most people write one statement per line. Who needs semicolons. I've often called it the most useless character in programming language history. Whenever I switch from a language that doesn't use them to one that needs them, it's a horrible transition. I have to mentally remember to add this character at the end of most lines.
Parentheses for function calls - in some contexts they are helpful. In most, though, they are not needed. Wherever they are needed, you will have them in F#. For people who went from Python 2 to Python 3, you'll know the pain of suddenly needing parentheses for print statements, and for most of those people, you will not see any benefit to adding those parentheses. Extend that to other functions.
I don't indent. I let the editor do it based on braces.
As an example, in a for loop in Python, I need to press a single key for indenting[1]. In a language like C, it would be 4 keystrokes - 2 for each brace. Come to think of it, this is true for if conditions, functions, etc. Pretty much all places you'd need braces in C. I'm having trouble figuring out where in regular programming in Python a braces would mean less work for the programmer.
Indenting is simply less work than inserting braces.
[1]Strictly speaking, for dedenting when I'm done with the for loop.
In the end you get used to almost everything.
I understand it's a matter of taste, but I don't understand why people insist on repeating themselves -- you're already going to have something indent your code for readability, why not have that just be what the language uses, too?
That said, you should know that in Python, at least, there is famous first-class support for the brace styles of many other languages, invoked by the brace operator "#". For example, if you want C-style braces you can simply write like so, using the brace operator to tell Python what you're doing:
def hello(): # {
print("Hello, world!")
# }
And Python will automatically understand it correctly!A more complex example uses Ruby-style "end" and conditionals:
def odd_or_even(num):
if num % 2:
return "Odd"
else:
return "Even"
# end
# end
Python's advanced brace-style parsing AI will correctly handle this. You can even mix and match brace styles within a single codebase, or even a single file, for times when your team just can't agree on one approach.curly braces or semicolons do not serve a purpose most of the time.
as F# is a functional language you do not require them to seperate statements as you always pass values...I hope you know what I mean.
Curly braces are everywhere, but they aren't used to distinguish contexts or end logical blocks, so you don't have the noise everywhere (increasing readability substantially).
Semicolons are used to logically distinguish list items. Semicolons are supported, but not required to terminate lines. This makes copy n paste easier for C# code.
Parentheses? It's a functional language... "()" is a valid value. Every lambda, tuple, parameter set, and value can be wrapped in them, and often must to be valid code.
In every case the reduction in line noise, superfluous characters, and inconsistent formatting is replaced with strict formatting requirements and strict variable definition requirements. That means better readability. It also means you can support multiline string literals and escaped variable names easily, further improving redability.
Does anyone reading this feel that way, or was it just FUD?
"One thing I noticed is that the compiler only crashes when building x86. It compiles fine for x64."
"Are we stuck on "Allowed but not officially supported" for now or are there any plans towards "Officially supported" ?"
Somehow F# isn't part of the full .NET team, as such it doesn't get the same attention regarding UI designers (Forms, WPF, UWP), database designers (EF) or deployment targets (IoT Core/.NET Native).
There was a Visual Studio release where they decided not to hold back the release, even though it broke a couple of F# tooling.
So there is that, on the other hand Microsoft seems to at least be willing to push it as a data science language on Azure.
All I hear from MS is that they love F# but the workhorse is C#.
In terms of language. F# is easier to learn and more practical to use for everyday programming. Haskell is more of an academic language, and takes a high level of expertise to utilize for real world development.
Haskell is a purely functional language which makes great effort to eliminate side-effects altogether. F# on the other hand, is merely functional-first, but allows side effects by explicitly marking things as mutable, or by utilizing existing .NET libraries which have side-effects.
It would be great to see an HTML minifier in F#. I've thought about building one as a way of learning the language. An F# based static site generator, similar to Jekyll or Hugo, would also be neat.
Compilation of F# is a confusing story to me. If it's still compiling to an IR, and getting JITted at runtime, that seems kind of inefficient in a world where Go exists. There's the CoreRT project, I think, that allows for precompiled .NET applications, but I'm not sure how F# fits in. I also read that all Windows Store/UWP applications are precompiled on Microsoft's cloud. I'm curious about compile-time flags and optimizations for F#, but they're rarely mentioned.
It really depends on your use case. If you're writing programs with very short run times, for example, then the time spent on spinning up the run-time and JITing the bytecode can amount to a significant portion of the program's execution time.
If you're writing a program that's going to run for several seconds or minutes (let alone hours, days or weeks), then the milliseconds spent JITing the bytecode just don't matter.
It's also true that, since JIT compilation happens just in time, it doesn't really have the luxury of being able to spend a whole lot of time on optimization. Depending on the kind of problem you're working on, that can make a meaningful difference. Fortran or C would still be my languages of choice for serious number crunching. .NET tends to be used more for I/O-bound or non-performance-critical applications, though, where that doesn't really matter, either.
Regarding JIT and Go, I've built identical programs in both and while Go is faster, its not by as much as you would think (in my example, 60ms vs 40ms). Go is much more verbose to write, but its output exe is all by itself without the hundreds of dlls .NET likes to lug around.
F# works with CoreRT just fine, with some small caveats (its sprintf/printfn functions don't work I think). I've modded one of my games to use it: https://github.com/ChrisPritchard/Tetris
- Single-case discriminated unions. I feel so unprotected when working in C# due to IDs usually being primitive types. You're never sure if you'll accidentally flip two `int` parameters in a method call.
- Automatic currying and partial application in combination with piping `|>`. Enables so intuitive and elegant code flow.
Performance characteristics are decent as well[1].
[1] https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
F# is based on a much more mature langauge, with mature concepts for handling the secondary and tertiary effects of those features currently coming into C# and Typescript. By adopting that mature language, F# started out "right" and hasn't needed much to fix it.
And in terms of work: checkout the templates for F#, the libs for F#, and the thoudands of examples on MSDN in F#... But more specifically, check the amount of low-level improvements, refinements, and user-friendly sugar the team has landed in years of late. There's constant improvement, but of a less "revolutionary" nature as the base design was so mature.
People confuse new shiny toys in IDEs with fundamental support. That's not necesarily the important thing... The convergance of functional languages and cloud native development is, in many cases, the important thing to MS, and is another area where F#s tooling/ecosystem is years ahead of the C# equivalents.
In general terms F# as a language is nicer than C#, but my real question is it good enough that you'd want to covert to it if you are mainly a group of C# programmers, and I reached the conclusion that it's probablly not simply becaus C#, in general, is not really that horrible to start with and a lot more people do things in C# and everything in the .NET world is looked at through the lens of C#. I asked a similar question on the F# communities slack, and beyond a few language features ( that are nice! comprehensions and discriminated unions, and more concise syntax with implicit typing ) it's really hard to find a reason. Part of the problem is there is very little in terms of libraries that are unique for F# that massively jump start you in any particular direction. What's more, quite a lot of F# code that fits in with frameworks that were built in C# often just look like C# written in F#. F# code written with F# oriented libraries are really nice and super concise, but it's a bit of a lonely world.
I think they are. F# defaults to immutable stuff. Everytime you write anything in C# and forget the word "readonly", you're opening the door for a race condition. Also F# is much more succinct, things that take dozens of lines in C# are just one line in F#, take a look at this quick guide I wrote: https://github.com/knocte/csharp2fsharp
It was essentially a C# subset with "static" removed and replaced with "isolated", with some other new stuff added. Code was separated into domains and actors, which could be safely used without the concerns on race conditions. Essentially erlang-like programming on .NET
- discriminated unions. DU types don't exist in C# or lots of other languages, and change the way you program
- complex match expressions (fortunately coming in C# 8)
- value tuples (thankfully arrived in c# 7)
- the pipe operator and partial application (another thing that changes the way you program)
- super implicit typing (its to var what var was to explicit typing)
- and its use of option/result types, along with compiler enforcement of all conditions.
Before I picked up F# properly, I looked at it as fancy but overhyped. But then, its a bit of a plato's cave type of thing: you don't know why `type A = B of int | C of string * bool` is awesome until you have used it a bunch of times.
Going back to a project with the C# mindset of `{get;set;}` everywhere, passing "records" into functions and not being able to prevent those functions to mutate them, it seems so unprincipled.
The other stuff in F# is also great, but even with none of it, the simple `with` operation is the thing that changes the whole game.
You don't have to remember/think/know:
-Possibility that somebody somewhere is unexpectedly effecting on you
-How to move data, it's just parameters and return values
-What object identity is
-etc.
It takes time to adapt to these constraints in a way you really don't have to think them. But as gain you can free quite a lot your mental load.
As result I feel that with F#:
-I feel significantly less stress
-It's easier to model complex system and understand/trust their behavior
-After 6-12mo I can constantly write clean and maintenable code. In contrast I am not very happy any of my C# projects after 6yr experience.
Yea yea not silver bullet but I love it.
https://fsharpforfunandprofit.com/posts/designing-for-correc...
That article made me feel like I'm kind of wasting some percentage of my life dealing with bugs that would just disappear if I was using a better language. I don't know what the tradeoffs are though but it did convince me I'm probably missing out on being more productive.
My only beef with F# is multi line expessions...indentation is sometimes weird.
programming languages are written to be read by humans and humans do better with start and stop points. if i've ever blearily looked at code at 3 in the morning,i basically run on autopilot relying on the braces and the semicolons to guide my eyes
F# is whitespace sensitive, so you need to stick to correct tab sizes anyway, and it becomes quite readable.
For types, you can also add `class`, `interface`, `struct` at the start and `end` on the correct indentation after its definition to show a clear boundary.
type X() = class
member this.X =
...
endI also think, that formatting code should be a non issue and should be handled by editor preferences.
The true problem is, that lots of devs think they write code when they truly define models that a represented by text.
Bottom line is: readability is very important, but we should have tooling that helps us with that. e.g: I want coloring for a block not to parse text for a closing brace.
Also, they only talk about units of measurement in the context of floats. Can I not have integers or rationals with units?
It is one of the best ML derived languages, but as it is, I rather wait for C# and VB.NET to keep getting features from F#.
I stopped learning F# myself for this reason in particular. I really enjoy the language but I just cannot stomach the F# community. The .NET community is small enough as it is, and F# is a fraction of a percent of that, but they are extremely vocal others and bully others for what seems like no other purpose than to gain personal popularity and sell books. If this community went away I think the language would do much better, or maybe there would be room for another functional language on .NET that could start fresh without a history of pain. The entire situation is simply sad.
P.S.
Can someone explain this?
// complex types in a few
type Employee =
| Worker of Person
| Manager of Employee listEmployee is a Sum Type i.e. it can either take a value of (Worker personObject) or (Manager [empObj1, empObj2...])
for instance, an binary tree would be
type Tree a =
| Leaf of a
| Node of (Tree a * Tree a)
Now, a Tree Int would be t = Node (Node (Leaf 1, Leaf 2), Leaf 3) abstract class Employee {}
class Worker : Employee {
public Worker(Person o) {...}
}
class Manager : Employee {
public Manager(Employee[] o) {...}
} abstract sealed class Employee {
enum TAG { Worker, Manager }
readonly TAG tag;
Employee(TAG t) {
tag = t;
}
public class Worker : Employee {
public Worker(Person p) : base(TAG.Worker) { ... }
}
public class Manager : Employee {
public Manager(Employee[] o) : base(TAG.Manager) { ... }
}
}
This is a bit closer to how it is really implemented. The constructors are internal to the outer type because it is sealed, making it a closed type. Interestingly C# rejects abstract & sealed on the same type, although this is accepted on the CLR.Discriminated unions are sometimes called tagged unions because of the way they're implemented. It's typically more efficient to check the tag on the object than it is to test its type. The tag is used when pattern matching over the object.
Wish it was easier to mix the two, it's pretty nice being able directly interface through dotnet, be even better if I could have fs and cs files next to each other.
It is still possible to have circular dependencies. Either by including the mutually related types in the same code file separated by the "and" keyword, or by using signature files to define the type signatures ahead of their implementation (which work similar to header/implementation files in C, C++ etc).
My biggest problem with F# is the bad tooling. For professional coding you need tools like static analysis, refactoring and so on.
with those you can use the knowledge of other to improve your code.
R# did a lot for C# in that regard.
You almost never have to specify the type of an object, thanks to a powerful type inference system."
As a C++ programmer, both of those sentences make me shudder. Lack of specified types reduces readability by an order of magnitude, at least for me personally, and especially with complex projects I end up spending a lot of time trying to guess "what is the compiler going to assume this object is"(looking at you, "auto" nonsense in C++)
Also, I agree that there could be a better solution - always use auto, and use an IDE which shows you the type inline. IntelliJ can do this for Rust. But unfortunately no C++ IDE has code intelligence anywhere near good enough to do this reliably.
I guess it depends on the IDE, here's what the one I use (QtCreator) can do for instance :
It's great on smaller projects and I have used it for few tools that I wrote - but the larger projects, no thanks. In general our code standard only allows auto if the type is defined immediately before it(so if you create a vector and then want a for loop immediately below it, then it's fine to use auto for the loop, otherwise no).
that's a problem with your IDE, I use QtCreator which leverages clang for parsing and gets it right the immense majority of time in my experience.
> but the worst part is that the debugger doesn't know either - so any time I get a crash with auto I need to spend additional few minutes to find the actual type(and the right template!) and cast it manually in the watch window,
this sounds like a deeper bug with VS. I use debugging with cdb, windbg, and VS IDE, and the debugger never had trouble with "auto" variables - I don't understand why it would, since in the binary debug info it's the actual type which is saved. Did you report it to MS ?
I don't know how large is your project, the main one I'm working on is overall a bit more than 300kloc and VS2017 had no problems with it last time I had to use it for reference.
Apart from that I also have an impression, not measurable, that since a couple of years using auto we somehow got used to it and don't have to rely on intellisense etc. Sounds like a contradiction, and might not have anything to do with auto but just C++ in general or even just the team becoming better, but it's like the code is more generic and cares less about exact types but still has less bugs because it's easier to reason about.
If you're using Visual Studio or Monodevelop, merely hovering the cursor over an expression will reveal its type as the compiler would infer it.
I personally write F# with most type annotations on functions, with the main exception that I omit "unit" on functions returning it, since it is usually obvious, and you will get a warning if you accidentally try to return anything else.
Well, the IDE shows you, inline, directly above the signature.
You're only missing type signatures when you have a type error (which will be telling you the types involved anyway...)