Functional Programming in C# - Oliver Sturm - E-Book

Functional Programming in C# E-Book

Oliver Sturm

0,0
20,99 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.
Mehr erfahren.
Beschreibung

Take advantage of the growing trend in functional programming. C# is the number-one language used by .NET developers and one of the most popular programming languages in the world. It has many built-in functional programming features, but most are complex and little understood. With the shift to functional programming increasing at a rapid pace, you need to know how to leverage your existing skills to take advantage of this trend. Functional Programming in C# leads you along a path that begins with the historic value of functional ideas. Inside, C# MVP and functional programming expert Oliver Sturm explains the details of relevant language features in C# and describes theory and practice of using functional techniques in C#, including currying, partial application, composition, memoization, and monads. Next, he provides practical and versatile examples, which combine approaches to solve problems in several different areas, including complex scenarios like concurrency and high-performance calculation frameworks as well as simpler use cases like Web Services and business logic implementation. * Shows how C# developers can leverage their existing skills to take advantage of functional programming * Uses very little math theory and instead focuses on providing solutions to real development problems with functional programming methods, unlike traditional functional programming titles * Includes examples ranging from simple cases to more complex scenarios Let Functional Programming in C# show you how to get in front of the shift toward functional programming.

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 451

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



CONTENTS

Introduction

Part I : Introduction to Functional Programming

Chapter 1 : A Look at Functional Programming History

What Is Functional Programming?

Functional Languages

The Relationship to Object Oriented Programming

Summary

Chapter 2 : Putting Functional Programming into a Modern Context

Managing Side Effects

Agile Programming Methodologies

Declarative Programming

Functional Programming Is a Mindset

Is Functional Programming in C# a Good Idea?

Summary

Part II : C# FOUNDATIONS OF FUNCTIONAL PROGRAMMING

Chapter 3 : Functions, Delegates, and Lambda Expressions

Functions and Methods

Reusing Functions

Anonymous Functions and Lambda Expressions

Extension Methods

Referential Transparency

Summary

Chapter 4 : Flexible Typing with Generics

Generic Functions

Generic Classes

Constraining Types

Other Generic Types

Covariance and Contravariance

Summary

Chapter 5 : Lazy Listing with Iterators

The Meaning of Laziness

Enumerating Things with .NET

Implementing Iterator Functions

Chaining Iterators

Summary

Chapter 6 : Encapsulating Data in Closures

Constructing Functions Dynamically

The Problem with Scope

How Closures Work

Summary

Chapter 7 : Code Is Data

Expression Trees in .NET

Analyzing Expressions

Generating Expressions

.NET 4.0 Specifics

Summary

Part III : Implementing Well-known Functional Techniques in C#

Chapter 8 : Currying and Partial Application

Decoupling Parameters

Calling Parts of Functions

Why Parameter Order Matters

Summary

Chapter 9 : Lazy Evaluation

What’s Good about Being Lazy?

Passing Functions

Explicit Lazy Evaluation

Comparing the Lazy Evaluation Techniques

How Lazy Can You Be?

Summary

Chapter 10 : Caching Techniques

The Need to Remember

Precomputation

Memoization

Summary

Chapter 11 : Calling Yourself

Recursion in C#

Tail Recursion

Accumulator Passing Style

Continuation Passing Style

Indirect Recursion

Summary

Chapter 12 : Standard Higher Order Functions

Applying Operations: Map

Map, Filter, and Fold in LINQ

Standard Higher Order Functions

Summary

Chapter 13 : Sequences

Understanding List Comprehensions

A Functional Approach to Iterators

Ranges

Restrictions

Summary

Chapter 14 : Constructing Functions from Functions

Composing Functions

Advanced Partial Application

Combining Approaches

Summary

Chapter 15 : Optional Values

The Meaning of Nothing

Implementing Option(al) Values

Summary

Chapter 16 : Keeping Data from Changing

Change Is Good — not!

False Assumptions

Implementing Immutable Container Data Structures

Alternatives to Persistent Data Types

Summary

Chapter 17 : Monads

What’s in a Typeclass?

What’s in a Monad?

Why Do a Whole Abstraction?

A Second Monad: Logging

Syntactic Sugar

Binding with SelectMany?

Summary

Part IV : Putting Functional Programming into Action

Chapter 18 : Integrating Functional Programming Approaches

Refactoring

Writing New Code

Finding Likely Candidates for Functional Programming

Summary

Chapter 19 : The MapReduce Pattern

Implementing MapReduce

Abstracting the Problem

Summary

Chapter 20 : Applied Functional Modularization

Executing SQL Code from an Application

Rewriting the Function with Partial Application and Precomputation in Mind

Summary

Chapter 21 : Existing Projects Using Functional Techniques

The .NET Framework

LINQ

Google MapReduce and Its Implementations

NUnit

Summary

Index

Professional Functional Programming in C#: Classic Programming Techniques for Modern Projects

This edition first published 2011

©2011 John Wiley & Sons, Ltd

Registered office

John Wiley & Sons Ltd, The Atrium, Southern Gate, Chichester, West Sussex, PO19 8SQ, United Kingdom

For details of our global editorial offices, for customer services and for information about how to apply for permission to reuse the copyright material in this book please see our website at www.wiley.com.

The right of the author to be identified as the author of this work has been asserted in accordance with the Copyright, Designs and Patents Act 1988.

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, photocopying, recording or otherwise, except as permitted by the UK Copyright, Designs and Patents Act 1988, without the prior permission of the publisher.

Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books.

Designations used by companies to distinguish their products are often claimed as trademarks. All brand names and product names used in this book are trade names, service marks, trademarks or registered trademarks of their respective owners. The publisher is not associated with any product or vendor mentioned in this book. This publication is designed to provide accurate and authoritative information in regard to the subject matter covered. It is sold on the understanding that the publisher is not engaged in rendering professional services. If professional advice or other expert assistance is required, the services of a competent professional should be sought.

978-0-470-74458-1

978-0-470-97028-7 (ebk)

978-0-470-97110-9 (ebk)

978-0-470-97109-3 (ebk)

A catalogue record for this book is available from the British Library.

ABOUT THE AUTHOR

OLIVER STURM has over 20 years experience developing professional software. He is a well-known expert in various areas of application architecture, programming languages and the third party .NET tools made by DevExpress. His main focus has been on the .NET platform since 2002. Oliver has spoken at many international conferences and has written more than 20 training classes and more than 100 magazine articles in English as well as German. He has also taught classes on topics around computer programming for more than 15 years. For his contributions to the .NET community, he has been awarded the C# MVP Award by Microsoft United Kingdom for several years now.

Based in Scotland, UK, Oliver works as a freelance consultant and trainer, and he is an associate at thinktecture, an international consultancy firm. You can find his blog at www.sturmnet.org/blog and his commercial website at www.oliversturm.com. His e-mail address is [email protected].

CREDITS

VP CONSUMER AND TECHNOLOGY PUBLISHING DIRECTOR

Michelle Leete

ASSOCIATE DIRECTOR—BOOK CONTENT MANAGEMENT

Martin Tribe

ASSOCIATE PUBLISHER

Chris Webb

PUBLISHING ASSISTANT

Ellie Scott

ASSOCIATE MARKETING DIRECTOR

Louise Breinholt

MARKETING EXECUTIVE

Kate Parrett

EDITORIAL MANAGER

Jodi Jensen

SENIOR PROJECT EDITOR

Sara Shlaer

PROJECT EDITOR

Brian Herrmann

TECHNICAL EDITORS

Michael Giagnocavo

Matthew Podwysocki

SENIOR PRODUCTION EDITOR

Debra Banninger

COPY EDITOR

Maryann Steinhart

PROOFREADER

Sheilah Ledwidge, Word One

INDEXER

Robert Swanson

COVER DESIGNER

Mike Trent

COVER IMAGE

© Oleg Kruglov/istockphoto.com

INTRODUCTION

FUNCTIONAL PROGRAMMING is an important paradigm of programming that looks back on a long history. The subject has always been very relevant to people who teach others how to program — the clean and logical concepts of functional programming lend themselves especially well to teaching. Certain industries that use computers and self-written programs heavily have also found functional programming to be the most productive approach for their purposes. However, for many of the “mainstream” software manufacturers, functional programming has long held an air of the academic and they widely chose to use approaches with an imperative heritage, like object orientation.

In recent years, more and more functional elements have been included in imperative languages on the .NET platform, and with Visual Studio 2010, F# has been included — the first hybrid functional language in the box with Microsoft’s mainstream development platform. Even more than the functional features that have been introduced to C# and VB.NET, this shows a commitment on Microsoft’s side.

WHO THIS BOOK IS FOR

The topic of functional programming in C# can be seen from two different angles. On the .NET platform there are many experienced developers and development teams, who have been using C# or VB.NET, or in some cases C++, to create software for the platform. If you have that sort of experience, there are lots of reasons you should be looking into functional programming: it’s a clean and easily maintainable style, it’s an important basis of programming as we know it today, and certain specific current concerns, like parallelization, can be targeted successfully with the help of functional programming ideas.

On the other hand, perhaps you’re not a .NET programmer at all. Instead, you have experience in one or more “traditional” functional programming languages. You need to work with people who use C#, or you want to use the language yourself. This book will help you understand how you can use the approaches you’re familiar with in C#, and it may give you valuable starting points when it comes to explaining these ideas to team members without your functional background.

The book assumes a basic level of understanding of C# language constructs, at least up to version 3.0 of the language. However, Part II is written to explain a few particular features of the language that are especially important, rather complex or often misunderstood. From experience, I recommend you give Part II a good look even if you’re quite fluent in C# — there are usually some little-known intricacies about the features that have been selected for this part, which may lead to misunderstandings later.

WHAT THIS BOOK COVERS

The language of the vast majority of examples in this book is C# 4.0, running on Microsoft .NET. There are a few examples in other languages, but they are for illustrative purposes only. If you want to try out the examples for yourself, but you’re not on C# 4.0 or Visual Studio 2010 yet, you may still have success using C# 3.0 and Visual Studio 2008 — there aren’t many new features in C# 4.0 specifically, and none of them have been exploited in the examples. However, a few examples utilize .NET Framework features like Parallel Extensions, which are available only in .NET 4.0.

The book introduces you to concepts of functional programming and describes how these can be used with the C# language. An effort has been made to provide samples with a practical background, but most of them still focus mostly on language level considerations. Functional programming is a technique for code, algorithm and program structure — as opposed to, for instance, application architecture. Of course it needs to fit in with application architecture . . . you get the point: it’s sometimes hard to find the perfect compromise between being too theoretical and going off-focus, but I’ve tried my best.

While I wrote this book, I developed a library of functionally oriented helpers, called FCSlib (that’s “Functional CSharp Library”). You can use this library in your own projects as you like, but please note that it doesn’t come with any warranty. The downloadable file containing the library code (more information about downloads in the upcoming section “Source Code”) includes a copy of the LGPL license text, which applies to the FCSlib code.

HOW THIS BOOK IS STRUCTURED

This book has four parts. The first part provides an overview of functional programming, both from a historical and a current point of view. Part II proceeds to give you the C# background you’ll need to understand the more complex examples that follow later. Again, reading this is recommended even if you know C# — it does have a few pretty basic items, but generally it’s not meant to be a language introduction for newbies.

Part III is the most important one. Its 10 chapters describe a variety of functional programming topics from a C# point of view, showing lots of examples and code snippets. The code library that accompanies this book, FCSlib, is built on the ideas described in this part.

Finally, Part IV gives you an overview of practical concerns of using functional programming in C#. I picked a few specific scenarios, and there are descriptions of functional programming ideas in existing products and technologies that you may be familiar with.

WHAT YOU NEED TO USE THIS BOOK

All code in this book has been tested with Visual Studio 2010, C# 4.0 and .NET 4.0. Much of it has been originally developed on C# 3.0, so you should have good success running the code on .NET 3.5. Going back further than that would mean major rewrites in many areas — the concepts may translate even to C# 2.0 in many cases, but the language features that make them reasonably easy to use are just not available in that version.

I have made several attempts to build the code on the Mono platform, but unfortunately I stumbled upon compiler bugs every time. Your mileage may vary if you try to use Mono — after all, it changes all the time.

CONVENTIONS

To help you get the most from the text and keep track of what’s happening, we’ve used a number of conventions throughout the book.

The pencil icon indicates notes, tips, hints, tricks, and asides to the current discussion.

As for styles in the text:

We italicize new terms and important words when we introduce them.We show keyboard strokes like this: Ctrl+A.We show file names, URLs, and code within the text like so: persistence.properties.We present code in two different ways:

We use a monofont type with no highlighting for most code examples.

We use bold to emphasize code that is particularly important in the present context or to show changes from a previous code snippet.

SOURCE CODE

As you work through the examples in this book, you may choose either to type in all the code manually, or to use the source code files that accompany the book. All the source code used in this book is available for download at www.wrox.com. When at the site, simply locate the book’s title (use the Search box or one of the title lists) and click the Download Code link on the book’s detail page to obtain all the source code for the book. Code that is included on the website is highlighted by the following icon:

Listings include the filename in the title. If it is just a code snippet, you’ll find the filename in a code note such as this:

Code snippet filename

Because many books have similar titles, you may find it easiest to search by ISBN; this book’s ISBN is 978-0-470-74458-1.

Once you download the code, just decompress it with your favorite compression tool. Alternately, you can go to the main Wrox code download page at www.wrox.com/dynamic/books/download.aspx to see the code available for this book and all other Wrox books.

ERRATA

We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books, like a spelling mistake or faulty piece of code, we would be very grateful for your feedback. By sending in errata, you may save another reader hours of frustration, and at the same time, you will be helping us provide even higher quality information.

To find the errata page for this book, go to www.wrox.com and locate the title using the Search box or one of the title lists. Then, on the book details page, click the Book Errata link. On this page, you can view all errata that has been submitted for this book and posted by Wrox editors. A complete book list, including links to each book’s errata, is also available at www.wrox.com/misc-pages/booklist.shtml.

If you don’t spot “your” error on the Book Errata page, go to www.wrox.com/contact/techsupport.shtml and complete the form there to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fix the problem in subsequent editions of the book.

P2P.WROX.COM

For author and peer discussion, join the P2P forums at p2p.wrox.com. The forums are a Web-based system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e-mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums.

At p2p.wrox.com, you will find a number of different forums that will help you, not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:

1. Go to p2p.wrox.com and click the Register link.

2. Read the terms of use and click Agree.

3. Complete the required information to join, as well as any optional information you wish to provide, and click Submit.

4. You will receive an e-mail with information describing how to verify your account and complete the joining process.

You can read messages in the forums without joining P2P, but in order to post your own messages, you must join.

Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the Web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to this Forum icon by the forum name in the forum listing.

For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works, as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.

PART I

Introduction to Functional Programming

CHAPTER 1: A Look at Functional Programming History

CHAPTER 2: Putting Functional Programming into a Modern Context

Chapter 2

Putting Functional Programming into a Modern Context

WHAT’S IN THIS CHAPTER?

Managing side effectsAgile programming methodologiesDeclarative programmingFunctional programming as a mindsetThe feasibility of functional programming in C#

There have always been groups of programmers more interested in functional programming than in other schools of programming, and certain niches of the industry have provided a platform for those well versed in functional approaches and the underlying theory. At the same time, however, the mainstream of business application programming — the bread and butter of most programmers on platforms made by Microsoft and others — has evolved in a different direction. Object orientation and other forms of imperative programming have become the most widely used paradigms in this space of programming, to the extent that programmers have been neglecting other schools of thought more and more. For many, the realization that solutions to certain problems can be found by looking back to something “old” is initially a surprise.

One of the main reasons programmers become interested in functional programming today is the need for concurrency programming models. This need, in turn, comes from the evolution of the hardware toward multicore and multiprocessor setups. Programs no longer benefit very much from advances in technology like they did when increases in MHz were a main measurable reference point. Instead, programs need to be parallelized to take advantage of more than one CPU, or CPU core, available in a machine. Programmers are finding that parallelization is no longer a mere luxury, but rather a requirement if they don’t want to see their codebase, their architecture, and their algorithms left behind gradually.

One area of the parallelization problem is increasingly being covered by standard tools of the platform, and that’s the technical side of dealing with parallelization. For a long time, programmers had to work with the underlying structures of the Windows operating system itself: processes and threads, mainly. This was true even for the managed .NET environment. In 2010, Microsoft released a new library called the Parallel Extensions to the .NET Framework, formerly identified as Parallel FX or just PFX. This library, packaged with .NET 4.0, revolutionizes the technical side of concurrency programming for the .NET programmer, providing task objects instead of threads, which are coordinated intelligently by the framework. It also allows for some advanced interaction between these units so that certain problems are now much easier to solve — no need to write your own scheduler to control the number of parallel execution units, no complex structures to retrieve results from background processes, and so on.

Unfortunately there’s still a structural problem because an application that has been written in a normal imperative style, based on the sharing and changing of state information, is often not easy to parallelize due to all the data exchange/shared access challenges. Imperative and object oriented programming almost make it a rule to store data in places where it can be accessed (for reads as well as writes) by more than just a single method or function. While the Parallel Extensions library provides handy utility functions to replace standard single-threaded ones readily, the functions are not that easy to use in reality because the rest of the code hasn’t been written with parallelization in mind. For instance, there is a Parallel.ForEach function that does vaguely the same thing as the standard C# foreach statement except it parallelizes its execution — but this will only work if the code that is in the loop has been structured so that there are no data access collisions.

MANAGING SIDE EFFECTS

In spite of the help provided by libraries such as Parallel Extensions, you still need to do a lot of potentially complex structural work on your codebase in order to parallelize it. In functional programming, the kind of data access where multiple methods or functions in a program have shared access to the same data — most importantly write access to that data — is called a side effect. One of the main ideas of functional programming is to manage such side effects. This may mean to prevent them, and it is certainly a target to reduce these side effects to begin with, because that makes the remaining ones easier to manage. It is an illusion, however, that a computer program could do anything useful without having side effects in the technical sense — whenever something is seen on screen, data is stored in a file or a database, or something is sent over a network, that is, on some level, a side effect.

The imperative reaction to the problem of shared data access is typically to impose restrictions, with the technical term being synchronization. This is often summarized as mutual exclusion, which describes the idea very well: while one execution thread accesses a particular piece of information to make a change, others can’t do so at the same time. It’s a simple and efficient concept, but quite hard to get right. As soon as there are many pieces of information, as there are bound to be in imperative applications, the individual critical sections tend to overlap and nest, and it becomes difficult to keep track of all the possible interaction scenarios, resulting in all sorts of locking issues. There are other solutions to many of these, such as specialized lock types or other synchronization structures like queues or flags.

In functional programming, programmers have learned to deal with the management of side effects in a different way because the structure and background of their languages required this to a higher degree. It would be wrong to say that functional programming has all the answers to the parallelization problems, but there’s definitely a large pool of knowledge there on the topic of programming without side effects, which in turn means easy parallelization. Taking those strategies into account is what makes functional programming interesting to so many these days, whether or not their languages were meant to be functional by their inventors. Parts of this book describe the application of functional techniques specifically with parallelization in mind.

AGILE PROGRAMMING METHODOLOGIES

After parallelization, a second interesting consideration is that of functional modularization — that is, modularization on the level of individual functions. In object oriented languages, there are typically classes and methods within classes. There are languages that allow the nesting of methods, but many do not — in C#, for instance, methods can’t be nested. But the use of anonymous methods and lambda expressions allow the creation of functions that are local to methods, which opens the door to modularization on the algorithm level.

This notion fits in very well with the application of modern software development methodologies like Agile. One of the main ideas in this space is an evolutionary approach in which programmers work along simple requirement specifications and, in a nutshell, do only what’s necessary in each step to satisfy these requirements. Refactoring becomes an important part of the concept, and modularization, with the implied reuse resulting from it, can be very useful as a technique on a method or function level when the introduction of new methods on the class level seems like too large a step to take. Just like in the area of techniques for parallelization, functional programming doesn’t offer a magical solution here, but there’s a lot to learn from functional techniques that have employed functions as reusable building blocks for a long time.

DECLARATIVE PROGRAMMING

Functional programming is generally regarded as a style of declarative programming. The target of declarative programming is to specify the goal, the logic of what a program, or a part of a program, should do, without describing the steps necessary to achieve that goal. In other words, it is about leaving choices to the computer when it comes to the details of executing a program, instead of requiring the programmer to specify these. Many types of declarative programming have been accepted into the mainstream over the years.

Domain-specific languages are one example. HTML, XML, and XAML can be regarded as languages that describe documents and data as well as execution instructions. Regular expressions describe complex input and their engines effectively parse and manipulate data. Querying languages such as SQL and the in-code querying functionality of LINQ are variations of declarative programming, as are the code contracts available in .NET 4.0. Functional programming is a less specific type of declarative programming, compared to these examples, but it is still just an extension of ideas that are already quite common today.

FUNCTIONAL PROGRAMMING IS A MINDSET

In the end, functional programming is a mindset. If you are willing to think in a certain way, it can offer you interesting solutions or at least food for thought, with a relevance to many practical aspects of programming today. You can do it in any programming language you want — well, almost. It should make your life easier and reduce the amount of code you need to write as well as the time to market for your next project and the maintenance efforts that come later.

Something that’s sometimes criticized about functional programming is the fact that the approaches are not bound to the most performative ones you could use to solve any given problem. This may or may not be true for any given algorithm–language combination — it is, of course, hard to make a general statement about this. It’s also difficult to judge given that an application of functional principles may enable you to utilize the processing resources provided by your machine more efficiently. The reality is that if a qualified person sat down and optimized each algorithm by hand, on a low level, using C code or assembler instructions, then he could certainly make everything run more efficiently. But at some point in the past the majority of programmers started moving away from such approaches and using higher level languages for most of the programming work they needed to do. They started looking at the time to market, the programmer’s efficiency, as a higher priority than the creation of the perfect algorithm from a machine utilization point of view.

Of course these steps were made gradually. Perhaps somebody went from C to C++ first, assuming that the compiler would be almost as efficient for C++ as it was for C. Maybe they moved on to Java or .NET at some later point in time, where a virtual machine is the platform to program against, and just-in-time (JIT) compilers do the — hopefully efficient — job of translating to the native CPU code. The world gets more complicated then because while there’s a potential performance loss in the additional translation work required, new possibilities are created at the same time, including those to translate an intermediate code binary file intelligently toward the precise processor and machine architecture used at runtime and applying any number of clever optimizations in the process.

Any kind of declarative programming is a logical next step in that sequence. You gain efficiency because the declarative languages allow you to specify the problems you’re trying to solve, and the computer can help more with the solutions than it’s allowed to in purely imperative programming scenarios. The quality of that help is eventually what decides the performance of the final result. But in today’s complex world of hardware, multicore CPUs in machines and even on graphics cards, and different versions and architectures of CPUs with many important distinctions, it isn’t hard to imagine that in the vast majority of cases a computer will make better choices — and much more quickly and efficiently than humans. For those edge cases where statistics fail, and for those perfectionists and control freaks among us, there’s still the possibility of interfacing with code written directly in a low-level language.

The first priority today is to program efficiently. The second priority, however closely it may follow, is to write efficient programs.

IS FUNCTIONAL PROGRAMMING IN C# A GOOD IDEA?

When all you have is a hammer, everything looks like a nail. Should programming languages be seen as general problem solving devices that can be applied to any problem and, as a consequence, to any solution strategy? Or should they be viewed as tools that are good for particular tasks, and less good or even useless for others? Practical understanding of different programming languages, the driving factors that define their priorities, and the consequences of the design decisions seems to point quite clearly toward the “tool” understanding of programming languages. Functional programming is a good example to document this statement. Let’s face it: if you want to write some purely functional code, you’ll have a much easier time doing it with the help of a purely functional language — that is, one that has been created with the precise techniques in mind that you are going to employ. No surprise there, really.

In reality, it’s all about finding the best compromise. It is certainly a goal to strive for to understanding the specialties of different languages and to be able to make informed decisions about their applicability to a particular problem situation. But in most real-world projects, there are limits to the number of such choices you can reasonably make. Other programmers involved may not be familiar with the same subset of tools that you know. It pays in the long term to have some consistency across projects, because it keeps down maintenance effort. It also makes it easier to hire new people to support existing code bases. At the same time, programmers who restrict themselves to just one language will often miss important opportunities offered elsewhere. And they will never be seen by their bosses or clients as the final point of reference in what should be their area of expertise.

Knowing the pros and cons of using particular tools and approaches is important. You can have any number of reasons for a decision to make a move or to stay where you are, but if you find that a choice is right in front you and you aren’t thinking about a decision, you are probably missing out.

SUMMARY

Picking up functional programming while staying with C# as a language is a strategy that should be based on practical considerations. This book is not telling you that C# can do everything functional just as easily as LISP, or Haskell, or even F# on the same .NET platform. It can’t. Yes, you can do most things, but they are harder, more syntactically complex, and perhaps even more difficult to understand as a consequence. This book shows you how it works, what you can and cannot do, and where the limits are.

If you are a C# programmer and you have reasons why the adoption of a different or an additional programming language is not an option for yourself or your team, this book is for you. If you want to learn about functional programming on the basis of a language you’re already familiar with, this book is for you. And if you know functional programming and you’re wondering how you can go about explaining it to your imperative programmer friends, this book is also for you.

Does it make sense to program functionally in C#? Yes, for all sorts of reasons, it does. Read on.

PART II

C# Foundations of Functional Programming

CHAPTER 3: Functions, Delegates, and Lambda Expressions

CHAPTER 4: Flexible Typing with Generics

CHAPTER 5: Lazy Listing with Iterators

CHAPTER 6: Encapsulating Data in Closures

CHAPTER 7: Code Is Data

Chapter 3

Functions, Delegates, and Lambda Expressions

WHAT’S IN THIS CHAPTER?

Functions and methodsConsiderations for reuseAnonymous functions and lambda expressionsExtension methodsReferential transparency

Almost all programming languages have a means of defining blocks of code and of declaring certain execution sequences as belonging together, usually for the purpose of reusability as well as for structural and maintenance reasons. The details of these mechanisms vary considerably between languages.

FUNCTIONS AND METHODS

C# is an object oriented language. Not just that, it’s a comparatively pure object oriented language. The degree of object orientation can’t really be measured, but different programming languages adhere to the ideas of certain programming philosophies to a certain extent, and rarely do they go all the way. In this case the interesting point is that C# doesn’t allow any functions outside of classes. This is a big difference compared to C++ — the first object oriented programming language for many “mainstream” programmers — which allows functions to live outside of classes, mainly for backward compatibility with C code. It can be argued that since C# supports classes with static members, and even fully static classes are supported since version 3.0, imperative code is simply hidden behind object oriented terminology as needed. However, looking at the understanding of C# evident with the majority of programmers, the C# design team succeeded in creating a perception of an almost purely object oriented language.

Because functions in C# can only exist within classes, they are typically called methods. Methods can accept a number of parameters, and they can have a return value. Some people might argue that they always have a return value, but the return value can be of type void, which basically means that the method doesn’t return anything. Just in case you haven’t ever seen a C# method before, here’s one:

class MyClass {

  int Square(int x) {

    return x * x;

  }

}

There are a few common elements missing from this simple class (accessibility specifiers for one thing), but there are also a few things in there that might not be entirely intuitive if you haven’t used C# before. Unfortunately, this book isn’t a general C# introduction. These introductory chapters point out and explain those C# features that are important in the following parts of the book. If you need a general introduction to the language, or to object oriented programming (although the latter isn’t very important in the rest of the book), you should probably start with a different book, such as Beginning C# 3.0: An Introduction to Object Oriented Programming (Wrox, ISBN 978-0-470-26129-3).

As is the case in many object oriented languages, methods in C# classes can be instance or class methods. Instances are created from classes, which goes a long way to explaining the difference. There can be many instances of the same class, and a class method works on the level of the class, while an instance method works on the level of the instance. That is a bit abstract until you start thinking about other types of members a class can have, such as variables and fields. Variables store information, and they also live either on the class level or on the instance level. A class field exists once per class (so that’s exactly once, from the point of view of any given application) and an instance field exists once per instance. Class methods can access information in class fields only, whereas instance methods can access information in the instance fields of their own instance. Instance methods can also access class fields, and if they have references to other instances, they can also access instance fields in those other instances. Enough of that — again, those are basics of the C# language and of object oriented programming.

Here’s why this is interesting for functional programming: in pure functional programming, there are no classes or instances of classes — there are of course techniques for the storage of data, but they aren’t usually called classes and they tend to work differently in many ways. Where all other elements live inside classes and objects (“object” is another word for “instance of a class,” by the way) in object oriented environments, all other elements live inside functions in functional programming. There may be data that is local to the function, like variables declared in a method in C#, but there isn’t the idea of data, especially data that can be modified during runtime, being anywhere outside the scope of functions. The typical C# instance method, which can access information outside its own scope, is not a function that fits in with the concept of functions that functional programming has.

Nevertheless, functional programming is possible on the basis of the object oriented .NET platform, both using languages that have special support for it and those that don’t have such support. F# uses class-level members for global members, and due to the special syntax support, the programmer isn’t confronted with the fact that there is a “translation” taking place. Unfortunately it isn’t possible to make C# do this automatically, but the solution remains the same. To simulate functions on a global level (or in any other scope), create them as class-level members inside classes. These members use the keyword static. Because they are encapsulated in classes, members can have varying visibility. Most functional environments have encapsulation levels — in modules or namespaces, for example — so apart from slightly more complex syntax in C#, there’s really no significant difference.

Some functional languages have top-level functions or allow modules or namespaces to be imported so that a qualification of a function call is no longer required. Here’s an example:

DoSomething "string parameter"

In C#, such a call always needs a qualifying class name, unless the function lives in the same class where the call is being written:

SomeClass.DoSomething("string parameter");

REUSING FUNCTIONS

Reuse is the greatest overall problem in computer programming. The assembly languages understood by processors are fine for the purpose of programming computers to do anything and everything you want — there’s nothing that can’t be done on this level. The problem is that after a very short time, small and large blocks of functionality start recurring, and programmers start trying to find ways to avoid wasting time by re-implementing code that’s already been written. If you think about it, that’s why functions in programming languages were invented in the first place: because they provide a common place for a block of code, a piece of functionality, that will presumably be used more than once.

Of course functions are not the end of the line when it comes to reusability. Especially in object oriented programming, the step beyond functions is made very quickly. Classes are used as building blocks together with interfaces and even larger modules. There are some mechanisms that work on the function level and promote reuse, and object oriented programmers have invented a slew of patterns to go along with these, many of which also work on the function level.

As a built-in language feature, C# only supports overloading of functions as a direct means of modularization on a functional level. C# 4.0 has both named and optional parameters so that the overload resolution process becomes quite complex, especially when taking other related mechanisms like inference of generic types for method calls into account. But these elaborate details are not the subject now, so here’s just a short, simple example of an overloaded method:

int Add(int x, int y) {

  return x + y;

}

 

int Add(int x, int y, int z) {

  return Add(x, y) + z;

}

 

double Add(double x, double y) {

  return x + y;

}

 

double Add(double x, double y, double z) {

  return Add(x, y) + z;

}