[HN Gopher] The combined power of F# and C#
       ___________________________________________________________________
        
       The combined power of F# and C#
        
       Author : freedude
       Score  : 133 points
       Date   : 2023-08-07 18:19 UTC (4 hours ago)
        
 (HTM) web link (steven-giesel.com)
 (TXT) w3m dump (steven-giesel.com)
        
       | guhidalg wrote:
       | I developed a very non-trivial ASP.NET Core application mixing F#
       | and C#. I learned you have to take the best parts of both
       | languages to get maximum benefits. Specifically you're going to
       | want a project graph that looks like this:
       | 
       | 1. Your top-level project should be a csproj where all your "web"
       | stuff is. Controller routes, DTOs, startup code, etc... This
       | project is responsible for converting data into nice objects that
       | are passed to the F# code.
       | 
       | 2. A mid-tier project written in F#, an fsproj. This is where you
       | can be nice, pure, functional, live out your best life pretending
       | C# doesn't exist. However you will eventually run into issues
       | interfacing with external libraries, EF Core, lack of standard
       | library support for whatever you're doing. That's ok! The final
       | layer will solve it.
       | 
       | 3. A foundational project written in C#. This project's job is to
       | hide the ugly and make your F# project into the functional
       | programming nirvana you know it can be. Wrap those dependencies
       | into pure functions, write your entity framework junk, use all
       | the latest C# language and runtime features and expose them to
       | your F# project.
       | 
       | So something like:
       | 
       | C# -> F# -> C#
       | 
       | Ultimately, I decided that C# really is good enough and I didn't
       | see enough benefits to continue using F#.
        
         | ComputerGuru wrote:
         | > Ultimately, I decided that C# really is good enough and I
         | didn't see enough benefits to continue using F#.
         | 
         | I've heard this story repeated so many times over the years.
         | The responsiveness of the C# language team in particular (as
         | opposed to the runtime or ASP teams, etc) is remarkable and the
         | thoughtful inclusion of functional-inspired features over the
         | years has really dramatically improved QOL for C# devs. (With
         | the exception of some annoying carve outs like going too far
         | with trying to please JS/node refugees with not only
         | introducing support for top-level statements but also pushing
         | it as the default in the various templates, the botched
         | delivery of global includes, and other such changes --- but to
         | be fair, many of these were implemented correctly and without
         | any complaints on my end in the language itself but my quibbles
         | are more with the delivery, integration, and polish in the IDE
         | and downstream by teams like the ASP.NET Core one.)
         | 
         | After a long pause during the denouement days of the .NET
         | Framework, the C# of today would be unrecognizable to C# devs
         | of yesteryear, and the changes keep coming.
         | 
         | (All this is from the POV of a developer that's been using C#
         | since 2002; back when J# was a thing and I was slowly adapting
         | to writing code in a case-sensitive manner after years of VB.)
        
           | [deleted]
        
         | daxfohl wrote:
         | Funny, I did exactly the opposite! I really enjoyed f#'s
         | functional-style web framework Suave, but put it on top of
         | services written in OO style, which all used immutable f#
         | records and lists under the hood. It ended up being a lot
         | easier to do all this in f# than mix the two languages, since
         | f# is dual purpose. I called it sandwich-oriented programming.
        
           | wizofaus wrote:
           | Surely C# qualifies more as "multi-purpose" than F# does?
           | It's certainly more of a multi-paradigm language - my own C#
           | code freely mixes functional, imperative and OO- style
           | (multiple implementations of the same interface etc.)
           | techniques, the latter two of which I struggle to envision
           | being improved by rewriting in F#.
        
           | guhidalg wrote:
           | Using a framework like Suave probably reduces the "impedance
           | mismatch" between ASP.NET and F#. If I had used that, I
           | probably wouldn't have needed to split the code base into C#
           | and F# parts.
        
             | evntdrvn wrote:
             | I've tried to use "ASP.NET Core with F# underneath" for
             | several projects, thinking it would make for an easier
             | bridge for the rest of the team members who were very
             | comfortable with asp.net already.
             | 
             | And each time, it turned out to be a mistake.
             | 
             | Things went way more smoothly by just using an F#-native
             | web framework like Falco or Suave or Giraffe or ...
        
         | pjmlp wrote:
         | Yes, that is the ultimate problem with F#, Microsoft behaves as
         | if it was a kind of mistake to add it to the Visual Studio
         | 2010, the experience always lags behind C# and VB, leaves to
         | the community to do most of the work, and now with stuff like
         | code generators being used everywhere is getting worse.
        
           | soulbadguy wrote:
           | +1
        
         | phillipcarter wrote:
         | This is an excellent distillation of how you can effectively
         | mix F# and C# in the same codebase.
        
         | Rapzid wrote:
         | F# deserves a project like Phoenix that the entire community
         | can get behind. World-class docs, zero getting started
         | friction(docs, examples, and libraries all just work), and
         | bomber F# APIs over any ubiquitous C# libs it might need.
         | 
         | It's just too piecemeal right now.
        
       | bob1029 wrote:
       | I know it's a really trivial matter, but I actually got to use
       | the tuple swap thing the other day and it felt _so_ good.
       | (ItemA, ItemB) = (ItemB, ItemA)
       | 
       | ~50% of our methods don't even have block bodies anymore...
       | Switch expressions are our bread & butter now. Once you learn how
       | to combine expressions + switch + LINQ, you have the triforce of
       | poor-man's functional programming inside the perfect imperative
       | realm by which to protect it.
        
       | raydiatian wrote:
       | Say it with me everybody
       | 
       | "Trade offs"
        
       | michaelteter wrote:
       | Functional core, imperative shell. This seems to be a good
       | approach, especially when you push pretty hard to stuff as much
       | as possible into the functional core.
       | 
       | Writing tests is much easier and requires much less code, and
       | bugs are much easier to track down (since you have less surface
       | area of "what might have modified this object I now hold?").
       | 
       | Since a functional approach also goes well with single-
       | responsibility-principle and composability, you can end up with
       | multiple times more actual functions. They're all (ideally) very
       | conceptually simple, but the larger number of more specialized
       | functions means you have to work a lot harder on choosing
       | meaningful names. And to write meaningful names of specific
       | functions, you can end up with some quite long names. This is
       | actually quite ok as it makes things much more readable, but some
       | people have some strong negative reactions to seeing 4-6 word
       | function names. But at least in this case (Java being the most
       | famous counter scenario) each function probably has more real
       | value as it's not just OO layer artefacts.
        
         | seanwilson wrote:
         | Can anyone explain why not "functional core, functional shell"?
         | Is this partly because the shell has to mostly interact with
         | things like UI APIs, file system APIs, network APIs and
         | database APIs that are usually implemented in an imperative way
         | already so you'd make your life harder this way? What if the
         | APIs were written in a functional style?
         | 
         | For example, I find in TypeScript, most libraries and the
         | language itself are not written with immutability in mind so
         | there's constant gotchas. So while I strongly prefer immutable
         | data structures, going against the grain to use immutability
         | everywhere usually isn't worth the frustration. That for me
         | doesn't mean immutability is a bad idea though, it's more that
         | the libraries and languages support is lacking.
        
           | xupybd wrote:
           | The shell is where you put all your side effects. Things like
           | user input or writing to files.
           | 
           | That way you can use pure functions on the inside. Pure
           | functions don't allow for side effects.
        
             | seanwilson wrote:
             | Why does "imperative" imply "side effects" here though?
             | Pure functional languages have ways of modelling side
             | effects.
        
               | xupybd wrote:
               | They do but it's a bit of a square peg round hole. It's
               | just easier not to use things like the IO monad.
        
               | WorldMaker wrote:
               | It's also fun to note that the IO monad in some
               | perspectives is an abstraction _for_ "functional core,
               | imperative shell" moving as much of the imperative "order
               | matters" computations to an outer "shell". The IO monad
               | in some ways _is_ the way of mathematically representing
               | the  "shell" of an application.
        
             | turboponyy wrote:
             | Pure functions can't perform side effects, but they can
             | describe them.
             | 
             | For a functional shell, your program's entry point would be
             | composed of pure functions describing effectful actions to
             | take. The necessary computations get bubbled up to the
             | entry point during evaluation, at which point the runtime /
             | compiled program executes them.
             | 
             | (At least, this is the abstracted perspective you should
             | view the purely functional source code from. The final
             | program itself in practice is, of course, effectful
             | throughout).
        
           | lmm wrote:
           | > Can anyone explain why not "functional core, functional
           | shell"? Is this partly because the shell has to mostly
           | interact with things like UI APIs, file system APIs, network
           | APIs and database APIs that are usually implemented in an
           | imperative way already so you'd make your life harder this
           | way? What if the APIs were written in a functional style?
           | 
           | Fundamentally the user isn't functional - if you ask them
           | what they want to do they'll say different things at
           | different times. You can have a 100% purely functional
           | programming language that works like a calculator (with no
           | memory) - the user can put in expressions and the language
           | will evaluate them - but generally users want their language
           | to be able to _do_ things that are non-idempotent and non-
           | time-symmetric and so on. You can, and should, push that part
           | to the edge, but it needs to be there somewhere.
        
         | kmac_ wrote:
         | This approach works very well. Side effects are pushed out of
         | core and no mocks are required for end to end tests. It's quite
         | hard to "sell" to fellow devs, but when it clicks, the code is
         | very clean.
        
         | gugagore wrote:
         | One thing that I have seen in the Julia ecosystem, where
         | multiple dispatch is pervasive, is that function names can get
         | away with only being verbs. Without dispatch, you often see an
         | approximation by baking in (Hungarian notation) the name of a
         | type into the function.
         | 
         | This is most clearly seen with conversation functions between
         | types defined in different libraries. A collection class might
         | have a method like "from_Array".
        
         | bob1029 wrote:
         | > Functional core, imperative shell.
         | 
         | You can find this pattern in a lot of places if you are a
         | little bit flexible with your definition of "functional".
         | 
         | For example, why would we not consider some combination like
         | SQL and PHP to be hinting at this exact same kind of archetype?
         | You've got a crusty outer shell of yucky hackarounds (PHP) that
         | talks to this (ideally) well-normalized & clean data store
         | (SQL). Assuming you "stuff as much as possible" into core part
         | of the solution, you could swap the outer shell for anything
         | you desire without much headache.
        
           | skrebbel wrote:
           | PHP is more like "imperative core, functional shell". After
           | all, a PHP request is a pure stateless function call. The
           | only way it can modify state anywhere is with IO (eg store
           | something in the database, write something to the session
           | store, etc) and all data you accumulate in your PHP code gets
           | purged after each request.
        
             | closeparen wrote:
             | And SQL is all about mutation... functional take on the
             | database would be something like Datomic.
        
       | leblancfg wrote:
       | Someone at Microsoft better get a trademark on "Powerchord".
        
       | Const-me wrote:
       | The C# version is slightly better, though.
       | 
       | Binary floating-point numbers are less than ideal for keeping
       | discount percentage because a value like 12.3% can't be
       | represented exactly.
        
         | wizofaus wrote:
         | Not sure why it's not "Percentage of decimal" though?
        
           | Const-me wrote:
           | Absolutely, it better be a decimal. These numbers in .NET are
           | decimal floating-points, they can represent all these 12.34%
           | without any loss of precision.
        
       | munchler wrote:
       | I love seeing F# mentioned on Hacker News, but this article in
       | particular is a bit dubious. Yes, you can use F# from C#, but it
       | gets frustrating quickly.
       | 
       | Fortunately, almost anything you can do in C# can be done better
       | in F# anyway, so there's really very little need to use C# at all
       | once you take the plunge into functional programming.
        
         | gsuuon wrote:
         | I agree - I guess this article is more about a (very) gradual
         | way to adopt F# into an existing C# code base, rather than an
         | inherently useful combination of C# and F#.
        
           | munchler wrote:
           | True, but for any serious integration the F# library should
           | expose an API that's designed to be more idiomatic for C#
           | callers. When I see `ListModule.OfSeq` being called from C#,
           | I cringe a little.
        
       | ctenb wrote:
       | You could make the C# code shorter by using the one-liner record
       | syntax. That would compare the SLOC more fairly.
        
       | einpoklum wrote:
       | > Where C# is the most dominant language in the .NET world
       | 
       | Why would we want to live in the ".NET world"? I say adopt a
       | programming language, or languages-ecosystem, that's not useful
       | only in the "[some niche] world", but more-or-less everywhere.
       | Whether it's older and well-trodden or newer and up-and-coming, I
       | don't see the benefit of limiting yourself that way.
        
         | WorldMaker wrote:
         | It is not really a "niche". The ".NET world" _is_ more-or-less
         | everywhere: it is cross-platform, open source, and runs on
         | Linux /Windows/macOS/iOS/Android/more.
         | 
         | The ".NET world" is comparable to the "JVM world" or even the
         | "LLVM world": a virtual machine target with a varied language
         | ecosystem and a lot of real machines supported at runtime (in a
         | cross-platform, open source way today).
         | 
         | ".NET world" is defining a complex language ecosystem, and it
         | probably isn't as "limited" an ecosystem as you seem to think.
        
       | jimmaswell wrote:
       | The F# is certainly nice, but the C# is odd. This is a textbook
       | example of either inheritance or interfaces. I did inheritance
       | here but it would be trivial to change it to an interface.
       | 
       | https://dotnetfiddle.net/F5fPZy
       | 
       | The class implementations add a bit of upfront verbosity but the
       | calculation at the end is arguably nicer to read: that method is
       | concerned with applying the discounts, but in the F# case it has
       | to know how to apply each type of discount, while the C#
       | encapsulates that in the Discount implementation.
       | decimal subtotal = OrderLines.Sum(ol => ol.Product.Price \*
       | ol.Quantity);       return Discount?.Apply(subtotal) ?? subtotal;
       | 
       | vs                 let subtotal = List.sumBy (fun ol ->
       | ol.Product.Price \* (decimal ol.Quantity)) orderLines       let
       | totalDiscount =        discount        |> Option.map (fun d ->
       | match d with         | Percentage p -> subtotal \* (decimal p /
       | 100M)         | FixedAmount f -> f)        |> Option.defaultValue
       | 0M       subtotal - totalDiscount
       | 
       | Though I'm also pretty sure F# could do the same thing with the
       | classes if you wanted. And someone else pointed out you can write
       | some C# that looks the same as the F# if you use a switch
       | statement. And I'm pretty sure you could make it look even more
       | F# if you used more Linq.
       | 
       | I guess the F# matching is pretty much like interface/class
       | checking as follows? I don't see the functional difference:
       | if (discount is IPercetage percentage) { .. subtotal \*
       | percentage.value / 100 ...         else if (discount is IFixed
       | fixed) { .. subtotal - fixed.value ...
       | 
       | And you could do even more with some newer C# features like
       | anonymous classes etc.
       | 
       | I'm not left feeling like I'm missing out on anything without
       | discriminated unions in particular. I'd be interested to see some
       | cases where the functional nature of F# does make a large
       | improvement over the equivalent C# though.
        
         | jackmott wrote:
         | [dead]
        
         | gsuuon wrote:
         | You can also hide the logic away in F#:                 let
         | calcDiscount =         function         | Percentage p ->
         | subtotal * (decimal p / 100M)         | FixedAmount f -> f
         | 
         | And then:                 let totalDiscount =         discount
         | |> Option.map calcDiscount         |> Option.defaultValue 0M
         | 
         | F# is missing some of the convenience operators, but you could
         | easily add these yourself if you wanted:                 let
         | (?) x f = Option.map f x       let (|?) x y =
         | Option.defaultValue y x
         | 
         | and so totalDiscount becomes:                 let totalDiscount
         | = discount ? calcDiscount |? subtotal
         | 
         | The benefit of DU's over inheritance for me is that you can't
         | tie yourself to any additional details that get stuck onto
         | Discount (since you can't extend DU's). If you have loosely
         | coupled data you won't have sort-of-relevant methods possibly
         | mutating shared state. The discount calc only takes a simple
         | thing hidden away by the Discount DU, and so there are fewer
         | plates you're trying to keep spinning in your head (all of
         | "what could be").
        
         | Smaug123 wrote:
         | The main difference is the totality checking. A discriminated
         | union guarantees that you've handled the _entire_ modelled
         | domain (and nothing else); repeated interface checking merely
         | guarantees that you 've handled a _subset_ of it (and also you
         | may have handled a bunch of other stuff).
         | 
         | It's so _comforting_ to know up front that you 've done
         | everything you need to do!
        
       | danjc wrote:
       | Brevity and clarity are often conflated. Sometimes they're
       | actually inversely correlated.
        
       | hd4 wrote:
       | While there's a thread on F#, I'd like to complain about how I
       | attempted to create/publish a F# dotnet app in entirely using the
       | terminal (i.e. without the bloat of Visual Studio) and it doesn't
       | seem to be supported, which was unfortunate.
       | dotnet new webapp -lang F# -o MyFSharpWebApp -f net8.0
       | 
       | was the command I used. This was in Windows 10. I'll probably
       | attempt it again in WSL2 when I have time, though I'm not
       | expecting better results.
        
         | phillipcarter wrote:
         | This is, unfortunately, a consequence of the annoying naming
         | Microsoft does (I am allowed to complain about this because I
         | worked on the .NET team -- nobody can name things we can't).
         | 
         | You'll note that in the list of default templates:
         | 
         | ASP.NET Core Empty web [C#],F# Web/Empty
         | 
         | ASP.NET Core gR... grpc [C#] Web/gRPC
         | 
         | ASP.NET Core We... webapi [C#],F# Web/WebAPI
         | 
         | ASP.NET Core We... webapp,razor [C#] Web/MVC/Razor Pages
         | 
         | ASP.NET Core We... mvc [C#],F# Web/MVC
         | 
         | ASP.NET Core wi... angular [C#] Web/MVC/SPA
         | 
         | ASP.NET Core wi... react [C#] Web/MVC/SPA
         | 
         | "webapp" is actually a flavor of MVC with Razor Pages to define
         | the UI, which is itself a flavor of UI that's different from
         | the typical HTML/JS/react setup most people use.
         | 
         | I think the cleanest way to do web development with .NET is to
         | leave .NET-isms out of the UI (.NET UI is, ironically, its
         | weakest link now) and keep it on the server.
        
         | Smaug123 wrote:
         | The templates are all listed at https://learn.microsoft.com/en-
         | us/dotnet/core/tools/dotnet-n... . You picked a template that
         | is indeed not supported in F#; the F# ecosystem is generally
         | oriented more around the SAFE stack and Fable.
        
         | gsuuon wrote:
         | > dotnet new list
         | 
         | Shows all the available templates - you could give mvc or web a
         | try?
        
       | Dwedit wrote:
       | Yay, the diagram of F#, C#, and VB .net. Because C++/CLI does not
       | exist.
        
       | xenadu02 wrote:
       | There's another power when using the same underlying runtime
       | environment as well: no bridging overhead. If your specific
       | problem set involves a lot of boundary crossing bridging overhead
       | can easily dominate all else.
       | 
       | Long ago I integrated IronJS (written in F#) into a project
       | written in C#. IronJS at the time was a very primitive JS
       | compiler though it was a real compiler using the runtime
       | machinery to emit Expression objects that were JIT'd into native
       | code.
       | 
       | I was very excited about switching to V8 for the vastly improved
       | performance. To my shock and horror once I got it working the
       | performance was worse. It turned out most scripts called our API
       | a lot (the equivalent of the DOM in a browser). Bridging between
       | CLR types and V8 (C++) types completely erased V8's superior
       | performance. No amount of lazy bridging and zero-copy
       | abstractions were enough and I eventually abandoned that branch.
       | 
       | It was a humbling experience that I learned a great deal from.
        
       | pjmlp wrote:
       | C++/CLI is missing from the picture, even if it is only available
       | on Windows.
        
         | TillE wrote:
         | C++/CLI really just exists for creating .NET bindings to C++
         | libraries, right?
         | 
         | If you've got a C interface, LibraryImport in C# is
         | sophisticated enough to get the job done on its own.
        
           | pjmlp wrote:
           | Kind of, originally the plan was to have .NET everywhere.
           | 
           | .NET 1.x brought Managed C++, which was replaced by C++/CLI
           | in .NET 2.0.
           | 
           | However Office and WinDev were never big fans of it, so its
           | main purpose has been as easier interop for C++ libraries
           | indeed.
           | 
           | Also COM and C, as for anyone that is comfortable in C++, is
           | is easier than getting all marshaling annotations correct.
           | 
           | However it isn't an option for code that has to be portable,
           | as it relies on Visual C++ toolchain.
        
       | shortrounddev2 wrote:
       | I want to like F#, but the syntax is just bonkers to me. There
       | are keywords which are used in only one context, such as `then`,
       | and sometimes an operator means something in one context, but
       | something else in another. e.g: equality/assignment
       | let a: int = 1 // Assignment         a = 3 // Testing equality,
       | will give you an error         a <- 4 // Assignment, valid
       | 
       | There's an article here with more things:
       | 
       | https://alexyakunin.medium.com/crying-out-loud-what-i-like-d...
       | 
       | I want to like F# since I love C#, but I just want something
       | closer to Scala, but for .Net
        
         | munchler wrote:
         | The reason this bothers you is because you're trying to apply
         | your imperative experience to a functional language. Once you
         | stop doing that, F# will make a lot more sense. For example:
         | let a: int = 1
         | 
         | This isn't assignment; it's a binding that permanently
         | associates the identifier `a` with the value `1`.
        
         | Eji1700 wrote:
         | This is such a weird example to me, mostly because I've yet to
         | come across a language that doesn't have awkward gotchas, and
         | that one is one of the easiest ("ah yeah...= is only assignment
         | in a let..weird"). The article cited ends with -
         | 
         | > That's it for now. Hopefully, some of these issues will be
         | addressed in future versions of F#, though as I said, most of
         | this is simply annoying / inconsistent. It shouldn't stop
         | anyone from using this awesome language
         | 
         | and as other have pointed out, some of this is complaining
         | about features or not working with the language. File order
         | matters should probably exist in more languages (the amount of
         | debugging/code reading time it saves is insane) and complaining
         | about explicit typing because it's slowing down your contest
         | code is just eye rollingly silly to me.
        
         | FrustratedMonky wrote:
         | It takes a bit of time to grok. But then it becomes pretty
         | simple and streamlined.
         | 
         | Recently I did some F# conversion to Python, and the Python
         | code really did seem ugly and ungainly in comparison.
        
           | wizofaus wrote:
           | Out of curiosity, what was the motivation for the conversion?
           | And did you use a tool (ChatGPT even?) to help?
        
             | FrustratedMonky wrote:
             | I used FABLE, that is like F# transpiler to other
             | languages. It compiles F# to other languages. The Python
             | seems hard to read, but could be my unfamiliarity with
             | Python.
        
         | Smaug123 wrote:
         | Some of the complaints in the article are certainly valid (why
         | would there be early-return in the context of computation
         | expressions, but not in ordinary functions?), but some I claim
         | are actually features, and some are false.
         | 
         | * Linearly ordered files. Several times in F# I have tracked
         | down an issue simply by bisecting the codebase, which is
         | impossible in C# because there's no meaningful way to halve the
         | code. I think I've only once ever had a problem with the linear
         | ordering that wasn't solved simply by reordering some files.
         | 
         | * Explicit type conversions. I've only ever found this awkward
         | when interfacing with C# code that is designed around C#'s
         | extreme laxity. Explicit is better than implicit!
         | 
         | * "No struct tuples" is false - that's what the `struct`
         | keyword is for. (It may have been true when the article was
         | written.)
         | 
         | * Dot notation for indexing is now no longer necessary.
         | 
         | It's certainly true that OO idioms are often clunky and feel
         | strangely like they were constructed by Frankenstein, but then
         | I almost never find myself trying to use them anyway. You don't
         | notice oddities in features which you never think of using!
         | Similarly, the number of times I use `<-` is so low that I
         | don't think of it as being incongruously odd - why shouldn't
         | there be a baroque syntax to indicate the place in your code
         | that's likely to have a 50% higher chance of bugs?
        
           | [deleted]
        
           | WorldMaker wrote:
           | > "No struct tuples" is false - that's what the `struct`
           | keyword is for. (It may have been true when the article was
           | written.)
           | 
           | Quite probably. The underlying CLR ValueTuple type is a
           | relatively recent .NET addition (and partly only exists
           | because C# asked for it). (It was added in Fx 4.7 / Core 1.0,
           | whereas the reference type Tuple was added way back in Fx
           | 4.0.)
        
           | Smaug123 wrote:
           | I have been informed that computation expressions do _not_
           | have early return. For example, `async` does allow you to
           | express what appears to be an early return, but only of the
           | `unit` type, and in fact it doesn 't return early; it simply
           | proceeds straight past the `return` keyword. Raised
           | https://github.com/dotnet/fsharp/issues/15759 .
        
         | sasmithjr wrote:
         | a <- 4 // Assignment, valid
         | 
         | This is a compiler error because you haven't made your variable
         | mutable.
         | 
         | Also, I actually like that initial assignment and equality
         | testing both use =. I think of `let a = 1` to be less like
         | assignment and more like `Assume that a = 1 is true`, so using
         | the same operator (e.g. `a = 3`) makes sense for comparisons.
         | 
         | And `<-` as a separate operator is good because mutability
         | should be exceptional for many (most?) codebases.
        
           | shortrounddev2 wrote:
           | Assume that a = 1 is true
           | 
           | I just don't read code as I would a mathematical proof. I
           | think in terms of what memory locations are equal to what in
           | the stack, or the heap, and what is the lifecycle of that
           | data in that memory address.
           | 
           | When I read "int a = 1" in C#, I implicitly translate that to
           | "take a 4 byte piece of memory on the stack, and set it equal
           | to 1". I don't think in the abstract sense of a formula.
           | 
           | When I see a class like:                   class Foo {
           | int x = 2;             string xyz = "Hello";         }
           | var foo = new Foo();
           | 
           | I read this as "allocate a chunk of memory big enough in the
           | heap to insert a 4 byte integer and an 8 byte pointer. Set
           | that 8 byte pointer equal to a static chunk of memory where
           | the "Hello" string is pooled.
        
             | FrustratedMonky wrote:
             | This is the biggest hurdle for a lot of people, at least
             | for me. The immutability.
             | 
             | IF you have grown up doing objects, or C#, and thinking
             | with variables. Then 'a=1' means a memory for variable a
             | has a 1, and you should be able to change that. But it is
             | really a like a function where the function returns a 1.
             | 
             | 'let a = 1' is not assigning the value 1 to variable a.
             | 
             | 'a' is a function that returns a 1.
             | 
             | I think this is biggest reason why people trying to learn
             | functional programming in languages that don't enforce
             | immutability, have a harder time than with languages that
             | do enforce it.
             | 
             | Like moving to another country, and the people around you
             | purposely don't speak English so you have to learn the
             | language. If the did speak English to help you, then you
             | wouldn't learn the language.
             | 
             | Enforcing immutability is like this.
        
               | shortrounddev2 wrote:
               | I got the concept of immutability, but I inevitably ended
               | up recreating OOP patterns whenever I tried working with
               | F#. I do Asp.net WebAPI Projects and trying to do
               | dependency injection ends up just translating C# to F#
               | code rather writing idiomatic F#. I just don't know if
               | HTTP is something F# is really good at doing. I can see
               | it being really useful if you were writing something
               | math-heavy
        
               | tremon wrote:
               | F# is severely hampered by its standard library, which is
               | object-oriented by design. Some newer things like fluent
               | api's or object initializers are more amenable to F#'s
               | functional style, but on the whole my experience matches
               | yours: as soon as you start interfacing with any .net
               | library, it feels like you're writing in a foreign
               | language.
        
               | FrustratedMonky wrote:
               | ah. yeah, if you are doing web programming. then for F#,
               | you would use a library that is really like a DSL for the
               | web. One of the things in practice in F#, it seems the
               | most useful libraries are written as DSL's, so it is like
               | a language extension for doing 'whatever'. To really get
               | these web based ones, need to understand "ELM
               | architecture".
               | 
               | In any case. I get it. If you have done ASP.NET, and C#,
               | then suddenly this F# way of building web pages by
               | programming through combining functions, it is hard to
               | get over the hump. Like brain has to re-change how to
               | think through the whole flow. Really, F# on the web is
               | like ELM.
               | 
               | I like https://websharper.com/
               | 
               | but other use this https://suave.io/
        
               | WorldMaker wrote:
               | Giraffe is another interesting one to explore:
               | https://giraffe.wiki/
               | 
               | Giraffe is nice because it is itself built "just" as
               | ASP.NET Core Middleware so it plays a bit more nicely
               | than Suave with a mixed stack of C#-defined Middleware.
               | 
               | It's more likely you accidentally fall back into just
               | translating C# patterns to non-idiomatic F# with Giraffe,
               | but it's also nicer when in that case of needing to live
               | in both worlds and use a mixture of libraries built for
               | C# ASP.NET projects.
        
               | xupybd wrote:
               | I make web apps with the SAFE stack. Using idiomatic F#,
               | the experience has been great.
               | 
               | I can imagine that trying to translate C# to F# would be
               | horrible. That is going against the grain.
               | 
               | I'd encourage you to have a look at the SAFE stack it's
               | really nice to use. https://safe-stack.github.io/
        
             | phillipcarter wrote:
             | > I just don't read code as I would a mathematical proof.
             | 
             | That's fine, although I'd say that FP is probably just not
             | for you. It's very much a style of programming that lends
             | itself more towards "programming is akin to proofs" than
             | "programming is about manipulating things on a von neumann
             | architecture". Neither is an incorrect view of the world,
             | but they do represent different ways of reasoning about
             | things and it's better to use a language more suited
             | towards one way of thinking.
        
               | trealira wrote:
               | To be honest, when I read e.g. Haskell code, I don't get
               | the sense of a mathematical proof at all, not compared to
               | proof assistants like Isabelle/HOL, Coq, or Lean. It
               | looks more like abstract, high-level wizardry, casting
               | that transform the output of one function into the
               | correct type so that it can become input into another;
               | and yet it's very abstract typing, nothing like proof-
               | assistant tactics (though I admit I'm not all that
               | experienced with proof assistants either).
               | 
               | I think immutability is more about making it easier to
               | reason about the code than mathematical proofs
               | specifically.
        
             | trealira wrote:
             | > When I read "int a = 1" in C#, I implicitly translate
             | that to "take a 4 byte piece of memory on the stack, and
             | set it equal to 1".
             | 
             | I think that's overspecifying a bit. It could be kept in a
             | register rather than the stack. And due to to the Single
             | Static Assignment transformation that modern optimising
             | compilers do, variables don't correspond exsctly to
             | registers anymore; each time you modify the variable, it
             | becomew a new variable, and then the compiler removes or
             | changes extraneous modifications and dead code. It only
             | keeps track of the values that move through the code. You
             | could really only count on variables corresponding exactly
             | to stack space registers before the SSA form existed.
        
         | xupybd wrote:
         | Regarding the syntax complaints, this is because F# is
         | functional first. Using mutable variables is hard while using
         | immutable ones is easier.
        
         | daxfohl wrote:
         | I felt the same, but once you get used to the syntax, it's much
         | nicer for functional first coding. If you find yourself
         | fighting the syntax a lot, you're probably using it in an
         | imperative style that is not idiomatic in f# anyway.
        
         | derefr wrote:
         | Lines 1 and 2 there don't mean different things. They're both
         | attempting to bind/unify `a` with a value. It's just that in
         | the second case, `a` already _has_ a _different_ value, so the
         | binding fails.
        
         | galkk wrote:
         | The example with <- is not an assignment, it is called
         | shadowing and introduces new value with same name, old one
         | isn't changed
         | 
         | But I agree with some ad hoc words criticism
        
           | gsuuon wrote:
           | It is indeed assignment: https://learn.microsoft.com/en-
           | us/dotnet/fsharp/language-ref...
           | 
           | shadowing would be a second 'let a = 2'
        
         | FrustratedMonky wrote:
         | F# is the Scala for .NET.
         | 
         | What about it is lacking?
         | 
         | I'm asking because at one time I was weighing moving to Scala,
         | but the F# algebraic types and compiler seemed more complete.
         | 
         | Is it syntax? that does take some getting used to.
        
           | shortrounddev2 wrote:
           | I meant the syntax, yeah
        
           | hardlianotion wrote:
           | In what way are the algebraic types more complete in F# than
           | Scala? I was interested in F# much earlier in the day, but
           | that was when Mono was not really a thing and I was not
           | really going to go back to Windows.
        
         | louthy wrote:
         | > but I just want something closer to Scala, but for .Net
         | 
         | That's what I have been working toward with my language-ext
         | library [1]. Including a ZIO like effects system [2], Haskell-
         | like Pipes [3], Clojure-like concurrency primitives [4], the
         | fastest immutable data-structures in .NET [5], and lots of
         | other common FP bits.
         | 
         | Obviously more support for expression based programming would
         | be welcome (and higher kinds), but you can do a lot with LINQ
         | and a good integrated library surface.
         | 
         | [1] https://github.com/louthy/language-ext
         | 
         | [2] https://louthy.github.io/language-
         | ext/LanguageExt.Core/Effec...
         | 
         | [3] https://louthy.github.io/language-
         | ext/LanguageExt.Core/Effec...
         | 
         | [4] https://louthy.github.io/language-
         | ext/LanguageExt.Core/Concu...
         | 
         | [5] https://louthy.github.io/language-
         | ext/LanguageExt.Core/Immut...
        
       | tablloyd wrote:
       | You can make the C# code much more F# like with records and a
       | switch expression.
       | 
       | Eg:
       | https://sharplab.io/#v2:EYLgZgpghgLgrgJwgZwLQAUEEsC2UECeAwgP...
        
         | sbelskie wrote:
         | FWIW, this a switch expression rather than a switch statement.
         | 
         | But in any case I really love this addition to the language but
         | the inability to have multi-line or block expression arms is a
         | constant annoyance for me.
         | 
         | You can even combine these with the new one line record syntax
         | to create a poor man's discriminated union.
        
           | ComputerGuru wrote:
           | Your pedantic correction is actually important for another
           | reason: the switch _expression_ (unlike the switch
           | _statement_ ) is defined at the language level as an
           | expression (evaluating to/"returning" a value), which would
           | be ok except C# doesn't (at the language level) have a
           | void/unit type, meaning the switch statement has to return an
           | actual value, limiting the places you can use it compared to
           | the F# counterpart (or the match expression from rust, etc)
           | to very specific cases, usually those performing an
           | assignment.
           | 
           | The workaround for that is the same as the workaround for the
           | really lame one line limitation: you need to call a
           | (preferably (static) local) function in the handler portion
           | and then return something like `true` assigned to a discard.
           | Hacks all around!
           | 
           | Eg
           | 
           | _ = foo switch a when ... => CaseA(foo), _ => CaseB(foo);
           | 
           | With CaseA and CaseB returning bool in order to call a
           | function depending on the value of foo rather than assign a
           | value.
        
         | jcpst wrote:
         | Microsoft has a good tutorial that showcases what you can do
         | when designing with switch expressions in mind:
         | 
         | https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals...
         | 
         | Probably one of my favorite recent-ish additions to the
         | language.
        
           | rjbwork wrote:
           | The fact that they've added all of this great stuff and have
           | STILL not added real discriminated unions is a damn travesty.
           | It would just so drastically improve the language.
        
             | jjtheblunt wrote:
             | genuine misunderstanding : what do you mean by "real"
             | discriminated unions.
             | 
             | I believe I am overlooking something (probably obvious even
             | to me) since i know:
             | 
             | https://learn.microsoft.com/en-us/dotnet/fsharp/language-
             | ref...
             | 
             | is perhaps a misuse of the term in this context.
             | 
             | (I'm guessing you mean more like in Rust, but am not sure.)
        
               | Smaug123 wrote:
               | The parent comment means that C# lacks DUs, not that F#
               | lacks them.
        
             | WorldMaker wrote:
             | Given few people anticipated ValueTuple and C# adding a
             | more direct tuple syntax, I feel like it is only a matter
             | of time before C# adds discriminated unions.
             | 
             | (There are multiple proposals tracking the idea. This seems
             | the most comprehensive and "central":
             | https://github.com/dotnet/csharplang/issues/7016)
        
             | isanjay wrote:
             | Would love to see DU in C#
             | 
             | I think they would add it by C# 14 or 15.
        
             | keithnz wrote:
             | you can easily do them, I added a comment on the article
             | showing how....
             | 
             | https://github.com/linkdotnet/Blog.Discussions/discussions/
             | 7...
        
               | LelouBil wrote:
               | It's just like in Kotlin !
        
             | pjmlp wrote:
             | Maybe the rest of the .NET world has more important stuff
             | to care about?
             | 
             | Anyone that cares so deeply about them can do the work on a
             | F# assembly.
        
               | diarrhea wrote:
               | I'm not arguing there is more important stuff, but DUs
               | would enhance the language on a wide, fundamental level,
               | accelerating a lot of other advancements.
        
               | Risord wrote:
               | Yea I don't care neither but business seems to care. If
               | you listen closely their specs are pretty much bloated
               | with DUs.
        
               | keithnz wrote:
               | its because they are easy to do in C# without explicit
               | support, but the proposal is still in the works, but they
               | argue a lot about the syntax and about exhaustive type
               | checking for all the edge cases.
        
             | ftcHn wrote:
             | Agree.
             | 
             | For now, you can get a reasonable DU via an [external
             | library](https://github.com/mcintyre321/OneOf).
             | 
             | [Nick Chapsas Video on
             | Usage](https://www.youtube.com/watch?v=7z-xjijYfcI).
        
       | pshirshov wrote:
       | Well, I've tried. Interoperability is imperfect and it's painful
       | to use both languages in one project.
        
       | kerblang wrote:
       | Surprised to see that C# doesn't have an Option/Optional
       | type/class yet. Even Java made it over that hump.
        
       | pharmakom wrote:
       | C# has basically zero value once you learn F#.
        
         | oblio wrote:
         | IDE support? Library support?
        
           | pharmakom wrote:
           | They are largely the same between F# and C#
        
         | tester756 wrote:
         | except projects and job postings count?
        
           | pharmakom wrote:
           | I'm only talking about the part where you solve a problem
           | with code.
        
       | i_s wrote:
       | I'd argue .NET isn't actually that great of a multi language
       | platform. We have a mixed F# and C# solution at work, and that
       | split sometimes causes a lot of friction. If you have some C#
       | code that depends on F# code, that constrains your ability to
       | have F# code depend on C# code. You need to be very careful about
       | how you organize your work to get a good solution (more than on
       | other platforms.)
       | 
       | In the JVM world, mixing languages works a lot better, because
       | you can compile .class files instead of whole assemblies. So
       | mixing clojure and Java, for example, is very easy to do in any
       | order.
        
       ___________________________________________________________________
       (page generated 2023-08-07 23:00 UTC)