Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
On moving code from C# to F# (felienne.com)
93 points by blah_blah on March 19, 2016 | hide | past | favorite | 59 comments


I LOVE F#. I wish I could use it more often. I haven't used it since I worked at Jane Street three years ago, and Jet.com is the only other place that's using it seriously at the moment.

It is such an expressive and clear language to write code in. That is until you start needing to use imperative .NET types :)


I thought Jane Street used OCaml! (I know the two are similar.) Why did they need to target the CLR?


Just a guess: even if your back-end is all OCaml, traders still want to get data into Excel to play with it.


Yes, Jane Street uses OCaml for their trading systems but we also use(d?) F# for some (very important) odds and ends.


F# is our primary language at Tachyus.


We use both C# and F# in our application, using C# for UI (WPF) and F# for data processing with a lot of calls from C# to F# and vice verse. Using F# was crucial, because it allowed writing heavy processing and complex algorithms (e.g. parallel hash aggregation) in a very clean and concise way with higher-level abstractions which saved us a lot of time. Things like not having to deal with null reference exceptions were also a big time-saver. Without F# it would have taken us one more year to release a production-ready application, or even made it impossible at all given the time & budget constrains that we had. If I ever start another project of that scale I will do it using only F#.


I've been using F# for a while and it's been excellent. It's just so less frustrating than writing C# in all its verbosity. There's really no reason to not use F# other than legacy or poor management. (Some folks just don't "get it". Perhaps the same kind of people that use a 20 char variable name when 3 would do. Or that are cautious about using local type inference. I don't know. But too many people conflate verbosity with readability and get scared.)

I tried porting a small demo program, a few hundred lines, directly from C# to F#. It required only 1/20th of the type annotations. I've written web APIs in F# and many took about half the lines of code.

I particularly like the ease in which I can define local functions to reduce redundancy. In, say, C#, there's so much overhead involved that it's just not worth it.

Going back to F# I've written years ago hasn't been hard either. Since the code is so compact, it's not difficult to figure things out.

F# should be MS's flagship. While F# isn't perfect (could use more inference, traits or typeclasses, and macros), in terms of tooling, ecosystem, language features it come out near the top.


> in terms of tooling, ecosystem

Does F# run on .NET Core yet? Last I checked .NET Core and ASP.NET Core didn't support F#, which is a really big demerit for new projects considering this is the platform Microsoft is pushing for future server side applications (as they should be).


yes, using .NET CLI ( http://dotnet.github.io/getting-started/ )

You can check https://github.com/enricosada/fsharp-dotnet-cli-samples/wiki... .

Remember to use last know good version of .NET CLI (see https://github.com/enricosada/fsharp-dotnet-cli-samples/wiki... ), until latest version is fixed


> use a 20 char variable name when 3 would do.

I generally think functional programming is a smart idea, but knock it off with the short, generic function names. We're not writing Fortran on an 80-char terminal any more. Name shit what it is, it's going to auto-complete anyway after you type 3-4 characters, so you might as well give it a name that you won't have to puzzle about later.


I'm talking more like locals. Consider:

  var newCustomers = getNewCustomers()
  foreach(var newCustomer in newCustomers) {
     newCustomer.this .that etc.
  }
Depending on the length of the surrounding function, you're better off using "xs" and "x". Or "cs" and "c". I think people trick themselves into thinking that long names somehow provide more context. At a high level, this is correct: modules, exported functions, etc. But for programming "in the small" it's just needless noise.

It's not just the hassle of typing long names out; a good editor can help there. It's the visual overhead of having so many extra pixels lit as you read things.

Short functions are good for local functions:

  var sb = new StringBuilder()
  sb.AppendLine bla
  ...
  sb.AppendLine foo // And another 5 places in the following 10 lines of code.
It's nicer to instead have: let al = sb.AppendLine al bla ...

This is especially true then the local code pattern is 2, 3, or more lines or when it contains branches.


I perfer the verbosity because it helps with eliminating ambiguity when the code changes hands or goes into "maintenance". This is especially true in weakly, or duck, typed languages.

Both have merits though.


> having so many extra pixels lit as you read things

Your brain is excellent at turning words, even long ones, into instantly recognizable shapes. That's why transposing lteters as I'm doign in this sentnce doesn't harm readability very much.

Good, easily-maintained code is not poetry, and it's not math. It's Hemingway: short, terse sentences that say only what they need to say and nothing more. They are self-contained and self-evident.

On a semi-related note, there's a study showing that non-programmers have a much easier time reading code with more white space. To adapt your example above:

  var newCustomers = getNewCustomers()
  
  foreach(var newCustomer in newCustomers)
  {
     newCustomer.this .that etc.
  }
It's much easier for your brain to pull out different symbols when there's more white space.


> short, generic function names

fit the length of the functions. Long names might be indicative of some deeper problem with coding style.


I think the reason functional programmers like short, terse names is because they need to see the structure of the code more than the individual identifiers. More verbosity makes it hard to get a picture of whats going on locally. Pattern Matching and Recursion creates structures that are easier to understand if it fits on the screen.


There's a happy middle ground there. At the call site is where it matters a lot more. If you have a function that's basically nothing but a pattern matching expression, the name of a parameter matters a lot less than the name of the input when you call that function. Same goes for what you name the result.

If you do this:

    let r = f x
Then you might be a fucker. But most good F# code I've seen is more reasonable:

    let res = getResult input 
Granted there's some exception, such as defining your own operators. F# does this itself, where "|>" is "let (|>) f g = g f". I don't think you gain much from adding verbosity to that.


In general, short names tend to be used for the most generic variables. Renaming "g" to "theFunction" in the (|>) one-liner doesn't really clear up anything. Just seeing it applied to something makes it clear enough that it's a function, etc. For something less generic the identifier can introduce the relevance of the variable better. But the thing about functional programming is that much of the code is written to be very generic, and so there's not much room to use longer names.

Also, another thing that I've noticed is that it becomes much easier to deal with short variable names in functional programming, because you know the value of the variable isn't about to change out of the blue. By restricting mutable state and side effects, it's possible to just substitute the values for variables wherever they exist. So for example,

    let r = getResult input
    let s = "abc" + r
    let t = doSomethingWith s
    printfn "%d" t
is known ahead of time to be exactly identical to

  "abc" + getResult input |> doSomethingWith |> printfn "%d"
Once you start introducing mutable state, something like that becomes a whole lot harder to read because you can never be sure if the values of those variables are changing, so you can't substitute in the declaration site.


Well, if you need to scroll to read the whole name, that's indicative of some deeper problems, alright. That's kind of what I was getting at, just that the code also needs to fit in my head. Use of verbose identifiers might be linked to verbose code and that might or might not be harder to follow. There is a sweet spot.

I am just defending that I don't know what car means mainly because I don't know LISP and I refuse to read documentation, but out of lazyness mind you.

On a related note, I often discover that trying to shorten text, sentences become a lot clearer when they are less verbose. Compare that to: On a related note, I often notice shorter sentences are clearer. Compare that to the overly terse Short Sentence Clarity!


In many ways code is similar to math, and in math they mostly use one-letter identifiers. And there is a very good reason for that. I have seen texts where authors tried to make formulas more reader-friendly by replacing letters with words, but in that case they might as well have replaced formulas with prose...


Code has similarities to math, but it's not math.

function a(b) ... requires reading the whole function definition to understand what it does.

function createNewUser(userInfo) ... tells you exactly what it is and what it does. Especially if you're dealing with pure functions, it makes reading and understanding a code base much faster (and decreases the need for documentation).


Math notation isn't as much concerned with implementation as it is the architecture.


The (potential) terseness of F# seems like a bit of a superficial benefit compared to other features of the language, such as discriminated unions and pattern matching, excellent support for immutable records, structural equality by default, computation expressions, etc.

I'm a C# developer with almost a decade of experience, and am pretty enamored with F# as well, but like almost everyone else, am stuck using it solely in my own personal time.

However, I'm not certain how much benefit most teams would gain from using F#, after seeing the average (poor) level to which most developers are able to leverage the C# type system to improve the design of their software. Too many developers are forever stuck in a purely imperative paradigm, only knowing how to type one line of code after another, relying exclusively in enums for "extensibility," etc. It seems a bit hopeful to convince the community at large to switch to a language with an improved type system in hope that it will be used to create better software.


I recall reading that bugs are many times related to the size of the code, across languages. This SO answer has some citations: http://programmers.stackexchange.com/a/185684

But I think somewhere I read that the number of bugs goes up once a function stops fitting on one screen. Or maybe that was Arthur Whitney - J and K seem to do that nicely, and even his C style does so.

Edit: Of course all those other benefits of F# are huge, indeed. But don't underestimate the advantages and pure joy that excellent "programming in the small" provides.

As far as teams being stuck, you're basically saying that mediocre programmers can't handle good things. That's fine, but then the problem is hiring mediocre programmers. I suppose for a lot of basic CRUD/LOB or "enterprisey" stuff, it's important you can take essentially a typist and have them add business rules (like in Wisconsin, if the user is over 50, remove a certain discount). I don't find this type of programming to be particularly interesting though, so who cares what they use?


"I suppose for a lot of basic CRUD/LOB or "enterprisey" stuff, it's important you can take essentially a typist and have them add business rules (like in Wisconsin, if the user is over 50, remove a certain discount)."

Is there really much of that stuff going on? I would have thought they would provide some kind of rules engine to the business rather than hard coding masses of it.


Yes it's going on, and half of it is hacked together in Excel.


I still think it'd be great if the .NET world were to switch over, if only for the sake of us few F# aficionados. :-)


Is it possible to call F# code easily from C#? Or vice versa?


Consuming C# code from F# works fine.

Consuming F# code from C# works pretty well for the most part, although F# specific types are cumbersome to use (records, discriminated unions, computational expressions aka monads). This just means that if you want an F# DLL to be usable from C#, you need to think a little bit about the exposed API (perhaps by adding a C# specific wrapper).

Having said that, IMO the interop between the two is better than the interop between JVM languages like java, scala & clojure (Kotlin is probably different).


Yes, I agree, but you need to be really careful about tail call recursion optimisation when calling f# code from c#. In F# it is always guaranteed, in c# only on 64 bit 4 and above runtime if I remember correctly, so you can't really rely on it for production code.


Unless it's changed, F# doesn't emit "tail." prefixes for tailcall. Nor is it guaranteed. The F# compiler will, in some cases, manually turn your tailcall-OK code into a loop. But it doesn't do it in all cases (nor could it).

The F# compiler used to emit "tail." prefixes in every case that was eligible. But not only does the CLR have lots of restrictions, it was slower to request tailcalls.

Maybe that changed in the last version or two.

Edit: OK I found the email where I had asked fsbugs why tailcalls were no longer generated. But that was in 2009 so I'm more out of date than I remember.

In the release notes[1] for the May 2009 release, there's this section:

Optimizations for Tailcalls

On some implementations of the CLI, normal calls can be more efficient than tailcalls. An optimization is now applied to determine if a function is “closed” in the sense that it never takes any tailcalls outside a finite non-recursive callgraph. If so, the use of tailcalls is suppressed.

1: http://blogs.msdn.com/dsyme/archive/2009/05/20/detailed-rele...


Wouldn't C# interface only with compiled il code and not directly with F# so any tail call optimizations in F# wouldn't depend on what you later do in C# compiler?


Yeah, right, the f# compiled code will be already optimised for the tail call recursion so it can be called safely from the c# code. What I remembered applies only to the c# generated IL.


Have they fixed the intellisense yet? Last time I tried to call c# from f# it compiled but autocompletion in vs didn't work.


Yeah, the intellisense is a lot better than it was in earlier versions.

That said, it doesn't attempt to read your mind, so the intellisense only kicks in when the type you're interacting with is unambiguous. So, for example, you'll need to explicitly state a function parameter's type before intellisense will help you figure out what methods you can call on it.


In general you should follow Demeter's law and not expose types behind value types if you can avoid it.


Regarding this 'law', Wikipedia put it quite nicely, saying quote, it is more suited as a metric for code smell as opposed to a methodology for building loosely coupled systems.


Yes, I have a WebAPI module written in C# that calls into an F# module for some file processing. From the C# project's perspective, the F# assembly is just another assembly with static methods. It was a great use case for me to highlight the benefits of mixed paradigm programming. By making the WebAPI module state based, it made certain operations easier, while the F# module can do the heavy lifting of processing the data.

You can also do a pure WebAPI module in F#.


That's a confusing post. You talk about WebAPI which is all JSON/AJAX, of course you can cross communicate there, the above poster is talking about direct inter-CLR calls (which you can do but have nothing to do with WebAPI).


I'm guessing the poster means an ASP.NET WebAPI controller that relies on an assembly written in F#, not a process making web API calls.


Why does it being WebAPI-exposed interface matter at all then? It is an extremely confusing way of phasing it. It literally doesn't matter, and even reading back if that IS what they meant then it is still a really circular way of wording it.


Most likely they're referring to the C# part being written for Microsoft's "ASP.Net Web API" framework, rather than just being a web API in general.

That framework is designed for C# programmers and most of the resources (tutorials/stackoverflow answers/etc) around it will assume you are writing C#. So it makes some sense to use C# for that part of your application even if most of the underlying business logic is implemented in separate F# libraries.

That's probably why they specified it - to explain why they're using both C# and F#. I can see how it could be confusing, especially if you're not familiar with that rather generically named framework.


It doesn't. That was just an incidental piece of detail.

If it makes it more comfortable to you, replace "WebAPI" with any other technology that interfaces your code with the outside world. Maybe a UI toolkit or something.


> From the C# project's perspective, the F# assembly is just another assembly with static methods.

It sounds like he's calling the F# functions directly.


Yes, the C# WebAPI project receives a file, and then passes it off to an F# module for processing. The WebAPI takes care of authorization, authentication, and some basic checks against the file, whereas the F# library is responsible for data processing.


Yes, very easily. Both are compiled to .NET assemblies and can see types of each other.


please dont override default scrolling behaviour, the site is unusable


Yep, agreed. I can only scroll by using the scrollbar.


Can somebody please build a scrollblocker for Chrome and Firefox?


Apparently I'm using one. It's called NoScript. ;-)


Not sure what issues you are seeing but I'm able to scroll completely normally.


There's a "smoothscroll.js" loaded by the page. Looks like it only targets Chrome users.

http://www.felienne.com/wp-content/themes/zerif-lite/js/smoo...


For someone uninformed, what did they change? I'm able to scroll using the keyboard keys, scroll bar, and arrow keys on my keyboard. Is mobile scrolling what's broken?


I'm using Chrome on Mac OS and I can't scroll left and right in any of the code examples. This is particularly bad because the OS hides scroll bars by default under the assumption that you'll be able to scroll left and right with the trackpad.

Also, it's hard to describe exactly what the problem is, but scrolling up and down definitely feels weird and frustrating. For example, a light push that normally goes down a few lines of text on any other page seems to go down a full page. It also seems "stickier", like any scrolling takes a split second to "kick in". As a more contrived example, if I hold two fingers down on the trackpad and scroll up and down in place, any other page will scroll up and down following my fingers, but this page seems to jump around in an inconsistent way.

Something on the page is trying to intercept scroll events and do something smart, but at least on a trackpad on Mac OS in Chrome it makes scrolling feel much worse and less predictable. It looks like Chrome, Firefox, and Safari all behave differently here, with Chrome behaving the worst.


They added a TON of "inertia." Flick the trackpad a tiny little bit and it keeps moving long after I take my fingers off, giving an entirely different screenful.

Your users know better than you how fast they intend to scroll. Always.


also seems to work fine on my end. scroll wheel, middle mouse button work too. seems normal.


Also the text on the code samples is so large the typical code is twice as wide as the box it's written in. Painful.


Easy, only up 3 tones.


It's a perfect fourth, which is 5 semitones. In other words, it's 2.5 tones. If you're going to make a pun, at least make it correct.


I think that this code can be much simpler, it is really difficult for me to follow it up. I'm not at all an F# expert, I just studied it a bit for fun last year, but I remember that all the code that I looked at was much more readable..




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: