What are the advantages of built-in immutability of F# over C#?
I heard F# has native support for immutability but what about it that can not be replicated in C#? What do you get by an F# immutable data that you don't get from a C# immutable data?
Also in F#, is there no way to create mutable data? Is everything immutable?
If you use both C# and F# in an application, can you change the immutable F# data in C#? Or do you just have to create new C# types that uses the immutable F# data and replaces the references that points to those dat开发者_如何学Ca?
The way F# works makes it easier to work with immutable data but there's nothing special that can't be done in C# in that regard. It may not provide neat syntax though.
F# supports mutable data with the
mutable
keyword. F# is not a pure functional language. It supports imperative constructs like loops as well as functional constructs.No. Immutable types are really immutable. The .NET type system is shared across both languages. You can't change the immutable data from C# either (short of reflection and memory hacks, of course).
Mehrdad already answered all your questions, but just to elaborate on #1 - the difference is in the amount of code you need to write. For example, here's the definition and sample use of a readonly point in C#:
class Point
{
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
var p = new Point(1, 2);
You could use automatic properties to make this a little bit shorter, but then immutability is not enforced for code inside the class definition, only for its clients.
In F#, you'd just write:
type Point = { x: int; y: int }
let p = { x = 1; y = 2 }
And if you wanted it to be mutable:
type Point = { mutable x: int; mutable y: int }
let p = { x = 1; y = 2 }
p.x <- 3
p.y <- 4
The biggest difference between F# and C# with respect to immutability is that F# is immutable by default. It's possible to replicate all of the immutable constructs and collections in C# but it takes a lot of extra work. In F# you simply get it for free.
F# is a hybrid language and does support mutability in a couple of forms. The simplest in the mutable keyword
let value1 = 42; // immutable
let mutable value2 = value1; // mutable
value2 <- 13;
Barring reflection tricks, once the data is created in F# it is immutable irrespective of the language you consume it from.
As others noted, there are some important benefits of using immutable data. To name a few:
- Parallelization - It is easier to parallelize program that calculates the result and returns it in an immutable data structure.
- Understanding code - If you write program using immutable data, the only thing a piece of code can do is to return a result - this makes program more readable, because you see what a function/method does just by analyzing inputs & outputs
Technically seaking, you can write the same immutable data structure in both C# and F#. The problem is, that F# encourages you to do this, while writing true immutable data strctures in C# is a bit painful. This means that when writing F# code, you'll more likely write immutable structures (because it's easier!) and you'll use mutability (which is possible in F# as well) only when you'll really need it (it's harder!)
Aside from declaring immutable types by default, F# also has some nice features that make working with them easier. For example when working with records:
type MyRect = { X : int; Y : int; Width : int; Height : int }
let r = { X = 0; Y = 0; Width = 200; Height = 100 }
// You'll often need to create clone with one field changed:
let rMoved1 = { X = 123; Y = r.Y; Width = r.Width; Height = r.Height }
// The same thing can be written using 'with' keyword:
let rMoved2 = { r with X = 123 }
You can write the same thing in C# too, but you'll need to declare immutable data structure with method WithX
that returns a clone with modified X
field, WithY
, WithWidth
, etc... Here is an incomplete example:
class MyRect {
readonly int x, y, width, height;
MyRect WithX(int newX) {
return new MyRect(newX, y, width, height);
}
// etc...
}
This is a lot of work without any help from the compiler.
What do you get by an F# immutable data that you don't get from a C# immutable data?
F# allows you to easily make modified copies of immutable data, this is very tedious and time consuming to from C#. Consider creating a record in F#:
type Person = { FirstName: string; MiddleName: string; LastName: string }
let me = { FirstName = "Robert"; MiddleName = "Frederick"; LastName = "Pickering" }
Say I wanted alter the last name field, in F# I can do this by making a copy using the "with" keyword:
let me' = { me with LastName = "Townson" }
If you wanted to do this in C# you'd have to create methods that copied each field into a new structure and there's a strong possibility you'd get the fields mixed up.
There are other suitable advantages to do with collections. For example C# supports the immutable ReadOnlyCollection. However each time you want to add a new item to this collection you must make a copy of the whole collections. F# build in list allows you to just add a new item to the end of the list without making a copy of it, i.e. newly the resulting list will actually share most of the old list. i.e.:
let myList = [3; 2; 1]
let myList' = 4 :: myList
When creating "myList'", the whole of "myList" is preserved unchanged and "4" is added to it's head to create "myList'".
I think you are looking at this from a too detailed feature-for-feature point of a view.
I'd see the major advantage of immutability by default of functional programming langauges to be on how it affects the actual programming mind set of the developer. When mutation is the default, the programming mind set is geared towards solutions by mutating the data. When immutability is the default, the programming mind set is geared towards solutions by transforming the data.
To elaborate on why the latter mind set is better. When developing programs through mutating the data, you end up getting bogged down in fine details, so your focus tends to be on how the program works 'in the small'. When developing programs through transforming the data, you don't need to worry about many of the fine details (such as how different mutating parts of your program interact with each other), and your focus tends to be on how the program works 'in the large'. So, the latter mind set gears the developer towards having a better and clearer 'big picture' on how the program works.
While having a nice clean 'big picture' of a program is nice, in some cases, real life concerns can outweigh it. Some data structures (arrays, multi dimensional arrays), are not good candidates for immutability because of the high cost of making new copies, so some common sense should always be applied on when to not use immutability even with functional languages.
Edit to answer the comment:
Functional language purists would argue that it would make the code uglier. I consider myself not to be a purist, so I don't think so; well, perhaps uglier from a theoretical point of a view.
F# is an impure functional programming language, so it supports mutability when it's needed. Having part of your state be mutable doesn't invalidate the benefits of having most of your state be immutable.
In most cases, you end up using a different (pure) data structure where you would normally use an array in an imperative language. E.g. a tuple, a list or a tree (or a set/map build on top of a tree; the standard libraries usually come with implementations with good time complexity).
And if you think that you really need a mutable array (for performance reasons), you have it available, so nothing is stopping you from using one.
What do you get by an F# immutable data that you don't get from a C# immutable data?
The first benefit is that an F# function doesn't have any other effect besides returning its result. No global data is changed, no mutable data is depended upon, and so you are guaranteed that, provided you stick to immutable data, the same call produces the same result, reliably, every time.
This first benefit is already nice by itself, because it makes your code easier to understand, but the big benefit kicks in because F# functions can safely be composed. Programming by function composition turns out to be an incredibly powerful, modular way to program with reusable parts. And you can build really powerful parts which can be put together in lots of different ways, so you can write more programs with less code.
These ideas are explained better than I ever could in John Hughes's landmark paper Why Functional Programming Matters. John explains how removing the ability to mutate actually adds expressive power to the language over all. Read the paper!
精彩评论