Hacker News new | ask | show | jobs
by stinos 3247 days ago
Ask HN: I've toyed around with F# and I kinda like it but I've never dug deep enough into it to answer the question: can I use this for 'real life' code as part of an existing C# desktop application for instance, e.g. build some F# into an assembly which is callable from C#? Without tons of hassle? What are good samples of real life application code in F#?
8 comments

> can I use this for 'real life' code as part of an existing C# desktop application .. without tons of hassle

Yes. Your standard OOP features like inheriting from C# classes, implementing interfaces, etc are supported natively in F#. The main hassle in being C#-compatible is exposing an external OOP api with only .NET types and interfaces instead of standard F# types. This means, for example, exposing `seq` (`IEnumerable`) instead of `list` (`Microsoft.FSharp.Collections.List`) or using the struct-tuple construct in F# 4.1 so C# 7 can access it.

> good samples of real life application code

No personal recommendations but have you seen https://github.com/fsprojects/awesome-fsharp

> Without tons of hassle?

Well, yes and no. You definitely can do this, and for some applications it's worth it, but often the overhead at the API level will make you cringe.

APIs designed for C# are very different than APIs designed for F#, to account for partial application of functions, sum-types, non-nullability, immutability and value-like behavior by default from F# types, and also to make good use of F#'s type inference. Also, given stuff like the |> operator, making "fluent" APIs looks very different.

Using APIs made explictly for F# from the side of C# is somewhere between enormously annoying and de-facto impossible. The other way 'round, it's just massively annoying, as you lose many advantages of F#, and the code will not be much more compact as if you would write it from C#.

Pain-points in practice are around F# functions vs. C# methods and delegates, async/await vs. async-expressions, code quotations vs. Linq expressions, etc.

To be productive in F#, you want your API small and primitive, and stay within the language for the rest. If this is possible, go for it; if not, evaluate.

A final tip: Porting a big block from C# to F# is much less work than it sounds, and opens the door to refactoring that part into something sensible.

Are there any F# APIs? I tried to introduce F# to a project but between all needed APIs written in C#/OOP style and only mild interest from a lot of developers and managers I couldn't really justify the added friction.

If there were a ton of F# libraries that showed how to create functional APIs people could learn from them by using them the same way a lot people learn OOP by using APIs.

As it is now the only way to get into F# is to have a group who really wants to do it and learn. Otherwise it's just an uphill battle.

Absolutely Here's some nice slices

Starting with front-end since it's a bit easier to jump into

Back-End C#, front-end SPA in F#

Check out Fable-Elmish (and Fable-Elmish with React (Elm-style model-update-view for React)) https://github.com/fable-elmish/elmish

WPF Desktop -> Elmish.WPF (Elm-style model-update-view for WPF) Check-out https://github.com/Prolucid/Elmish.WPF

Back-End Slices for lambda-architecture-style systems

Web,Front-end in whatever, streaming with Storm and F# via FsShelter (and FsCassy for Cassandra, FsBunny for RabbitMQ)

Streaming, front-end in whatever, Web Layer with Freya

Also: Some tips Install VS Code with all the ionide plugins. Also grab Forge to create new fsharp projects if you're not doing net core development. Use Expecto for tests. Then from the editor you can build,run, debug, paket install, and run test(s)

yes you can. C# / F# interop is not zero hassle but it is low hassle. Most of the time it just works. There are a few features in each language that are not zero hassle, if a C# api uses a custom implicit conversion, calling it from F# requires you to explicitly call the implicit conversion (ha!) and if an F# api returns something F# specific like an Option type, using it in c# can be a pain.

At my company we have a C# codebase for a large web application, but we create a 2 stage caching feature for it in F#. This F# project uses a couple of C# oriented libraries (stackexchange.redis and protobuf-net). So lots of interop going both ways.

Some examples of people using it in production: http://fsharp.org/testimonials/

I'm not gonna say thanks to each post individually, so: thanks for all replies! Really informative.
It depends, if you want to use it side-by-side with C# in a .NET Core project I'd say "forget it", you will just come away with scars from the process. If you're doing a greenfield F# only project, yeah sure, it all works lovely and is a great language.
I can't share the code with you, but I did just that on a proprietary app for my company. Only the GUI shell of the app is in C#, and that only because the GUI builder features of Visual Studio can only generate C# code.

All of the "real" code in that app is in an F# library, which you add to the Visual Studio solution just like you would any other C# helper library. When you add a source file to that library, it's an F# source file, and it's built with the F# compiler into the library, which is then linked with the C# "main" program.

There are a few tricky parts, owing to the substantial differences between C# and F#. They all come down to the fact that there are aspects of both C# and F# that don't map naturally to the other. While there may be low-level .NET or IL ways to force the call, it's better to restrict your use of each language at the boundary between the two parts of the program.

Some examples:

1. F# has two ways of passing parameters to a function called the tuple and curry forms. Curried functions are the full-power form, but C# can't call them directly, so any function or method you want to export to the C# side must use the tuple form. At a superficial level, the only difference is some parentheses and commas, but at a low level, you're purposely nerfing the F# function to allow C# to call it. This is not an area you can avoid knowing about, since all of .NET uses tupled calling form, being written for C# initially.

2. F# has several native data types that have no direct implementation in C#. Some newer versions of C# have .NET extensions to allow them to manipulate values of these types given to the C# side from the F# side, but given a choice, it's often simpler to restrict the set of data types you define the interface between the two in terms of. That is, you generally don't want to allow discriminated unions, records, tuples, or function values through the boundary, if you can help it. Use data types C# copes with better: classes, structures, lists, and arrays instead.

3. C# code often makes use of null values, which are...well, "sinful" in F#. It is possible to use null in F#, but strongly recommended against, since F# is all about definite value states, and null adds an element of indefinite-ness to the application. You can choose either to allow null values through the C# to F# boundary or enforce the F# side's wish not to accept them at the boundary. Your choice.

4. Once you get into the F# way of doing things, you start to become more choosy about the C# libraries you use from F#, since some are more acceptable from an F# standpoint than others. You start to avoid libraries that have mutable values flying around everywhere, methods with side effects, etc. Some C# libraries are outright annoying to use, because you have to continually cast away so much of the F# value in order to use them. Fortunately, .NET itself is generally pretty good in this regard. The NuGet world shows less restraint here.

Were your fellow developers interested in F#? I have found most people simply don't care and don't want to learn it.

And there is the famous line "Functional programming? We did functions 30 years ago. No big deal".

> Were your fellow developers interested in F#?

I was sole developer on that project.

But here's a thought for you: you can only achieve mediocrity if all choices require 100% buy-in from all interested parties.

> I have found most people simply don't care and don't want to learn it.

No one likes to have their cheese moved. But cheese moves nevertheless.

> We did functions 30 years ago.

Most people saying that probably don't realize that what computer programmers call "functions" are not what mathematicians call "functions."

The reason FP is becoming popular now is that the distinction now matters much more than ever in today's multicore world, where multiprocessing is often the only practical way to make software substantially faster.

'But here's a thought for you: you can only achieve mediocrity if all choices require 100% buy-in from all interested parties."

Exactly! Unfortunately this is the reality in a lot of corporations. Pretty sad.

Beware that you won't be able to deploy the code to UWP though.
There is a way to develop for UWP with F# - MS' own React Native support + Fable. Write your app in F# using Fable React Native bindings, transpile to JS and deploy to UWP.