Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Delegates and anonymous inner classes are equivalent, modulo API:

    //Java
    
    Bax.addHandler(new Foo()
                   {
                       @Override
                       public void Bar()
                       {
                           doSomething();
                       }

                       @Override
                       public int Baz(X n)
                       {
                            return computeInt(n);
                       }

                   });
    
    //C#

    Bax.AddHandler(() => DoSomething(), n => ComputeInt(n));

But, anonymous delegates and lambdas are at once syntactically nicer and more powerful, because of type inference and the fact that they can capture local variables.

Regarding Java enums, the actual equivalent feature in C# is class nesting. There is a tiny bit more ceremony involved in defining them, but they're more flexible than Java enums. For instance, you can decide whether or not to implement them as readonly (final) fields, or as static properties, depending on how much you care about cache friendliness.

    public abstract partial class SomeEnum
    {
         private SomeEnum(){}

         public abstract int Biz();

         sealed class AFoo : SomeEnum { public override Biz() => 2 }
         sealed class ABar : SomeEnum { public override Biz() => 4 }         
         sealed class ABaz : SomeEnum { public override Biz() => 8 }         
  
    }

    //Singleton implementation:

    public abstract partial class SomeEnum
    {
        public static readonly SomeEnum Foo = new AFoo();
        public static readonly SomeEnum Bar = new ABar();
        public static readonly SomeEnum Baz = new ABaz();
    }  

    //Cache friendly implementation:

    public abstract partial class SomeEnum
    {
        public SomeEnum Foo => new AFoo();
        public SomeEnum Bar => new ABar();
        public SomeEnum Baz => new ABaz();
    }     
It's also worth noting that extension methods on C# enums give you most (all?) of the power of Java enums.


That is only equivalent within the boundaries of your API (i.e. when you use them as pure callbacks). But your delegates are two different objects, while in the Java example, it's a single object. This makes a difference if, for example, object identity matters.

From practical purpose, Java anonymous classes can be used in any scenario where you need to create a one-off object that derives from a class or implements one interface. A delegate can only be used in a scenario where the receiving variable or function wants a function type.

I'm not arguing that delegates are lambdas are bad, mind you. For the common scenario involving callbacks, they're vastly superior. But they're not a complete replacement for Java inner classes.


Yes, but we can recover all of the power of anonymous inner classes by building up a (usually small) set of "ad-hoc" classes that just wrap delegates, as I explain here: https://stackoverflow.com/questions/20703002/does-object-exp...

By the way, thanks for your work on PTVS, I just discovered it recently.


But they aren't really anonymous then, since you have to write a wrapper class for every class or interface that you intend to implement inline.

By the way, I totally forgot about F# object expressions! But they're a good example of this feature. Better than in Java, in fact, because they let you implement multiple interfaces. Also, IIRC, they're true closures (whereas Java only lets you close over finals, not writable locals).

Ideally, you'd have both those and lambdas in a language, like C# and Scala do. If I had to choose, though, I'd definitely pick lambdas - that is the 90% use case.


Brevity is the feature, not anonymity. What C# actually lacks is syntax sugar. But, a few years ago, I spent an hour or so implementing `Ad-hoc` classes for most of the interfaces and abstract classes that I thought I would ever need, and it's been sufficient over 90% of the time[1]. N.b. these classes could have been generated programmatically.

I'm not claiming that the technique is exactly equal to what Java gives you out of the box, but rather that C# can get within epsilon. In other words, for my purposes, the prefix AdHoc- might as well be a keyword (as in AdHocIEquality<T>, AdHocIEnumerable<T>†, AdHocDisposable, AdHocHttpHandler, etc...), because it's indistinguishable from syntax sugar.

On the other hand, the F# object expression really is more than just syntax sugar, because of the way it interacts with type inference (no need to upcast to satisfy the type checker), and (as you noted) that it can implement an arbitrary set of interfaces. But, it's not all carrots and apples: F# lambdas don't work well with protected members. Meanwhile, C# can close over just about anything (a ref local, such as Span<T>, being the obvious exception).

[1] https://github.com/noblethrasher/AdHoc-Implementations/blob/... (in a newer version, I implement the interfaces explicitly)

† which, really only works well in VB because lambdas can contain `Yield` statements.


Side note: in C# 7.0, local functions (which, while not anonymous, are true closures) can contain "yield".


On your delegates example for C#, since the parameters of the lambda and methods match, and you aren't relying on any closure behaviour, you can use 'method group syntax' to make it even more succinct:

  Bax.AddHandler(DoSomething, ComputeInt);




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: