Related
Is there any case in C# code where positional arguments are not enough?
I really don't see any benefit of named arguments, on contrary I can see how overusing of named arguments could make code hard to read? So my question is, why would someone use them and how can it help in writing better code as I'm sure they were not implemented without reason?
This looks cleaner to me:
private void Foo(1, true);
then:
private void Foo(bar: 1, baz: true);
Named arguments are meant to increase readability. For example I've just used one as such
public void MarkAsDone(bool skipped) {}
Now by invoking the method without the name we have an ambiguity
MarkAsDone(true); //does true mean that it is successfully done?
Which can be resolved by clarifying with a name
MarkAsDone(skipped: true);
I think using the named parameter makes the client code way less ambiguous.
Apart from that they can be used to uniquely identify an optional parameter when there's more than one with the same type
MarkAsDone(int first, int second=0, int third=0) {}
///
MarkAsDone(1, third: 3);
I use named parameters to make call sites clearer and when I have parameters with default values. The default values case has been discussed in a number of different answers already, so let's talk about call site clarity.
An analysis with metasyntactic variables isn't going to highlight their usefulness. Consider, instead this more "real-world", if you will, example.
Let's look at a call site:
something.OpenFile(documentPath, true);
What is this going to do? It's going to open documentPath. And do something else? What else? I can't remember, even though I wrote OpenFile only a week ago.
Here are three different examples for OpenFile that are relatively realistic.
void OpenFile(string path, bool shouldOverwrite)
void OpenFile(string path, bool preserveExisting)
void OpenFile(string path, bool enableWriting)
With named parameters, we can make the call sites clear:
something.OpenFile(documentPath, shouldOverwrite: false);
It's pretty clear that the file will not be overwritten.
something.OpenFile(documentPath, preserveExisting: false);
It's pretty clear that the file will be overwritten if needed.
And finally, we have:
something.OpenFile(documentPath, enableWriting: false)
It's pretty clear that the file will be opened for reading only.
Could this particular example be solved with something else like an enum? Yes. Can you always change the code? No. Does everyone else have the same abiding hatred for bool parameters that I do? No. :-)
Can you over do it with named parameters? Yes. Do good local variable names help? Tremendously.
We found a very interesting use for named arguments when we needed to use a method like this:
private void ShowPopup(FrameworkElement content,
string title = "My Application",
bool isDialog = true,
double? width = null,
double? height = null,
double? offsetX = null,
double? offsetY = null,
bool isTransparent = false,
... etc)
where almost all parameters are optional. There are situations where you will want to leave all these parameters to their default, except one or a couple of them, such as:
PopupHelper.ShowPopup(_view, isTransparent: true);
or things like that.
They are useful - indeed implicitly required - when calling methods with optional parameters - because when you call a method of with optional parameters you must specify the ones you want to pass, otherwise you have to provide the whole list up to the last one you want to use.
Given a method like this:
public void Do(Thing thing, bool doItTwice = false, bool logResults = false,
string something = null, bool makeTeaAfterwards = false)
You then must use named parameters to avoid having to specify the whole list:
Do(thing, makeTeaAfterwards: true);
Rather than:
Do(thing, false, false, null, true);
The latter also has the disadvantage that you must replicate the defaults, which introduces the possibility of error.
I'm not sure, but I think you have misunderstood named parameters.
Please see:
http://www.dotnetperls.com/named-parameters
Basically, they are useful when you've a lot of parameters to send to a method. With named parameters you can be sure of which parameters you are sending to the method
Method1(test1: 1, ..., test20: 10);
You should use it careful, as it has a substantial performance drawback.
If you had a method signature like:
private void Foo(int bar, bool baz);
then named arguments don't help much, no.
But imagine a method signature like:
private void Foo(bool bar, int baz=0, int qux=0);
And say you wanted to pass the default value of baz but a parameter for qux, then named arguments helps there:
Foo(true, qux:1);
These days C# supports optional parameters, for example:
public void Dance(string song = "makarena",
string location = "your house",
string performer = "Michael",
DateTime? date = null,
int milliseconds = 0,
Action callback = null)
{
///party code
}
Now you can call it by skipping over some of the arguments (in any order):
Dance(location : "my house", date : DateTime.Now, performer : "Christina");
I tested the code. Sadly I didn't see Christina's sexy dance because I forgot to set the milliseconds parameter :P (Not my fault, but of those who did the API, why would they make milliseconds optional? :P).
My opinion is that the true value of this is in COM Interop and similar situations. For example Office COM objects has some methods with lots of arguments that are a pain without these (For example Word.Documents.Open).
Good practice is to keep the arguments in the correct order still.
Good practice is to not blindly remove the names when you get your readability from elsewhere.
Example function:
public void TrackDataChange(IEntity oldData, IEntity newData)
Old call:
dataTrackerService.TrackDataChange(newData: valuesFromClient.ToEntity(), oldData: valuesFromDb.ToEntity())
New call:
var oldData = new ValueEntityConverter(valuesFromDb).Entity;
var newData = new ValueEntityConverter(valuesFromClient).Entity;
dataTrackerService.TrackDataChange(newData, oldData);
Of course this compiles but the resulting data is now messed up, because
originally the order was wrong but still worked correctly because of the names
someone removed the names but didn't check the order
Not sure you can solely blame either developer...
Answered to a similar question that got deleted so I´ll post it here.. I think the Com Call argument has not been included yet:
There is one or two good reasons to use named parameters.
1) When using Com calls / Optional parameters
Imagine this:
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true;
var myFormat =
Microsoft.Office.Interop.Excel.XlRangeAutoFormat.xlRangeAutoFormatAccounting1;
excelApp.get_Range("A1", "B4").AutoFormat(myFormat, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
In C# 3.0 and earlier versions, you need to supply an argument for
every parameter.
However, you can greatly simplify the call to AutoFormat by using named and optional arguments, introduced in C# 4.0.
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );
2) Named parameters can create better / clearer code
File.Copy("source.txt", "destination.txt", true);
Unless you’re a developer that is already familiar with this method, you can only guess as to what the last Boolean parameter is for. With C# 4.0 named parameters this code can be written like this to express intent more clearly:
File.Copy("source.txt", "destination.txt", overwrite: true);
3) It shortens code
instead of using
Person person = new Person();
person.FirstName = "John";
person.LastName = "Smith";
person.DateOfBirth = new DateTime(1970, 1, 1);
you can use (depends on readability preferences)
Person person = new Person() { FirstName = "John", LastName="Smith", DateOfBirth = new DateTime(1970, 1, 1)};
Useful to ensure non-breaking code when calling against generated methods
In an application where a method has parameter values that are tied to fields in a database (e.g. a constructor for a test objects that has properties in the database), it's possible that, based on a change to the database, the order of the parameters might change. If the data types of the method parameters remain the same, and hand-rolled code (e.g. a unit test) calls the generated method, it can be very difficult to see that the hand-rolled code no longer matches the generated code. Named parameters can help prevent this.
For example:
A database has a table MyCreation with columns IsBig and IsColoured. Using an ORM, a test method to create sample data exists to populate such data:
/* Generated Code from an ORM */
public IMyCreation CreateTestObject(bool isBig, bool isColoured)
{
IMyCreation _myCreation = new MyCreation();
_myCreation.IsBig = isBig;
_myCreation.IsColoured = isColoured;
return _myCreation;
}
A method in a hand-rolled test class makes use of this:
var myCreation = mcTest.CreateTestObject(false, true);
Now, if the DB were to change, e.g. a parameter were renamed (IsBig becomes IsGrande), then the order of the parameters might change, and the generated function now becomes:
/* Generated Code from an ORM */
public IMyCreation CreateTestObject(bool isColoured, bool isGrande)
{
IMyCreation _myCreation = new MyCreation();
_myCreation.IsColoured = isColoured;
_myCreation.IsGrande = isGrande;
return _myCreation;
}
However, everything will still compile. The calling code is still valid, but no longer correct, as the value for each parameter is different.
var myCreation = mcTest.CreateTestObject(false, true);
If named parameters are used, protection against generated parameter changes is achieved:
var myCreation = mcTest.CreateTestObject(isBig: false, isColoured: true);
... this code would then break (in the case of a param rename) - which is desirable!
Or, in the case of a simple parameter swap without a rename, would continue to work without needing a fix:
var myCreation = mcTest.CreateTestObject(isBig: false, isColoured: true);
would be correct, regardless of whether the function signature is
public IMyCreation CreateTestObject(bool isBig, bool isColoured)
or
public IMyCreation CreateTestObject(bool isColoured, bool isBig)
For generated code, where ugly code is more tolerable, an approach like this might be useful to force named parameters to be used.
They can be a nice declaration of intent, and increase readability where the arguments are the same type or can be implicitly converted.
E.g
int Duration(d1,d2)
Is that from d1 to d2 or d2 - d1 ?
Intellisense might tell you if the arguments have good names, and or the documentation is correct and up to date. Or you could look at the code...
With multiple optional arguments they are even more useful, avoid rules like all optional arguments have to be the last ones, and all up to the one you want to not use the default have to be specified. Total nightmare if for some reason you need to re-factor the argument list.
You might want to think about the differences between succinct and terse. Succinct is always good, terse rarely is.
I feel it it sacrifices compactness for readability. Lets say you have a function that cleans an array of some unwanted elements. Unwanted may be: old, deprecated, unused:
// unnamed:
collection.remove(true, true, false)
// named:
collection.remove(old:true, deprecated:true, unused:false);
There are many other ways to achieve this of course, from bitwise flags to intellisense. But, when programming in Python I use named params quite allot. Of course, no strong typing there, and worse tooling.
In a method that is so long that it scrolls off the screen. Just to make life easier as I program, if I want to refer to the variables of a class I can use the Me or this objects depending on which language I am using.
eg. Me.var1 = "Hello"
Is there an object (like Me) that would allow easy reference to the parameters of a function?
eg. params.par1 = "World"
There's no such feature in the language. Local variables and method arguments are treated specially by the .NET jitter, they are heavily optimized at runtime. Anything .NET would do, or you would do, to capture those variables would defeat such optimizations.
A very simple solution is to use Window + Split, it gives you two views on your code. Scroll the top one to the method header, write your code in the bottom one. You can adjust the splitter to give you more room in the bottom window.
Taking advantage of IntelliSense would be another way. Prefix the argument names with a little string, like "par". Then typing "par" in your code automatically gives you the list of argument names in the IntelliSense popup window.
These are however but band-aids for the real problem. As soon as you find yourself reaching like this, your first thought should be to split up the code in the function to make it smaller. There are some hard truths I discovered after thirty years of coding:
Long methods have more bugs. There's a metric for this, called "cyclomatic complexity". The higher the number, the more likely that the code is broken. Well supported by Visual Studio, this blog post is useful.
Code should never be indented more than 3 levels deep. By far the simplest way to discover that your cyclomatic complexity is getting out of hand without running a tool.
A method should never be larger than what fits on the screen. Any code that doesn't fit is a cognitive tax that produces compile errors and bugs. There's a corollary to this, programmers with big monitors create more bugs. The hard rule I use is one inspired by using DOS editors, a method should not have more than 25 lines of code.
Wide code produces a special kind of bug, the nasty kind that you can't see. Anything that's off the screen to the right is code that may have a bug that can take you a long time to discover. VB.NET is especially prone to this kind of bug since it uses end-of-line as a statement terminator. Much improved in VS2010 btw, the underscore is now optional in many cases. Always break your line to avoid this kind of bug.
Plan ahead and write maintainable code. Maintained code is never smaller than the original. If you already have trouble writing the original code then by definition you cannot maintain it. You have to start out small.
Always design first, code later. Long methods are a strong indicator of not thinking about code long enough before you start coding. In itself a strong bug inducer, in addition to writing correct code that just doesn't do the job.
The short answer is no. It seems like you are hoping to use this to distinguish between parameter scope and class scope for function parameters and fields with the same name, unfortunately you can't. Either use different naming schemes, or do the following:
public class MyClass {
private string myString;
private int myInt;
public MyClass(string myString) {
this.myString = myString;
}
public int DoStuff(int myInt) {
this.myInt += myInt;
return this.myInt;
}
}
to be really clear and avoid problems, you could change the names:
public class MyClass {
private string m_myString;
private int m_myInt;
public MyClass(string myString) {
m_myString = myString;
}
public int DoStuff(int myInt) {
m_myInt += myInt;
return m_myInt;
}
}
And you should really start by writing a test before the code, then you can check that you haven't accidentally mixed things up in your code.
Footnote
I include this as people coming to the title of this question may be looking for the following information.
While you say
Just for ease of programming - if I am a long way down in a function I would like to see what parameters there are without having to scroll up
In case you really want to look at your parameters from inside your code for other reasons then you need reflection. This is slow, and it's typical use would be to find a method, then reflect the parameters in that method. For a very comprehensive sample, see MSDN - ParameterInfo Class. The pertinent part of the code is:
foreach (MemberInfo mi in typeof(MyClass).GetMembers() )
{
// If the member is a method, display information about its parameters.
if (mi.MemberType==MemberTypes.Method)
{
foreach ( ParameterInfo pi in ((MethodInfo) mi).GetParameters() )
{
Console.WriteLine("Parameter: Type={0}, Name={1}", pi.ParameterType, pi.Name);
}
}
You should be able to use GetParameters() reflection method
MethodInfo barMI = bar.GetMethod("Foo");
ParameterInfo[] pars = barMI.GetParameters();
foreach (ParameterInfo p in pars)
{
Console.WriteLine(p.Name);
}
You can use this in run time. But for your aim, I would try to refactor the number of functions and their names. I try to keep code length under 80 symbols per line and the number of lines in a class under 100. Which is not always possible, but it's a good objective to decouple stuff and keep classes simple.
A simple way would be to encapsulate your parameters in an object so you can just refer to that, and intellitype (or whatever predictive feature) would show you what properties you have available without having to scroll back up. Like this
public class MyParamObject{
public string FirstParam {get;set;}
public string SecondParam {get;set;}
}
Then you could change your method from
public void MyReallyOvergrownMethod(string firstParam, string secondParam){...
to
public void MyReallyOvergrownMethod(MyParamObject params){...
then you can use the params parameter like this in the method
//Deep inside the method
if(params.FirstParam == "SomeValue"{//Do something
This is a numpty solution to a problem that would be best solved by refactoring your method. Look at loops, and conditionals and get them out into seperate private methods that are named after what they do. Loads of stuff on this, if you search for cleancoders.
In light of your comment "Just for ease of programming - if I am a long way down in a function I would like to see what parameters there are without having to scroll up": in Visual Studio, with code showing, just above the scrollbar there is a little bit you can grab and pull down to split the window. You can then have your function declaration visible in one pane and scroll as much as you like in the other. Or you can use Window menu->Split.
I've been wondering about this: would you support using simply an object as a parameter in your method? My reason behind doing this would be overloading. Currently, I'm trying to create a method that caters to many different datatypes: string, decimal, DateTime... the list goes on.
It's getting a bit messy though, so I was thinking of doing the following
public void GenericMethod(object val)
{
if (val is string)
// process as string
else if (val is decimal)
// process as decimal
else if (val is DateTime)
// do something for dt
else
// ...
}
What do you think of such a method? Would it incur unnecessary overhead? (during type checking) Have you implemented it? Tell me...
EDIT: Yeah, and just a sidenote, I'm kinda familiar with overloading. But it gets a little annoying when there are like more than 10 overloads...
Yes, that would work. However there are better ways of doing this.
Your best bet is to use overloads:
public void GenericMethod(string val)
{
// process as string
}
public void GenericMethod(decimal val)
{
// process as decimal
}
etc.
Whenever you use a is keyword in your code that's a huge hint that you're probably forgetting to use some important O.O. principles: overloads, subclasses, or the like.
Overloads aren't actually that annoying to work with, just to write. Remember, you're not coding this for yourself today, you're coding this for yourself three months from now when you have to read the code and figure out why the heck you did it that way, or where in the world that bug comes from.
Yet another reason to avoid the "switch on type" technique is for consistency with the .NET framework (and thus people's expectations). Follow Console.Write and the other wide variety of methods that are overridden within and under a given class.
I've been wondering about this: would you support using simply an object as a parameter in your method?
Very rarely. If there's a fixed set of types which are properly supported - and you'll throw an exception otherwise - then I'd use overloads.
If you can actually accept any type, and you'll handle a not-specially-supported type in some well-known way, then it's okay to accept object. That's what LINQ to XML does all over the place, and the result is a very clean API. I'd do it very carefully though - it's rarely a good idea.
And yes, there'd be an overhead. I wouldn't usually make that the basis of the decision though - the overhead will be small enough to be negligible in most cases. Design your API as cleanly as you can, then work out whether it's going to cause a bottleneck.
Yes, it would incur overhead for both type checking and boxing/unboxing the value type. I would recommend the overloads.
Another possibility, as long as you aren't doing a lot of math with the number, would be to make it a generic method. Arithmetic is rather difficult with generics though, as there are no constraints for value types which enables the use of operators.
No need of those!
Just declare as many methods with same name as you want and take each type as argument in each method.[This is called Overloading. e.g. You may have seen that +1 Overloads beside Methods, which implies that there is 1 more Method with same name but with different argument types]
Say Like this :
void Method(decimal d)
{
//Process Decimal
}
void Method(string s)
{
//Process String
}
By default, It will find its own method according to the Type.
There are cases where your approach makes sense. I've used it before, mostly when I have a bunch of processing that is the same for different data types.
But this is not overloading. Overloading would be to define different signatures for the same method name like this:
public void GenericMethod(string val)
{
// process as string
}
public void GenericMethod(decimal val)
{
// process as decimal
}
public void GenericMethod(DateTime val)
{
// do something for dt
}
// Etc.
And for some cases, this approach makes more sense.
Implementing many overloads one of them takes object is no problem. Take a look at Console.WriteLine overloads for example. http://msdn.microsoft.com/en-us/library/system.console.writeline.aspx However, take care that int for example can conflict with double:
int sum(int i, int j)
{
return i + j;
}
double sum(double i, double j)
{
return i + j;
}
object sum(object i, object j)
{
return i.ToString() + j.ToString();
}
==============================
static void Main()
{
sum(1, 2); // Error: ambigous call between `int` and `double` versions
sum(1.0, 2.0); // calls double version, although 1.0 and 2.0 are objects too
sum("Hello", "World"); // object
}
C# delegates have always been difficult for me to grasp and so I was very happy to stumble across logicchild's article on The Code Project web site titled "C# Delegates: Step by Step". He has a very succinct way of explaining C# delegates and I can recommend it to you. However, in trying out the examples, I see that are two ways to initialize a delegate, mainly:
//create a new instance of the delegate class
CalculationHandler sumHandler1 = new CalculationHandler(math.Sum);
//invoke the delegate
int result = sumHandler1(8, 9);
Console.WriteLine("Result 1 is: " + result);
and
CalculationHandler sumHandler2 = math.Sum;
//invoke the delegate
int result = sumHandler2(8, 9);
Console.WriteLine("Result 2 is: " + result);
where the math class is defined as
public class math
{
public int Sum(int x, int y)
{
return x + y;
}
}
So which is the "correct" way and why?
They are both correct, but method group conversion, which is the second option was added in 2.0 (IIRC). I.e. if you're using an old version of the compiler you need to use the first option. Otherwise the extra typing is really redundant.
I always use the first method for the sake of readability. The second option makes it appear that math.Sum is a property and is returning a result that is a CalculationHandler. Personally, I think that's confusing.
Both are correct.
The second one is a shortcut provided by the compiler, both does actually create the code of the first one.
The first one shows more clearly what's actually happening, while the second one is less code so it's easier to read (once you understand what's really happening).
Personnaly I preferre the second option (method group conversion). From a functional point of view I don't care about the type of delegate, since that will not give me any hints to what the method assigned to the delegate is doing when invoked.
The method name will (at least should) however give me a good idea of what's going to happen when the delegate is invoked and in the second option I don't have to search for the method name.
As a side note VS will give you the first version if you use autocomplete with event handler registration. Resharper will use the second and mark part of the code in the first version as redundant.
Both ways are OK, short version is just C# compiler service. The first way is more verbose and shows exactly what happens. Both versions produce the same IL code, which is actually close to the first version.
I will be add also additional variants of the initialization by lambda expression, which can be useful in some cases:
Func<int, int, int> func = Sum;
func = new Func<int, int, int>(Sum);
func = (x, y) => Sum(x, y);
I don't fully believe that the IL code in all cases will be the same (i didn't check it, with lambda expression can exist the "intermediate call"/"variable"), but the last can give additional variants to call the method
func = (int _, int y) => Sum(5, y);
func = (_, y) => Sum(5, y);
There is a lot of talk about monads these days. I have read a few articles / blog posts, but I can't go far enough with their examples to fully grasp the concept. The reason is that monads are a functional language concept, and thus the examples are in languages I haven't worked with (since I haven't used a functional language in depth). I can't grasp the syntax deeply enough to follow the articles fully ... but I can tell there's something worth understanding there.
However, I know C# pretty well, including lambda expressions and other functional features. I know C# only has a subset of functional features, and so maybe monads can't be expressed in C#.
However, surely it is possible to convey the concept? At least I hope so. Maybe you can present a C# example as a foundation, and then describe what a C# developer would wish he could do from there but can't because the language lacks functional programming features. This would be fantastic, because it would convey the intent and benefits of monads. So here's my question: What is the best explanation you can give of monads to a C# 3 developer?
Thanks!
(EDIT: By the way, I know there are at least 3 "what is a monad" questions already on SO. However, I face the same problem with them ... so this question is needed imo, because of the C#-developer focus. Thanks.)
Most of what you do in programming all day is combining some functions together to build bigger functions from them. Usually you have not only functions in your toolbox but also other things like operators, variable assignments and the like, but generally your program combines together lots of "computations" to bigger computations that will be combined together further.
A monad is some way to do this "combining of computations".
Usually your most basic "operator" to combine two computations together is ;:
a; b
When you say this you mean "first do a, then do b". The result a; b is basically again a computation that can be combined together with more stuff.
This is a simple monad, it is a way of combing small computations to bigger ones. The ; says "do the thing on the left, then do the thing on the right".
Another thing that can be seen as a monad in object oriented languages is the .. Often you find things like this:
a.b().c().d()
The . basically means "evaluate the computation on the left, and then call the method on the right on the result of that". It is another way to combine functions/computations together, a little more complicated than ;. And the concept of chaining things together with . is a monad, since it's a way of combining two computations together to a new computation.
Another fairly common monad, that has no special syntax, is this pattern:
rv = socket.bind(address, port);
if (rv == -1)
return -1;
rv = socket.connect(...);
if (rv == -1)
return -1;
rv = socket.send(...);
if (rv == -1)
return -1;
A return value of -1 indicates failure, but there is no real way to abstract out this error checking, even if you have lots of API-calls that you need to combine in this fashion. This is basically just another monad that combines the function calls by the rule "if the function on the left returned -1, do return -1 ourselves, otherwise call the function on the right". If we had an operator >>= that did this thing we could simply write:
socket.bind(...) >>= socket.connect(...) >>= socket.send(...)
It would make things more readable and help to abstract out our special way of combining functions, so that we don't need to repeat ourselves over and over again.
And there are many more ways to combine functions/computations that are useful as a general pattern and can be abstracted in a monad, enabling the user of the monad to write much more concise and clear code, since all the book-keeping and management of the used functions is done in the monad.
For example the above >>= could be extended to "do the error checking and then call the right side on the socket that we got as input", so that we don't need to explicitly specify socket lots of times:
new socket() >>= bind(...) >>= connect(...) >>= send(...);
The formal definition is a bit more complicated since you have to worry about how to get the result of one function as an input to the next one, if that function needs that input and since you want to make sure that the functions you combine fit into the way you try to combine them in your monad. But the basic concept is just that you formalize different ways to combine functions together.
It has been a year since I posted this question. After posting it, I delved into Haskell for a couple of months. I enjoyed it tremendously, but I placed it aside just as I was ready to delve into Monads. I went back to work and focused on the technologies my project required.
And last night, I came and re-read these responses. Most importantly, I re-read the specific C# example in the text comments of the Brian Beckman video someone mentions above. It was so completely clear and illuminating that I’ve decided to post it directly here.
Because of this comment, not only do I feel like I understand exactly what Monads are … I realize I’ve actually written some things in C# that are Monads … or at least very close, and striving to solve the same problems.
So, here’s the comment – this is all a direct quote from the comment here by sylvan:
This is pretty cool. It's a bit abstract though. I can imagine people
who don't know what monads are already get confused due to the lack of
real examples.
So let me try to comply, and just to be really clear I'll do an
example in C#, even though it will look ugly. I'll add the equivalent
Haskell at the end and show you the cool Haskell syntactic sugar which
is where, IMO, monads really start getting useful.
Okay, so one of the easiest Monads is called the "Maybe monad" in
Haskell. In C# the Maybe type is called Nullable<T>. It's basically
a tiny class that just encapsulates the concept of a value that is
either valid and has a value, or is "null" and has no value.
A useful thing to stick inside a monad for combining values of this
type is the notion of failure. I.e. we want to be able to look at
multiple nullable values and return null as soon as any one of them
is null. This could be useful if you, for example, look up lots of
keys in a dictionary or something, and at the end you want to process
all of the results and combine them somehow, but if any of the keys
are not in the dictionary, you want to return null for the whole
thing. It would be tedious to manually have to check each lookup for
null and return, so we can hide this checking inside the bind
operator (which is sort of the point of monads, we hide book-keeping
in the bind operator which makes the code easier to use since we can
forget about the details).
Here's the program that motivates the whole thing (I'll define the
Bind later, this is just to show you why it's nice).
class Program
{
static Nullable<int> f(){ return 4; }
static Nullable<int> g(){ return 7; }
static Nullable<int> h(){ return 9; }
static void Main(string[] args)
{
Nullable<int> z =
f().Bind( fval =>
g().Bind( gval =>
h().Bind( hval =>
new Nullable<int>( fval + gval + hval ))));
Console.WriteLine(
"z = {0}", z.HasValue ? z.Value.ToString() : "null" );
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
Now, ignore for a moment that there already is support for doing this
for Nullable in C# (you can add nullable ints together and you get
null if either is null). Let's pretend that there is no such feature,
and it's just a user-defined class with no special magic. The point is
that we can use the Bind function to bind a variable to the contents
of our Nullable value and then pretend that there's nothing strange
going on, and use them like normal ints and just add them together. We
wrap the result in a nullable at the end, and that nullable will
either be null (if any of f, g or h returns null) or it will be
the result of summing f, g, and h together. (this is analogous
of how we can bind a row in a database to a variable in LINQ, and do
stuff with it, safe in the knowledge that the Bind operator will
make sure that the variable will only ever be passed valid row
values).
You can play with this and change any of f, g, and h to return
null and you will see that the whole thing will return null.
So clearly the bind operator has to do this checking for us, and bail
out returning null if it encounters a null value, and otherwise pass
along the value inside the Nullable structure into the lambda.
Here's the Bind operator:
public static Nullable<B> Bind<A,B>( this Nullable<A> a, Func<A,Nullable<B>> f )
where B : struct
where A : struct
{
return a.HasValue ? f(a.Value) : null;
}
The types here are just like in the video. It takes an M a
(Nullable<A> in C# syntax for this case), and a function from a to
M b (Func<A, Nullable<B>> in C# syntax), and it returns an M b
(Nullable<B>).
The code simply checks if the nullable contains a value and if so
extracts it and passes it onto the function, else it just returns
null. This means that the Bind operator will handle all the
null-checking logic for us. If and only if the value that we call
Bind on is non-null then that value will be "passed along" to the
lambda function, else we bail out early and the whole expression is
null. This allows the code that we write using the monad to be
entirely free of this null-checking behaviour, we just use Bind and
get a variable bound to the value inside the monadic value (fval,
gval and hval in the example code) and we can use them safe in the
knowledge that Bind will take care of checking them for null before
passing them along.
There are other examples of things you can do with a monad. For
example you can make the Bind operator take care of an input stream
of characters, and use it to write parser combinators. Each parser
combinator can then be completely oblivious to things like
back-tracking, parser failures etc., and just combine smaller parsers
together as if things would never go wrong, safe in the knowledge that
a clever implementation of Bind sorts out all the logic behind the
difficult bits. Then later on maybe someone adds logging to the monad,
but the code using the monad doesn't change, because all the magic
happens in the definition of the Bind operator, the rest of the code
is unchanged.
Finally, here's the implementation of the same code in Haskell (--
begins a comment line).
-- Here's the data type, it's either nothing, or "Just" a value
-- this is in the standard library
data Maybe a = Nothing | Just a
-- The bind operator for Nothing
Nothing >>= f = Nothing
-- The bind operator for Just x
Just x >>= f = f x
-- the "unit", called "return"
return = Just
-- The sample code using the lambda syntax
-- that Brian showed
z = f >>= ( \fval ->
g >>= ( \gval ->
h >>= ( \hval -> return (fval+gval+hval ) ) ) )
-- The following is exactly the same as the three lines above
z2 = do
fval <- f
gval <- g
hval <- h
return (fval+gval+hval)
As you can see the nice do notation at the end makes it look like
straight imperative code. And indeed this is by design. Monads can be
used to encapsulate all the useful stuff in imperative programming
(mutable state, IO etc.) and used using this nice imperative-like
syntax, but behind the curtains, it's all just monads and a clever
implementation of the bind operator! The cool thing is that you can
implement your own monads by implementing >>= and return. And if
you do so those monads will also be able to use the do notation,
which means you can basically write your own little languages by just
defining two functions!
A monad is essentially deferred processing. If you are trying to write code that has side effects (e.g. I/O) in a language that does not permit them, and only allows pure computation, one dodge is to say, "Ok, I know you won't do side effects for me, but can you please compute what would happen if you did?"
It's sort of cheating.
Now, that explanation will help you understand the big picture intent of monads, but the devil is in the details. How exactly do you compute the consequences? Sometimes, it isn't pretty.
The best way to give an overview of the how for someone used to imperative programming is to say that it puts you in a DSL wherein operations that look syntactically like what you are used to outside the monad are used instead to build a function that would do what you want if you could (for example) write to an output file. Almost (but not really) as if you were building code in a string to later be eval'd.
You can think of a monad as a C# interface that classes have to implement. This is a pragmatic answer that ignores all the category theoretical math behind why you'd want to choose to have these declarations in your interface and ignores all the reasons why you'd want to have monads in a language that tries to avoid side effects, but I found it to be a good start as someone who understands (C#) interfaces.
See my answer to "What is a monad?"
It begins with a motivating example, works through the example, derives an example of a monad, and formally defines "monad".
It assumes no knowledge of functional programming and it uses pseudocode with function(argument) := expression syntax with the simplest possible expressions.
This C# program is an implementation of the pseudocode monad. (For reference: M is the type constructor, feed is the "bind" operation, and wrap is the "return" operation.)
using System.IO;
using System;
class Program
{
public class M<A>
{
public A val;
public string messages;
}
public static M<B> feed<A, B>(Func<A, M<B>> f, M<A> x)
{
M<B> m = f(x.val);
m.messages = x.messages + m.messages;
return m;
}
public static M<A> wrap<A>(A x)
{
M<A> m = new M<A>();
m.val = x;
m.messages = "";
return m;
}
public class T {};
public class U {};
public class V {};
public static M<U> g(V x)
{
M<U> m = new M<U>();
m.messages = "called g.\n";
return m;
}
public static M<T> f(U x)
{
M<T> m = new M<T>();
m.messages = "called f.\n";
return m;
}
static void Main()
{
V x = new V();
M<T> m = feed<U, T>(f, feed(g, wrap<V>(x)));
Console.Write(m.messages);
}
}