What is the difference between delegates in C# and functions as first class values in F#?
Asked Answered
G

2

28

More specifically what are the characteristics (if any) that delegates have that functions as first class values in F# don't have; and what are the characteristics that functions as first class values have (if any) that delegates in C# don't have?

Germanize answered 9/10, 2010 at 19:24 Comment(1)
@delnan, not sure why you think delegates were bolted on to C#; Anders et al included them in the language design from the beginning. In fact, he had included them in J++, which he worked on before C#. As for delegates being an ugly implementation, that is subjective and hence uninformative. For reference, see artima.com/intv/simplexity.htmlExpurgatory
K
31

Delegates and F# "First class function values" are quite different.

Delegates are a mechanism of the CLR, a type-safe wrapper around function-pointer+object pairs (for instance methods, the this-pointer gets captured together with the method address).

F# function values on the other hand, are implementation of an abstract class FSharpFunc<,> (it used to be called FastFunc<,> before the official release of F#). Invocation happens via ordinary virtual methods, which is much faster than delegate invocation. That is the reason the F#-team didn't use delegates in the first place.

So if you can "implement" functions as first class values via abstract classes/virtual methods, why did Microsoft add delegates?

  • There was no alternative In .NET 1.0/1.1, there were no generics, so you had to define a new delegate type (="function type") for every function signature you wanted to use.
  • (No, just using interfaces like in Java doesn't count. :-P )

Ok, but we have Generics since .NET 2.0, why do we still have delegates? Why can't we just use Func<,> and Action<> for everything?

  • Backwards compatibility
  • Multicast Delegates Delegates can be chained together to form new delegates. This mechanism is used to implement events in VB.NET and C#. Behind the scenes, an event is really just a single delegate field. Using the += syntax you essentially add your event-handler-delegate to the chain of delegates in the event field.

Apart from events, is there a reason to use delegates over FSharpFunc<,>

Yes, one: Each and every implementation of FSharpFunc<,>, that includes lambda-expressions*, is a new class. And in .NET classes are encoded in the metadata of the compiled assembly. Delegates on the other hand require no extra metadata. The delegate types do but instantiating these delegate types is free in terms of metadata.

But wait, aren't C# lambda-expressions/anonymous methods too implemented as hidden classes?

Yes, C# lambdas take the worst of both worlds ^^

Kashgar answered 9/10, 2010 at 20:2 Comment(7)
"C# lambdas take the worst of both worlds": what a pessimistic way to put it... but I see your point ;)Pinfeather
Am I to infer from your answer that functions as first class values in F# only advantage over delegates is speed? Is there nothing in functions as first class values that introduces a paradigm shift in the way I write my programs?Germanize
In C# 3.0 now it's pretty close. In 2.0, delegates were so cumbersome to author (very heavy syntax) that you'd rarely use them. And F# type inference helps too. That is, the point I'm trying to make is "a preponderance of syntax sugar" leads to paradigm-shifting. See #196794 as evidence of this.Remake
Exactly, C# is already a very functional language. What's still missing, though, is proper pattern matching. And then maybe better support for writing immutable immutable classes.Kashgar
@SealedSun: Can't really call C# a FP language until it supports proper higher-level function manipulation (composition, etc) in a generalised fashion. Much as I love pattern-matching and easy immutability, they're not--strictly speaking--key to FP.Glob
@Glob Things like function composition, const and flip are just library functions. They are part of .NET 4.0 in the form of the FSharp runtime library. But what's indeed missing is automatic currying and a nice syntax for partial.application.Kashgar
@SealedSun: function composition without partial application is awkward at best... kind of like tuples without pattern matching (I'm looking at you, Anders). ;-PGlob
K
7

I just wanted to add that this statement from SealedSun isn't true:

Invocation happens via ordinary virtual methods, which is much faster than delegate invocation. That is the reason the F#-team didn't use delegates in the first place.

F# functions are not faster then delegate invocation, maybe that was the case back in .NET 1.0, but now a days delegate invocation and invoking virtual methods are pretty much on-par.

Also invoking F# functions that can't be bound statically by the compiler is very slow compared to invoking a delegate.

open System
open System.Diagnostics

let time name f = 
  let sw = new Stopwatch()
  sw.Start()
  f()
  sw.Stop()
  printfn "%s: %dms" name sw.ElapsedMilliseconds

time "delegate call" (
  fun () ->
    let f = 
      new Func<int, int, int>(
        fun i1 i2 -> 
          let y = i1 + i2
          let x = y + i1
          let z = x + y + i2
          z + x + y + i1
      )

    let mutable r = 0
    for i = 0 to 10000000 do
      r <- f.Invoke(i, i)
)

let f i1 i2 = 
  let y = i1 + i2
  let x = y + i1
  let z = x + y + i2
  z + x + y + i1

time "fsharp func (static bound)" (
  fun () ->
    let mutable r = 0
    for i = 0 to 10000000 do
      r <- f i i
)

let make f =
  let mutable r = 0
  for i = 0 to 10000000 do
    r <- f i i

time "fsharp func (dynamic bound)" (
  fun () -> make f
)

Console.ReadLine() |> ignore

Produces the following results on my computer

delegate call: 65ms
fsharp func (staticly linked): 4ms
fsharp func (dynamic invoke): 356ms
Kostman answered 17/10, 2010 at 19:47 Comment(1)
I believe you are correct, at one point I had a link to an interview with one of the .Net team where this point (virtual vs delegate) was discussed. However it is not exactly to the point of my question, there seems to be a proliferation of programming languages and F# and 'funtional' programming are buzz words today. In picking functions-as-first-class-values I was trying to ask was is all this buzzing a philosophical shift worth investigating or mostly hype (or marketing) in a more objective fashion (so my question wouldn't get closed).Germanize

© 2022 - 2024 — McMap. All rights reserved.