I'd argue that that's painting with too broad a brush. C# has picked up a lot of features to support functional programming, and has made great strides in reducing boilerplate and clutter, but there are still all sorts of things that F# has and C# either lacks, or requires a lot more verbosity to accomplish the same thing.
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.
I haven't actually used C#, or any .NET language, since before 7 came out. Based on what I've seen as a sideline observer, though, it looks to me like C#'s pattern matching and destructuring are just syntacitc sugar, and therefore still significantly weaker than what F# has. I don't think you can get to the level of type safety that F#'s pattern matching provides without F#-style algebraic data types.
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.
C# now has active patterns (which feel like the `is` pattern matching) in the ability to declare a variable as you pass it as an out parameter to an extension function, e.g.
if (num.IsNotPrime(out var a, out var b))
WriteLine($"{num} = {a} × {b}");
any kind of pattern matching without the ability to check for exhaustiveness defeats the safety they provide, which is need to make that comparable in utility and power to inheritance (i.e. so you can actually replace inheritance w/ pattern matching.)
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.
> pattern matching without the ability to check for exhaustiveness defeats the safety they provide
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.
I'm guessing that's a reference to how, in an F# project, files have a specific order in which they're compiled, and you can only refer to things that are declared previously in the current file, or in a previous file.
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.
To this list, I would add code quotations. You can <@...@> around any expression and get a syntax tree at runtime that you can explore, transform and even compile. While C# does have a similar feature in Linq.Expressions there are entire categories of (completely banal) C# expressions that cannot be quoted.
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#.
to #2 - FSharp.Charting should work from the REPL (though I haven't tried it myself). You can get the REPL within an IDE from both Visual Studio and VSCode.
I love F# and there's only one thing lacking in its ecosystem: not many opensource projects written in it. And I don't mean libraries, tools & frameworks, there are tons of those; I mean a real app.
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.
I probably don't need to use bitmaps as maps at all, really; Text files would work just as well. But using System.Drawing cross platform in .net core was an education in itself, so I think worth it :)
curly braces enable code readability, you know where to start reading and you know where to stop reading. the situation is the same with the semicolon.
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
If you use VS or Monodevelop, there's are options you can enable which show indentation margins, which is even better than braces. Seems like a non-issue.
Basically, you are discussing an attempt to move away from the purely textual, linear representation of program code (at least, in the way the programmer sees it). Yes, sophisticated tooling becomes very important then. But it is not always available.
I wouldn't say it's really sophisticated tooling. Many basic editors support visual whitespace in one form or another. Some insert a semi-opaque character in place of tabs/spaces, and others show rulers.
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.
as I have yet to see source code that is not properly formatted I do not agree.
I 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.
In my opinion it's honestly the best statically typed general purpose programming language.
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.
I moved directly from Python to OCaml and I have to say, I’ve never been happier. Special shout outs to Jane Street, as their open source software is really solid and a pleasure to use. The community is small but really smart. Overall I think F# and OCaml really nailed the programming language design sweet spot of powerful and practical.
Can you eloborate on what kind of projects you work on which has made the move easy from Python to OCaml. While I love OCaml I have not heard positive things about the library eco-system in terms of variety and maintenance. Perhaps, you could throw some light on that based on your experience, especially after giving up the eco-system Python provides you.
This is a sincere question and would love to find good excuses to adopt OCaml as my primary language of choice.
>I have not heard positive things about the library eco-system
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.
I'm looking at Ocaml again because of the existence (and quality) of the Bucklescript backend for Javscript.
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.
Most likely not. You could get away writing a lot of utility type functions between the two, but the libraries, async scene, module system, object system, etc. vary enough that it would be practically impossible to share any non-trivial piece of code. Which isn't to say that porting anything would be hard, most of the core code would stay there and you'd only really adjust the edges of your code so to speak--if you separate out access to libraries or try to port the APIs from one language to another (which would be easy in OCaml with it's module system) it would certainly be possible to share 90% or more of your core code.
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.
That answer hasn't changed, in fact as of today OCaml and F# have diverged more than they had back then.
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/
Thanks very much for that perspective and the link.
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.
Sure :-) Another one I admire is http://opalang.org/ . It too is based on OCaml, funnily enough. The last commit is from last year, though, so this is not a project on the rise.
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.
>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?
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.
i agree. f# is really nice and is very practically designed. it has very clean and consistent syntax. i wish more python people tried it. due to oop being perfectly fine in f#, one could write code in f# just as they do in python, and it would be superior in nearly every way.
TBH I think F# wins over OCaml just because of its mobile deployment story. It doesn't seem that OCaml's ecosystem has mature solutions for iOS&Android deployment.
I played around a lot with F#, and I really like it, but I got to this question of why use F#, and it is actually really hard to come up with a good answer to it, mainly because C# is really good and the real question in .NET is why use F# over C#. If you program with the same mindset of F# in C# then the differences are not super quantifiable.
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.
> If you program with the same mindset of F# in C# then the differences are not super quantifiable.
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
While those are nice things, they don't really bite me in the C# world. There's a lot of fuss about it in the F# world, but it really isn't that big of a problem in my experience. I do like the robustness of it, but in practical terms... it's only a minor point in F#s favor
C# with the good old .NET BCL has excellent support for multithreading, even if some language features could make it even better, there's no need for smugness.
I wish MS had continued support for their "Axum" project, or at least open-sourced it so that it could be continued outside of MS.
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
Speaking as someone who has been doing C# for over 15 years, and still professionally, but who uses F# almost exclusively in my private projects, the biggest things are:
- 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.
Speaking as someone who's been programming for nearly 40 years, C# since it came out in beta, and F# when it first came out ( though I haven't used it consistently since then). I know about all those things, I have done signifiant programming with F# and other functional languages. Like I said, I like F# and I think it is a nicer language and I like it is more functional, but in the broader picture, I don't think the advantages are that significant that you'd bet your products on it. I'd tend to suggest something like Elixir might be a better option. But you may hit a sweet spot where F# is a good choice... cool, but I think the sweet spot is quite small
For me, `with` is enough. e.g. `let output = { input with status = "failed" }`. For all those times you want to be able to return a modified value but not mutate the original. Once you're used to doing this in F# you take it for granted.
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.
I agree that mutability won't often bite professional programmers as you say. But as context is good to know that quite typical F# programmer has strong C# background like you. Individual features are often raised during discussions but point behind features is mind-shift (at least for me).
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.
I have never gotten deep into F# but have watched it from a distance for a while. I remember f# 1.0 and thinking this is cool but not fully baked. As f# has grown, I feel like because of or in spite of F#, C# has learned new tricks with each version. While I wish I had time to really ramp up and learn every intellectual curiosity I’ve had, I don’t feel like I have ever had enough friction with c# to “switch”. I’m working with very specific problem sets though so my case isn’t everyones. That said I’m still interested in F# and hope to get into it sometime...
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.
I've read on HN that F# doesn't get nearly as much attention and support from Microsoft as C# does, to the point where people expressed concern that F# might be put into maintenance mode.
Does anyone reading this feel that way, or was it just FUD?
Speaking for the tooling attention that is accurate.
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.
MS' Matt Torgeson explained that once. Their investment is aligned with the user base. There are millions C# devs, 100 Thousands of VB.NET devs and 10 Thousands F# devs. But in difference to VB, F# has a independent community with a strong focus on improving F#.
All I hear from MS is that they love F# but the workhorse is C#.
I've wanted to learn F#. I'm particularly curious about parsing and text processing, and wonder whether the pattern matching feature would work well for that.
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.
> If it's still compiling to an IR, and getting JITted at runtime, that seems kind of inefficient in a world where Go exists.
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
Curly braces - F# is a whitespace-significant language, so contexts are still plenty visible.
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.
It is because those things are simply not needed to parse or understand the code.
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.
Fair enough. I save on keystrokes by not inserting braces. I do have to manually indent once in a while, but the editor will usually figure out what I mean.
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.
All you are saying is personal taste and familiarity. Nothing wrong with that but I could argue every one of your points exactly the other way and would be as right as you are.
My editor understands when to indent in Python, and often when to dedent. When it doesn't know to dedent, I just hit Backspace on the next line to close the indented block.
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 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.
Having used and enjoyed F#, I ended up programming in Scala which is almost the same language, despite the huge superficial differences:
- 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 can echo this. I'm working in F# in my day to day. While I like the language. I find the tooling IDE and other essentials are missing. I spent several weeks fighting swagger generation client and server tools. Something that just worked on the jvm.
I bounce between Scala and Kotlin. But as a Linux dev I find the JVM far more forgiving.
I am new to programming...wanted to import and process tables from https://en.m.wikipedia.org/wiki/Megacity
Was using ionide on vscode But not working because .NET CORE is not supported
Returns the suggestion to switch Fsac.Runtime to netcore after I get the error fs0039 HtmlProvider is not defined even though Intellisense recognises it..
Re F# tooling and IDEs: sadly the churn around the transition to .Net Core has really hurt F#s tools. Things that were stable and working since inception, and enabled highly productive workflows, have been trampled by missing features and shifting boundaries on the new platform.
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.
Ultimately these higher-level requirements like JVM vs. .NET are the biggest factor in deciding a language. For example, my latest project need to run on Azure Functions (consumption plan, has cold-start) for cost reasons, so the deciding factor was "which language has the lowest cold start time?" If you're doing ML model design, you use Python because that's what the notebooks and libraries are written in. At any given moment, OS/cloud platform support, library availability, and desired app model has way more impact on choosing a language than design.
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.
> JVM knows nothing about generics. What kind of casts are you talking about?
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).
> 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.
I suppose you meant boxing/unboxing. If so, yes, that's necessary for primitive types. As for regular objects, no casts are needed.
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?
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).
> Yes, F# does not have this particular limitation
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! ;)
Is F#'s type system sophisticated enough to express type classes, higher-kinded types, and/or existential types? Scala's implicits and related language features can go a long way down those roads, but I know very little about F# other than "it's like Scala but on the CLR" and am curious what the story is over there.
I love F#, but it seems like the language is either abandoned or on life support by Microsoft - compare the feature development speed of C# and Typescript against F# and you'll see that.
Lots and lots of new "features" isn't necessarily a good thing.. Also F# already has many of the features that are being added to C# and TypeScript ;) I for one would advise Microsoft to sponsor more work on F# libraries, such as in data analysis & TypeScript interop..
C# is still rushing to get features that F# has had for years, with no hope on some major fronts. If F# were innovating that much it would indicate that F# was sorely lacking at launch, but it wasn't.
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.
Can someone please explain to me how you can use F# without each aspect of the development process being a Microsoft technology?
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
is it microsoft or windows you are against? basically all of the f# toolchain is open source, and it runs perfectly fine on all three major os platforms using either .net framework (windows), .net core (cross-platform), or mono (cross-platform). most people either develop f# in visual studio or using visual studio code. same goes with c#.
.net core, which is intended to be fully cross-platform is the future of .net.
I understand there exists .net core and mono. I'll give them mono. My problem is I haven't seen a single example of a practical application written in .net core or a company that uses it, everything is .net framework. There just aren't many available alternatives to the frameworks and packages that are those who use .net framework take for granted. I hear what they're saying about it's the future, but I have yet to see the fruit of it.
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.
well, i don't know what to tell you. i am not really here to defend or market for the world's most valuable company. all i know is that my understanding is that .net core is the future of their .net stack and they are doing things that show that. for example, with .net core 3.0, there are desktop packs for uwp, wpf, and windows forms so that you can develop even your windows apps for .net core. so even on windows, .net core is quickly moving to replace .net framework for new projects. of course old projects will likely lag being so attached to the .net framework. that's the case for any technology platform transition.
also, on a technical point, .net core is fast, faster than .net framework and mono.
quite the contrary, people are quickly moving away from the .net framework towards .net core, which is now objectively better and moving at a fast pace. I help maintain a popular open source library for .net. We develop on MacOS using VS Code (only use Windows for testing) - the experience is good. We have many large customers (brands you would know), and .NET Core support is important to pretty much all of them.
we're running a ton of .net core docker containers at my company. C# is really a great language and now you can run it on anything. If you haven't seen it yet, it's because you aren't looking that hard.
The last time I brought this up on HN, I received a comment [1] from one of the people who work on F# at Microsoft:
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.
It strikes me as nonsense. Let's take the paragraph and replace "F#" with "C", ".NET" with "PDP-11", and "Core" with "V6 Unix".
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 a language that looks like F# and compiles? Sure.
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.
>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,
What are "dynamics" in this context?
>and it bases major language features on deep-down .Net capabilites not found in other VMs.
F# without the .NET platform is essentially OCaml.
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.
Mostly. It does add some novel new features which could be reused on other platforms, but many of the features are tightly linked to the .NET base class library, and would not translate cleanly over to other platforms (certainly possible to simulate them, but you would probably want something which integrates better with your VM)
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.
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).
Thanks, I think we find ourselves in the same boat.
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?
Azure. Microsoft revolves around Azure these days, if they can provide a better dev experience that leads to more people using Azure they're happy to spend money on it.
Not just Azure, cloud. Office can be extended with .NET. And Office is now Office 365.
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 :)
> I haven't seen a single example of a practical application written in .net core or a company that uses it
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.
What? Do you even work in the industry? Everyone is moving more and more towards .net core. I work at a big old school finance company and all new development is done with .net core
We migrated the compiler and virtual machine for our DSL, our ETL pipeline, and our machine learning code (traditional & deep) to .NET core on Linux earlier this year. We are impressed with the performance and stability, and the developer experience has significantly improved since the mess two years ago.
We are a tiny bit miffed at some missing features, though (especially in System.Reflection.Emit).
I'm not sure where this is coming from. I work at a ftse 100 company and all of our newner microservices are .net core. Almost every team in the org has some .net core running and we're slowly moving framework projects over to it.
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.
When I use F# on Linux (my main machine) I use VS Code on Linux and it seems to work fine once setup properly and it has all the minimal features (e.g rename, find usages, etc). I've heard Rider as an IDE has F# support now as well. You typically use the command line with the "dotnet" command to create projects and such. Still Microsoft technologies however they can run on Linux.
That used to be true, but times are changing. Visual Studio Code + .Net Core mean you can program in C# and F# even on a Mac now.
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.
Writing F# in JetBrains Rider on a Mac, and running it in Ubuntu based Docker image in AWS.
My colleagues are working on Windows with Visual Studio and Ubuntu with VS Code. True multi-platform, multi-tool development on the same codebase.
While this was definitely true five years ago, I'm happily writing C# on a Mac with Rider today, having a great experience. Except for when looking up old documentation mostly relating to .NET Framework, I never feel like a second class citizen anymore.
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".
If I want to learn F# is there a good IRC/slack channel I can get on? I'd like recommendations for libraries. I have a project I could throw at it for fun/ learning.
P.S.
Can someone explain this?
// complex types in a few
type Employee =
| Worker of Person
| Manager of Employee list
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.
Ok, the idea was to communicate to someone who has never seen an ADT before what kind of thing it is, rather than a full decompilation of how it's really implemented, but thanks for that too.
Wow, and I was just looking at mixing this in with a API C# dotnet core app I was playing with.
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.
One thing about F# is that the ordering of compilation units is essential. You need to list your files in the order they are to be compiled because you cannot have circular dependencies between the units. This leads to making better decisions about code most of the time.
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).
> …because C# was so good at stealing its best features.
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.
I think so, yes. However, I'd attribute that to F# having the first implementation and not enough clout to influence the central .NET implementation, like C# did. AFAIK, there's another computation expression builder using Task<T> in FSharpx that performs better.
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.
They have different design goals. Async in F# works better for F# applications. Tomas Petricek wrote a couple good articles [1][2] comparing both approaches to async computations.
From a language design standpoint, it's kinda damning...
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.
Another thing hindering F# adoption is the expectation that people will want to use your libraries from C# too, which leads you to using a C# compatible subset of F# which does not leverage its main advantages over C#.
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.
Yes, F# was the first with async. Interop with C# is native, all code is compiled to IL and JIT-ed together. Problem with TPL is that it is supported by Roslyn at the language level. The C# compiler rewrites async/await into very efficient state machine. F# cannot natively integrate into that state machine and a long async call chain is always broken on C#/F# boundary, while in C# async-only code could be compiled in a big state machine and with ValueTask (and even better IValueTaskSource that is used in Streams and Sockets in dotnet core 2.1+) a long running while(true) {await... } loop could be allications-free. Add to this upcoming in C# 8 AsyncStreams and importance of this increases. F# allocates a lot on every boundary and basically cannot be a part of a high preformance async data processing pipeline where GC latency pauses are important. Throughput is also lower. There is a way to hook into the state machine manually, but it's still less efficient, cumbersome and unmaintainable. Been there - done that.
Ofc everythink is IL but working with Options in C# is not fun at all... same with F# async and C#...not belding well into each other- some things I meant when saying that interop is not good imho.
I am with you in thinking, that there should be only one mechanism and that C#s async is superior...
Been learning F# the last two months. Wanted to learn Ocaml first. But F# is the sweet spot, beautiful functional syntax . Can leverage the now open .Net Ecosystem + pretty fast for doing financial stuff that I wanna do.
Lack of support in all targets that require .NET Native, no love from the teams that do .NET graphical tooling, a couple of high figures on the community that love to bash C# and VB.NET and the company that makes it possible that F# exists to start with, is what puts me off to invest more time into F#.
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#.
> a couple of high figures on the community that love to bash C# and VB.NET and the company that makes it possible that F# exists to start with
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.
211 comments
[ 2.7 ms ] story [ 239 ms ] threadAlso, 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.
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.
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.
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.
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.
I 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.
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.
[1] https://github.com/mirage
[2] https://github.com/ocsigen
[3] https://opam.ocaml.org/packages/index-popularity.html
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.
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.
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#.
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
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:
And Python will automatically understand it correctly!A more complex example uses Ruby-style "end" and conditionals:
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.
- 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
https://github.com/ionide/ionide-vscode-fsharp/issues/973
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] http://www.scala-native.org/
[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.
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.
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.
https://github.com/confluentinc/confluent-kafka-dotnet
[1] https://news.ycombinator.com/item?id=17936732
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".
P.S.
Can someone explain this?
Employee 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
Now, a Tree Int would beDiscriminated 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.
[0]: http://foundation.fsharp.org/membership
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).
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
[1] http://tomasp.net/blog/csharp-fsharp-async-intro.aspx/
[2] http://tomasp.net/blog/csharp-async-gotchas.aspx/
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.
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...
http://joeduffyblog.com/2015/11/19/asynchronous-everything/
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.
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.