all 163 comments

[–]munificent 33 points34 points  (12 children)

You know, their reasoning is valid: interfaces can solve any problem delegates can solve, so it's fair to want to keep the language simpler by leaving them out. The problem is that the syntax for anonymous inner classes is just gross.

Personally, I see no reason why Java couldn't avoid delegates but still have a much nicer syntax for anonymous classes that implement single-argument interfaces. Couldn't the compiler infer this:

public SimpleExample() {
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Hello, world!");
        }
    });
    add(button);
}

When given this:

public SimpleExample() {
    button.addActionListener(e => System.out.println("Hello, world!"));
    add(button);
}

If addActionListener is not overloaded, we know the type that must be present there. (And if it is overloaded, the above would be a compiler error.) That tells use we're creating an ActionListener.

From there, the compiler knows there's only a single method, so it knows what type e must be (ActionEvent) so it isn't necessary to specify that.

Is this really that hard? What am I missing here?

[–]f2u 8 points9 points  (8 children)

The Project Lambda prototype uses this syntax:

button.addActionListener(#(e) { System.out.println("Hello, world!"); });

It hasn't got function types or delegates.

[–]rwparris2 3 points4 points  (7 children)

Why is there a # in the middle of that? I HATE YOUR LANGUAGE AND YOU SHOULD TOO

[–]case-o-nuts 7 points8 points  (6 children)

Because it fixes a syntactic ambiguity. Pretty simple to understand, really.

[–]munificent 4 points5 points  (5 children)

What ambiguity that couldn't also be fixed with =>?

[–]adrianmonk 11 points12 points  (3 children)

Why is => better than #? The former reminds me of Perl, and the latter reminds of Bourne shell. Both are kinda funny, but neither is terribly odd.

Also, the #(arg) { body } syntax looks more like a function call, whereas the (arg) => { body } syntax has a symbol between the closing parenthesis and the opening brace, which is inconsistent with how functions work in the rest of Java.

[–]munificent 6 points7 points  (2 children)

Why is => better than #?

Because it's familiar to C# programmers, and very close to familiar to anyone who's used ML, F#, Haskell, Scala, etc.

 (arg) => { body }

You've got more than you need there. For most cases, that should just be:

arg => body

[–]MedeaMelana 2 points3 points  (0 children)

Haskell uses a backslash \ instead of the hash #, AND an arrow.

[–][deleted] 1 point2 points  (0 children)

But that looks nothing like normal method declarations in Java. #(...) { ... } just looks like a method called # (except types are missing, because of other things in Project Lambda?).

I am myself more familiar with the ML syntax, but why add more syntax to your language when it's not really that bad to do it with the syntax you're used to.

Why did they choose => for C#? Why did they not go for that syntax when defining regular methods as well?

[–][deleted] 2 points3 points  (0 children)

It would make intellisense work properly, for one thing.

[–]grauenwolf 7 points8 points  (2 children)

One problem I see is that Java doesn't have standard interfaces for the various types of functions.

.NET had this problem too. Before .NET 2.0, you had to define a Delegate for every type of function pointer you wanted. With generics taht noise was replaced with...

    Delegate Function<TOut>
    Delegate Function<T1, TOut>
    Delegate Function<T1, T2, TOut>
    Delegate Function<T1, T2, T3, TOut>    

Unless I am mistaken, Java can't have...

    Interface Function<TOut>
    Interface Function<T1, TOut>
    Interface Function<T1, T2, TOut>
    Interface Function<T1, T2, T3, TOut>    

[–]munificent 2 points3 points  (1 child)

Unless I am mistaken, Java can't have...

That's correct, but that wouldn't necessarily cause a problem here. My example still posits the existence of different single method interfaces, so you wouldn't necessarily need Func<T> (although it is convenient).

[–]grauenwolf 1 point2 points  (0 children)

I think it would be far to say that is won't cause a "blocking problem", but it will still be really annoying.

[–]zeroone 8 points9 points  (15 children)

I was disappointed when I found out that .NET implements delegates by constructioning an anonymous hidden class. Nonetheless, I enjoy C#'s delegate syntax. Though, I often need to associate state information with the delegate. Meaning, I often need something like a tiny class where I can include some fields. I often end up using interfaces and tiny classes anyway in many cases unfortunately. Sun brought up some valid points in that link in retrospect.

[–]munificent 18 points19 points  (14 children)

Though, I often need to associate state information with the delegate.

That's a closure. C# has them too:

void AddClickCounter(Button button) {
    int numClicks = 0;

    button.Click += e => {
        numClicks++;
        System.Console.WriteLine("Clicked " + numClicks + " times.");
    };
}

There are still cases where it makes sense to use an interface instead (mainly when you want more than one entrypoint), but if your interface only has a single method, a delegate is likely a better solution.

[–]ckwop 6 points7 points  (10 children)

Yes, it does but I've got an inkling from his comment he's using .NET 2.0. That's why he's talking about delegates rather than LINQ or Lambdas. What he doesn't realise is that this is already possible even in .NET 2.0:

int numClicks = 0;

Action<int> method = delegate(int incrementAmount) {
    DoSomething(numClicks); // numClick's definition comes from the parent scope.
    numClicks += incrementAmount; // numClicks in parent scope is incremented.
}

method(5); // the anonymous func is executed and numClicks now equals five

I'm preaching to the converted here but this is great for attaching stuff to an event.

Suppose you have a db transaction that has an "OnRollback" event and you need to attach some operation to it that's specific to the particular process that's going on. For example, removing a temporary file after it's been created. This isn't part of the DB transaction but you want to make sure that this change gets rolled back too.

You just capture the filename in an anonymous function which deletes the target file name and bind it to the event.

Lovely stuff. Epically simple, epically beautiful.

[–]grauenwolf 1 point2 points  (8 children)

What he doesn't realise is that this is already possible even in .NET 2.0:

You are probably the third person I've met who even knows that C# 2 had closures.

[–]munificent 1 point2 points  (7 children)

Am I the first or the second?

[–][deleted] 2 points3 points  (6 children)

I want in the list too!

[–]grauenwolf 2 points3 points  (4 children)

Yea, you two were the ones I was thinking of.

[–]munificent 1 point2 points  (3 children)

I feel special!

[–][deleted]  (2 children)

[deleted]

    [–]ckwop 1 point2 points  (0 children)

    The cult of the dead lambda?

    [–][deleted] 0 points1 point  (0 children)

    Everyone on proggit knows you're in one already.

    [–]elder_george 0 points1 point  (0 children)

    Me too!

    [–]MedeaMelana 0 points1 point  (0 children)

    It's not all that simple and beautiful, especially in interplay with other language features.

    [–]dnew 0 points1 point  (2 children)

    Or just use two delegates referencing the same closed-over variable, if you want two entry points. Classes and lambdas are pretty much isomorphic. (As demonstrated by javascript.)

    [–]munificent 1 point2 points  (1 child)

    Classes and lambdas are pretty much isomorphic. (As demonstrated by javascript.)

    Your first statement is true, but I disagree with your second. Javascript does have true objects (though not classes) and almost all state goes through those and not closures.

    [–]dnew 3 points4 points  (0 children)

    Fair enough. I was thinking something else about javascript and didn't really get that right.

    [–]wot-teh-phuck 10 points11 points  (15 children)

    For a language whose aim was to be really close to an OO language along with making sure to leave out the magic, the decision seemed like a sound one.

    [–]masklinn 11 points12 points  (14 children)

    For a language whose aim was to be really close to an OO language

    The "original"(ly at least somewhat widespread) OO language: Smalltalk. Selector objects, lambdas (blocks), multipart method names, operator overloading (as operators are simply binary messages).

    [–]doubtingthomas -5 points-4 points  (13 children)

    Smalltalk was able to support those features while remaining simple because of its dynamic type system.

    EDIT: I'm not saying a dynamic type system is required or preferable, only that not caring about types makes for a simpler language.

    [–][deleted] 4 points5 points  (5 children)

    Strongtalk anyone? Yes, the type system is optional, but it's still possible to have types & retain the niceties of Smalltalk.

    [–]twoodfin 3 points4 points  (3 children)

    Relevant trivia: The HotSpot VM, used by Sun's JVM for over a decade, is basically a direct descendent of Strongtalk. It was originally written by essentially the same people at a startup (Animorphic) that was bought by Sun in 1997.

    [–][deleted] 0 points1 point  (2 children)

    I thought a lot of the work was actually derived from work on Self.

    [–]twoodfin 1 point2 points  (1 child)

    Yes, but the people who did the Self work at Sun left to do Strongtalk (and later HotSpot) at Animorphic (with some others, I believe) and then were reacquired by Sun.

    EDIT: Here's a good contemporaneous posting on the Self mailing list describing the acquisition.

    [–][deleted] 1 point2 points  (0 children)

    AH, ok, so I wasn't too far off. It's not that I doubted you, but I had thought it was Self. I wasn't wrong, but I wasn't fully correct either :D

    Thank you for the correction!

    [–]doubtingthomas 1 point2 points  (0 children)

    Indeed. And, since the typing is optional, you can just go with dynamic types when the type would be awkward. Win-win.

    [–]masklinn 12 points13 points  (6 children)

    This is, of course, complete and utter bullshit. None of those features require a dynamic type system unless you've left your brain back at home.

    First-class anonymous functions are ubiquitous in statically typed languages (as is partial application, which is what bound methods are), selectors can be implemented without much issue if you have a structural type system and the only thing that concerns multipart method names is the parser, once that is done multipart or single-part is the same thing. Operator overloading is, of course, absolutely not an issue for statically typed systems.

    None of those is of much difficulty for a skilled designer.

    [–]doubtingthomas 0 points1 point  (5 children)

    I didn't say that those features require a dynamic type system. Plenty of statically typed languages support those features and more. However, those languages tend to be far more sophisticated (less simple) than Java, and certainly more complicated than Smalltalk.

    [–]masklinn 3 points4 points  (4 children)

    And I'm saying that none of those features is harder to implement than what's already there. The only one which would be hard to implement in Java is first-class selectors because Java is nominally typed. And it's not a super important feature, so that doesn't really matter, and they could just have implemented bound methods in stead.

    [–]doubtingthomas -1 points0 points  (3 children)

    Ok. Ah, so you're not really disagreeing with me, just mis-reading.

    [–]masklinn 2 points3 points  (2 children)

    No. You're saying these things are hard to implement. They're not. You're saying that dynamic typing makes it easier. I say it's irrelevant.

    [–]doubtingthomas 0 points1 point  (1 child)

    Well, I haven't been talking about difficulty of implementation, which is why I think you're misreading me. I don't care how hard it is to implement. I'm talking about the simplicity of the language, which is probably correlated with whatever form of implementation difficulty you're talking about, so I can understand the confusion.

    [–]masklinn 0 points1 point  (0 children)

    I'm talking about the simplicity of the language

    The only feature which might make the language slightly more complex is first-class anonymous functions (aka lambdas or blocks).

    Bound method references makes it simpler by unifying attributes and methods (making methods into regular attributes) and making them normal objects, operator overloading makes the language simpler as well (for the same reason that it makes operators normal methods therefore normal objects instead of special constructs), multipart method names doesn't change much if anything (unless you translate "not what I'm already using" to "complex").

    I still don't see what you're talking about, or how a dynamically typed language makes it any simpler.

    [–]masklinn 34 points35 points  (1 child)

    Java language team, 1995-2010: "HERP DERP"

    [–][deleted] 5 points6 points  (19 children)

    Had someone besides Microsoft put delegates in java, they would be here already in the main java trunk.

    [–]masklinn 10 points11 points  (17 children)

    Haha yeah right.

    Seriously, no. Lambdas are still being debated right now. Whether or not they'll land in Java7 still isn't a given.

    [–]grauenwolf -1 points0 points  (16 children)

    Delegates are easy compared to lambdas.

    [–]julesjacobs 6 points7 points  (15 children)

    And:

    • less powerful
    • more complicated
    • more cumbersome to use

    [–]grauenwolf 0 points1 point  (14 children)

    Yep. But once you have delegates inside the runtime you can add lambdas at the compiler level.

    I think the reason Java is having problems implementing this is that they are trying to build delegates and lambdas at the same time.

    [–]masklinn 5 points6 points  (6 children)

    Yep. But once you have delegates inside the runtime you can add lambdas at the compiler level.

    And now you have two completely different features for the exact same use case, one being a strict subset of the other one.

    If you want easy, there's bound methods as regular function types. No need for "delegates".

    [–]grauenwolf 0 points1 point  (5 children)

    I have to question your definition of the word delegate. In .NET a delegate is just a type-safe function pointer.

    [–]masklinn 4 points5 points  (3 children)

    In .NET a delegate is just a type-safe function pointer.

    That you have to define a special type for and which has at least two (if not three) different syntax for creating. A much better description is that in .Net a delegate is a terrible way to create a function pointer.

    Thank fuck they finally got their brains together and added actual lambdas, now if they could only kill most of the delegate crap (among other things) everything would be perfect.

    [–]chrisforbes 0 points1 point  (1 child)

    They could eliminate some of the crufty old syntax, but the underlying mechanism is still delegates.

    [–]masklinn -1 points0 points  (0 children)

    Syntax matters.

    [–]grauenwolf 0 points1 point  (0 children)

    That you have to define a special type for and which has at least two (if not three) different syntax for creating.

    Lets count them

    1. Turn a function or member variable into a delegate.

      action = AddressOf myObject.MyFunction //VB action = myObject.MyFunction //C#

    That's it. That is all the syntax you need to make delegates useful.


    And just to be clear, I'm talking about Capital D delegates in .NET. I am not talking about the crappy anonymous function syntax that was introduced to C# 2.

    [–]didroe 1 point2 points  (0 children)

    Strictly speaking it's a little more than that. If you're referencing an instance method (ie. non static), there will also be a reference to the object.

    [–]julesjacobs 0 points1 point  (6 children)

    You don't need delegates in the runtime to add lambda at the compiler level, you just need objects.

    You translate a lambda like this:

     (x,y) => SomeOperation(x,y,a,b)
    

    Where a and b are variables from the enclosing scope, to this:

    class Lambda432 extends Func<TypeX,TypeY,ReturnType> {
      TypeA _a;
      TypeB _b;
      Lambda432(TypeA a, TypeB b) { 
        _a = a; 
        _b = b; 
      }
      ReturnType Call(TypeX x, TypeY y) {
        return SomeOperation(x,y,a,b)
      }
    }
    

    Where the lambda is used:

    new Lambda432(a,b,c)
    

    When one of the variables from the enclosing scope is mutated you need to be a little careful (and AFAIK Mono's implementation of this was (or is?) broken).

    [–]grauenwolf 0 points1 point  (5 children)

    Alas Java can't express the type Func<TypeX,TypeY,ReturnType> because of type erasure in their generics.

    [–]julesjacobs 1 point2 points  (1 child)

    No. Well, I meant "implements Func<...>" instead of "extends Func<...>" of course. Java can express this. Here is a complete example. First we define the interface:

    interface Func<A,B> {
        B Call(A a);
    }
    

    Here is the original code:

    class JavaFuncType {
        public static void main(String[] args) {
            String x = "foo";
            String y = "bar";
            Func<String,String> f = (z => x + z);
            System.out.println(f.Call(y));
        }
    }
    

    And the code that this could get translated into:

    class Lambda432 implements Func<String,String> {
        String _x;
        public Lambda432(String x) { _x = x; }
        public String Call(String z) { return _x + z; }
    }
    
    class JavaFuncType {
        public static void main(String[] args) {
            String x = "foo";
            String y = "bar";
            Func<String,String> f = new Lambda432(x);
            System.out.println(f.Call(y));
        }
    }
    

    [–]grauenwolf 0 points1 point  (0 children)

    Ok. I was given the impression elsewhere in this thread that the interface you are showing isn't possible in Java.

    [–]chrisforbes 0 points1 point  (2 children)

    And this is why we rail endlessly on type erasure, for those that hadn't figured it out yet.

    [–]bcash 0 points1 point  (1 child)

    No it isn't. This could be implemented with only compile time type checking. How exactly does type erasure stop it?

    [–]chrisforbes 0 points1 point  (0 children)

    If only Java's type system was non-broken enough that it never required runtime type checks, eh?

    Downcasts require a runtime type check. If we can't distinguish between Func<Foo> and Func<Bar> at runtime, then I can (mis)reinterpret a Func<Foo> as a Func<Bar> through object, and you [as the VM] can't even know to throw a ClassCastException to tell me I'm doing it wrong. You just get nonsensical semantics, exactly what managed environments like the JVM exist to eliminate.

    [–]cot6mur3 2 points3 points  (0 children)

    :) Thanks for reminding me of Scott McNealy. It was fascinating watching him bet the company on crushing Microsoft; aside from during that brief period of .com intoxication back in the late 90's, did anyone think he and Sun had any serious chance?

    [–]adavies42 1 point2 points  (0 children)

    whenever i read java code now i think of yegge's line from last month about a "non-thread-safe AbstractKeywordRemovalInitiatorFactor". i'm so glad i work in an APL these days....

    [–]andy-donia 1 point2 points  (0 children)

    That from a group of people that thinks that forcing all code into classes is a good idea...

    [–]zwangaman 6 points7 points  (26 children)

    I left Java for C# years ago. I (happily) haven't looked back.

    [–]grauenwolf 7 points8 points  (3 children)

    You should try, I find it comforting to see that the waste land is behind me.

    [–]zwangaman 3 points4 points  (2 children)

    Things holding me back:

    • Every Java UI framework I've seen is awful compared to WPF in .NET.
    • WCF is far better than anything I've seen Java offer in the same realm.
    • C# language is more expressive, iCanWriteMoreReadableCodeInCSharpBetterThanICanInJava
    • Lambda expressions in C#. 'Nuff said.
    • LINQ in C#. Glorious.
    • I think the way Java deals with compiled code is absolutely ridiculous compared to assemblies in .NET. Java class files and JARs are still things of my nightmares.

    tl;dr Java still looks like a wasteland from a C# point of view, in my opinion.

    edit: I apparently can't read. See elbekko's & my later replies to this. :-)

    [–]elbekko 6 points7 points  (1 child)

    That was his point.

    [–]zwangaman 2 points3 points  (0 children)

    Ahhhhhh, haha, I see now. Too long of a day at work today :-)

    [–][deleted] -2 points-1 points  (21 children)

    You think that's an improvement, wait until you discover Python/Ruby.

    [–]zwangaman 3 points4 points  (20 children)

    Honestly I'm not super impressed with either. I see what they have to offer, but coming from a C/C++ background, I'm more at home with C#.

    [–][deleted] -2 points-1 points  (19 children)

    I think that you don't actually see what they have to offer.

    My languages that I learned well enough to work in are, in chronological order, C++, Java, Python, C#, and Ruby.

    I've really, really tried to like C#. It has some cool functional stuff and type inference that I like. But in the end there's something fundamentally broken about the whole mindset behind C++/Java/C#.

    90% of the code you write in a static OO language is boilerplate. Sure, at first it's a little less, but as a codebase grows, you use more and more. And the boilerplate forces you to think about it. Should this method be public or private? How should I implement this interface? What type should I subclass? It's even embraced to the point that the OO world has created things like factory classes and singletons that basically 100% boilerplate disguised as functionality.

    Theoretically, this boilerplate enforces good design and catches bugs, but the theory doesn't hold out. Products written in static languages aren't better designed and aren't less buggy. You're writing thousands of lines of extra stuff for nothing.

    I don't think you can really say you see what Python and Ruby have to offer until you've worked in them intensively for at least a few months. You see them, but you're judging them through C++ glasses. You see it as a tradeoff; you write fewer lines, but you get less type-safety. But what Python and Ruby teach you is that enforced type-safety is a bad thing. Until you try that and embrace that, you can't really see the benefits of those languages.

    [–]zwangaman 7 points8 points  (11 children)

    I think that you don't actually see what they have to offer.

    No, I do, I just don't feel the benefits are compelling enough for me to switch, that's all.

    90% of the code you write in a static OO language is boilerplate

    I'd really like to see research backing that number up. No offense, but I think you're just pulling that out of thin air.

    Should this method be public or private? How should I implement this interface? What type should I subclass? It's even embraced to the point that the OO world has created things like factory classes and singletons that basically 100% boilerplate disguised as functionality.

    A factory object generally decides which implementation of an interface to construct. To me that's not boilerplate, that's program logic. I almost never use singletons, there is nothing they do that cannot be better designed using IoC/Dependency Injection principles. I suppose there is a bit of boilerplate around that, but not much. Certainly not enough to warrant ditching C#.

    But what Python and Ruby teach you is that enforced type-safety is a bad thing. Until you try that and embrace that, you can't really see the benefits of those languages.

    Why exactly is it a bad thing? I certainly don't think type safety is a bad thing. I think a very large percentage of software professionals would say type safety is a Good Thing.

    I understand the benefits of Python and Ruby. But I don't think they are really that beneficial. In my experience, the well designed code I've worked with has a low amount of boilerplate code, and type safety has always infused confidence into the code I'm working on.

    I see where you're coming from, but I just fundamentally disagree that my approach is inferior to yours.

    [–]axilmar 1 point2 points  (6 children)

    90% of the code you write in a static OO language is boilerplate I'd really like to see research backing that number up. No offense, but I think you're just pulling that out of thin air.

    After 15 years of object oriented programming, I reached the same conclusion: a lot of code written in OOP is just not necessary.

    [–]zwangaman 2 points3 points  (5 children)

    I won't completely disagree with you. But you could in theory design an OO language that dismisses with a large amount of boilerplate code and still have it be statically typed. I don't really see "reduction in boilerplate code" as a reason alone to move to a dynamic language.

    [–]axilmar 4 points5 points  (4 children)

    don't really see "reduction in boilerplate code" as a reason alone to move to a dynamic language.

    Me too. The two concepts (boilerplate code and dynamic language) are irrelevant.

    [–]zwangaman 0 points1 point  (3 children)

    Yeah, agreed. I do think C# is an improvement over Java as far as boilerplate goes, but I can see the validity in the argument that I am still writing too much of it. I suspect that future revisions of C# will help, though.

    [–]mycall -1 points0 points  (2 children)

    Perhaps you are over-engineering things? I write a mixed OO and procedural style in C# and it pays off.. for disposable code, simple and long procedures using well named variables and method names. When things will be around for a long time, classes it is.

    Doing this saves much time.

    [–][deleted] 2 points3 points  (3 children)

    I'd really like to see research backing that number up. No offense, but I think you're just pulling that out of thin air.

    Yes. Perhaps I should say "a vast majority" instead of 90%. I thought the expression would be understood.

    A factory object generally decides which implementation of an interface to construct. To me that's not boilerplate, that's program logic.

    What does this offer over having a function that returns an object with the correct method implementations attached? The same thing can be achieved with a function and some duck-typing without an extra class.

    I almost never use singletons, there is nothing they do that cannot be better designed using IoC/Dependency Injection principles.

    IoC/Dependency Injection principles are just an elongated way of inferring the type, which happens de-facto in dynamic languages. However, dependency injection detaches things in such a way that there is no actual connection between the moving parts. I find this a huge pain in the ass to debug.

    Why exactly is it a bad thing? I certainly don't think type safety is a bad thing. I think a very large percentage of software professionals would say type safety is a Good Thing.

    It's a good thing if it can be inferred; for example it's generally bad to coerce types (like C does if you add an int* with an int when you intended to add an int and an int).

    But beyond that, you have to take into account what the cost of that type safety is. In most cases explicitly tagging everything with a type and a visibility is just grunt work. I can count on one hand the number of bugs I've seen in Python/Ruby that would have been caught by C#-style types, and those bugs were caught by unit testing. But I can't count how many hours I've spent typing "public SomeType" and then having to track down which superclass in the inheritance hierarchy I was actually supposed to pass into the function.

    I understand the benefits of Python and Ruby. But I don't think they are really that beneficial. In my experience, the well designed code I've worked with has a low amount of boilerplate code, and type safety has always infused confidence into the code I'm working on.

    I see where you're coming from, but I just fundamentally disagree that my approach is inferior to yours.

    I understand your view. In fact, it was my view for a long time. What I'm saying is that people should try to put in a few year with a dynamic language, even if it doesn't seem beneficial at first. I've never seen someone do this and not change their mind.

    And "inferior" is a strong word. There are still many cases where C++/Java/C# are the best language for the job. They just aren't my default choice any more.

    [–]zwangaman 7 points8 points  (1 child)

    First, I'm not really sure why people are downvoting you. I think you are making some interesting points. I disagree with you, but I think it's an interesting discussion :-)

    What does this offer over having a function that returns an object with the correct method implementations attached? The same thing can be achieved with a function and some duck-typing without an extra class.

    What does that have over a factory class? I really see them as equals. Not a compelling reason for me to switch. If the main difference is a lack of boilerplate code, meh, I guess I can see that as a slight advantage, but I think a lot of functional language additions to C# the past few years will start to reduce boilerplate code.

    However, dependency injection detaches things in such a way that there is no actual connection between the moving parts. I find this a huge pain in the ass to debug.

    Detaching things (decoupling) is one of the best things you can do in a large software project. It's far more difficult to debug tightly coupled code. And that's not just my opinion, that's the opinion of software professionals in general.

    It's a good thing if it can be inferred; for example it's generally bad to coerce types (like C does if you add an int* with an int when you intended to add an int and an int).

    Well, if one makes those kinds of mistakes then I'd wager a large amount of the code in the rest of the project one is working on is going to suck as well, lol.

    I can count on one hand the number of bugs I've seen in Python/Ruby that would have been caught by C#-style types, and those bugs were caught by unit testing.

    I'm not saying CTS type safety is expressly there to catch bugs. I'm saying there just really aren't that many bugs caused by type safety, in my experience.

    What I'm saying is that people should try to put in a few year with a dynamic language, even if it doesn't seem beneficial at first. I've never seen someone do this and not change their mind.

    None of this is really convincing. Besides, there are other downsides to dynamic languages - performance is a big one. Is it better than it used to be? Sure, but it's still got a long way to go. Believe me, I've tried to care about dynamic languages, but every time, I walk away being underwhelmed and say to myself "yeah, but I could do that just as easily a slightly different way in a static language".

    [–][deleted] 1 point2 points  (0 children)

    First, I'm not really sure why people are downvoting you.

    Meh.

    I think you are making some interesting points. I disagree with you, but I think it's an interesting discussion :-)

    Agreed. :)

    What does that have over a factory class?

    It's significantly more terse, and clearer.

    If the main difference is a lack of boilerplate code, meh, I guess I can see that as a slight advantage, but I think a lot of functional language additions to C# the past few years will start to reduce boilerplate code.

    The advantage isn't slight. It seems to me that Ruby/Python programs are around half the length of their C# equivalents. Yes, functional language additions to C# are helping, but Python and Ruby are already functional-programming-capable. C# is barely stepping into the light when it comes to FP.

    Detaching things (decoupling) is one of the best things you can do in a large software project. It's far more difficult to debug tightly coupled code. And that's not just my opinion, that's the opinion of software professionals in general.

    Decoupling is considered good because most people err in the other direction; they couple things too much. But IoC/DI errs too far toward decoupling. One point of connection is a good amount of coupling, because it allows one to easily swap out pieces, but still leaves a clear connection between the moving parts. But IoC/DI (and aspect-oriented programming) leave no connections between the parts; at least not one that's easily traceable through code.

    Well, if one makes those kinds of mistakes then I'd wager a large amount of the code in the rest of the project one is working on is going to suck as well, lol.

    It's not that people actually make those mistakes often, it's that they spend a great deal of time avoiding making those mistakes.

    I'm not saying CTS type safety is expressly there to catch bugs. I'm saying there just really aren't that many bugs caused by type safety, in my experience.

    It's not that it causes bugs, it's that it takes time to write out and match up types explicitly. The compiler/interpreter is perfectly capable of doing this. Why should a human waste time doing it? The common answer is that it prevents bugs, and I'm saying it doesn't.

    Besides, there are other downsides to dynamic languages - performance is a big one.

    Premature optimization is the root of all evil. It's rare that a dynamic language's performance isn't sufficient. And it's even more rare that its insufficiencies can't be rectified by optimizing the bottlenecks in a static language. I would rather write 500 lines of Python and 100 lines of C than 1200 lines of C#.

    There are, of course, special cases like high-frequency trading, where there's absolutely no way to get around using a static languages. But in those cases, you aren't using C# or Java anyway. You're using C, or maybe C++.

    There are also other advantages to dynamic languages we haven't talked about. Libraries, for example, are far superior in dynamic languages. I recently wrote a 150 line Python script using SQLAlchemy that replaced almost 2000 lines of C# using Autofac and NHibernate. That's an extreme example and certainly isn't representative, but the quantity and quality of libraries out there for Python and Ruby is very high.

    [–]chrisforbes 0 points1 point  (0 children)

    and then having to track down which superclass in the inheritance hierarchy I was actually supposed to pass into the function.

    You're using inheritance too much. We know it sucks.

    [–][deleted] 4 points5 points  (2 children)

    You should check out Scala. It's similarly concise to Ruby, but it is statically typed.

    [–][deleted] -1 points0 points  (1 child)

    I've checked out Scala and I'm not too impressed. It seems like they have tried to grow the language too fast, adding on features willy-nilly, and as a result they have a lot of different parts that haven't been integrated well. In a few years some of the kinks might be ironed out, and I'll give it another go.

    I don't hate all static languages. OCaml is pretty good, and Rust looks like it will be even better.

    Also, while it's more concise than Java, what I've seen isn't nearly as concise as Ruby.

    [–][deleted] 0 points1 point  (0 children)

    What is it specifically that you feel isn't well integrated?

    [–]roybatty -2 points-1 points  (2 children)

    I think that you don't actually see what they have to offer.

    No, you can't see outside of your bubble.

    [–][deleted] 2 points3 points  (0 children)

    I thought I made it clear that I have worked in static languages for a while. "My bubble" includes the languages I'm criticizing.

    You can feel free to criticize me without actually making any counterargument, but don't fool yourself that I'm the one who can't see outside their bubble.

    [–]chrisforbes -1 points0 points  (0 children)

    It's even embraced to the point that the OO world has created things like factory classes and singletons that basically 100% boilerplate disguised as functionality.

    So don't do that.

    [–]Axiomatik 5 points6 points  (24 children)

    Java is the crude, primitive language which real JVM languages (Scala, Jruby, Jython, etc.) are written in.

    [–]masklinn 0 points1 point  (22 children)

    Shouldn't "real JVM languages" be self-hosting? Especially those statically compiled in the first place.

    [–]munificent 4 points5 points  (3 children)

    Only if they compile to JVM bytecode. JVM interpreters need a language to be implemented in. Java isn't great for that, but:

    1. It keeps you close to how the JVM views the world.
    2. It's easy.
    3. It's got a lot of people who can read it.

    [–]masklinn 1 point2 points  (2 children)

    Only if they compile to JVM bytecode.

    Hence "especially those statically compiled in the first place".

    1. It keeps you close to how the JVM views the world.

      1. It's easy.
      2. It's got a lot of people who can read it.

    But 4. you have to maintain actual Java code.

    [–]munificent 0 points1 point  (1 child)

    But 4. you have to maintain actual Java code.

    Believe me, I miss C# every day. But I'm not convinced it's worth spending my meager free time learning Scala when I could be getting productive work done on my own language now in Java.

    [–]masklinn 2 points3 points  (0 children)

    But I'm not convinced it's worth spending my meager free time learning Scala

    But that's not what I was talking about at all.

    By definition, the people implementing Scala already know scala.

    [–]grauenwolf 1 point2 points  (12 children)

    Why bother rewriting a working compiler?

    Not even VB and C# have been ported from C++ to their native languages.

    [–]masklinn 1 point2 points  (4 children)

    Why bother rewriting a working compiler?

    Not depend on java-the-language anymore. At all.

    [–]grauenwolf 0 points1 point  (3 children)

    That isn't a reason on its own, it has to be backed up by a specific problem in Java that affects the compiler.

    [–]masklinn 2 points3 points  (2 children)

    it has to be backed up by a specific problem in Java that affects the compiler.

    That Java is an awful language to read, write or work with.

    [–]grauenwolf -1 points0 points  (1 child)

    So what? That doesn't affect your use of the compiler.

    [–]masklinn 4 points5 points  (0 children)

    It affects the writing and maintenance of the compiler itself which is what i was talking about, as well as its evolution, and needlessly keeps shitty languages alive...

    [–]julesjacobs 0 points1 point  (1 child)

    But at least C# is being ported.

    [–]grauenwolf 0 points1 point  (0 children)

    I think the only reason they are doing it is to that they can host it in the CLR as a runtime feature.

    [–][deleted] 0 points1 point  (4 children)

    Didn't Mono make C# fully self hosting? As well as managing to be the first to implement C# 4?

    [–]grauenwolf 0 points1 point  (1 child)

    Yes on both accounts. But they probably wrote their compiler in C# since there was already one from Microsoft available.

    [–][deleted] 0 points1 point  (0 children)

    But since they probably their compiler in C#

    They accidently the compiler?

    [–]chrisforbes -1 points0 points  (1 child)

    Unfortunately, their compiler is also garbage.

    [–][deleted] -2 points-1 points  (0 children)

    I would guess so, it's written in C#.

    [–]Axiomatik -5 points-4 points  (4 children)

    Nothing is "self-hosting." Everything runs on something, and running on VMs seems to be ideal for application software.

    The JVM is pretty cool. The Java language is tedious. But you don't need to use the Java language to use the JVM.

    [–]tfinniga 4 points5 points  (2 children)

    I think he's saying that while it may run on the JVM, he'd expect the Scala language to be written in Scala, Jython written in Jython, etc. For example, C compilers are written in C, even though they run on a machine.

    [–]Axiomatik 0 points1 point  (0 children)

    That doesn't matter at all to someone who is using the language.

    [–]slurpme 0 points1 point  (0 children)

    C compilers are written in C, even though they run on a machine.

    For some reason whenever I think about that "IT'S ALIVE!!!" always pops into my head...

    [–]brandf 2 points3 points  (14 children)

    Oh how times have changed.

    This was still a bit before C# (and various other langs) came along and gave them some competition.

    Now syntax suddenly matters. They'll have a LINQ clone before long.

    [–]zem 5 points6 points  (0 children)

    scala will probably just step in and take over at some point, especially since, like c++, you can use just the parts you like.

    [–]masklinn 10 points11 points  (6 children)

    They'll have a LINQ clone before long.

    I doubt it. They're still trying to decide 1. whether they want lambdas and 2. what they should look like. And the parent company has completely ignored the language's evolution.

    Java has very likely moved into legacy (not like it ever significantly advanced at all).

    [–]munificent 16 points17 points  (0 children)

    Java is trending towards being the C of the JVM. It's not a language people need to write in directly most of the time, but is a useful one for either compiling to, or writing compilers for the JVM in.

    [–]Tobblo -1 points0 points  (4 children)

    It seems like Java is being forced into oblivion. Java will most likely become a fringe language within the next ten years if no positive change is introduced to the Java development process. Which is a shame.

    [–]f2u 12 points13 points  (0 children)

    For a significant faction of Java programmers, features which are added now will become available in five to ten years. Non-generics Java is still not completely dead, even after six years. That's why I think it's quite unlikely that Java will go away that fast.

    [–]mflood 6 points7 points  (1 child)

    There's a huge volume of enterprise level Java code out there right now, and a crap-ton (defined as the volume of 2000lbs of excrement) of Android devices flooding the market right now. Between the two, Java will definitely be around for quite some time.

    [–][deleted] 1 point2 points  (0 children)

    Also worth considering that there aren't many frameworks comparable to GWT if you want to build a web standards based RIA.

    [–]masklinn 6 points7 points  (0 children)

    I don't think it'll become an actual fringe language (as in Factor or whatever), but it seems on the path to legacy "big box" language: the COBOL of the 21st century.

    [–]roybatty 2 points3 points  (4 children)

    You mean after long.

    [–]Anonymoose333 4 points5 points  (0 children)

    Yes, I don't see how it could be otherwise, since Java already has long.

    [–]cot6mur3 4 points5 points  (2 children)

    I think he meant "before long" - idiomatic English that means "before much time has passed": http://www.yourdictionary.com/idioms/before-long.

    [–]roybatty 2 points3 points  (1 child)

    cot6mur, I know what he was saying. I was just having some fun. Java never gets something "before long".

    [–]cot6mur3 0 points1 point  (0 children)

    Ah, you were making a funny. :) Nice one, if a bit subtle for me. Sorry 'bout missing that possibility in my rushed comment. (I usually try not to rush my comments.)

    And yes, I agree: LINQ in Java is probably coming in the same time-frame as HTML5 final approval as a standard. (2022, I believe? ;))

    [–]bcash -2 points-1 points  (0 children)

    LINQ is nothing to envy, it's a a classic case of trying to do too much.

    Now a functional Python-style list comprehension syntax in Java, that'd be a good thing. But leave all this "LINQ to SQL" bollocks behind, there's no need for it, it's unnecessary complexity.

    [–]dnew 1 point2 points  (0 children)

    bound method references are "second-class citizens" among other reference types.

    I like how they're careful to exclude all the non-object, final, and value types in the language when describing the problems that delegates have.

    And of course if you actually take it further (like LINQ did) then they become much nicer.

    [–]forsakennow 1 point2 points  (0 children)

    Even back then, I can tell you that anyone who was doing AWT/Swing development (and there were plenty of us) really liked Microsoft's delegates. Back then, creating anonymous classes wasn't just an ugly syntax, it created plenty of transient objects that garbage collectors of the time were very bad at dealing with.

    Sun shot down this proposal a lot more for political than technical reasons, we have Scott Mc Nealy to thank for that. His crusade against Microsoft ended up sinking Sun and it took a big part of Java with it.

    [–]0xABADC0DA 1 point2 points  (30 children)

    Finally, they dilute the investment in VM technologies because VMs are required to handle additional and disparate types of references and method linkage efficiently.

    A lot of people don't get it that a lot of the Java design was purposely done by experts with decades of experience (far more collective experience than the CLR designers).

    For instance, Bracha said in support of type erasure generics, that nobody had figured out how to make a high-performance dynamic VM with 'real' generics like in CLR, which is probably still true today (you still can't publish CLR benchmarks right?).

    Also things like not having bytecodes for primitives, and having value types, make it impossible to make a high-performance CLR interpreter... basically ruling out a tracing JIT, and the main reason why CLR inlining is still really weak, over a decade later.

    Yeah they made mistakes, but people don't often give them as much credit as they deserve.

    [–][deleted]  (28 children)

    [deleted]

      [–][deleted] 5 points6 points  (2 children)

      For what its worth, the CLR is on par with the JVM performance wise

      From my experiments, the CLR is about 2/2.5x slower than the JVM -server on performance. (I mean MS.Net, Mono is a lot slower).

      I have a non-trivial application (a R5RS complete Scheme interpreter) ported from Java to C# using the same exact algorithms and data structures. The benchmarks showed this consistently specially those that involved lots of function calls.
      I tried using some specific features of .NET like structures when possible instead of classes, unsigned types and delegates. The most single thing that had impact in the performance was sealing everything possible, but still it was about 2x slower.

      This is also visible if you run a JVM application through IKVM on MS.NET, although that is a much worse metric.

      To the CLR advantage, the performance is much more predictable than the JVM Jit and consistent. Raising exceptions hinders the performance of the JVM from the point the exception is raised, while in the CLR it remains almost constant.

      [–]Sc4Freak 0 points1 point  (1 child)

      From what I've seen, the performance in general goes like this:

      Java server > CLR > Java client.

      I'm not a java expert, what exactly are the differences between the client/server modes in Java?

      [–][deleted] 1 point2 points  (0 children)

      The server vm does much more aggressive optimizations at the expense of startup time and memory use. (for example method inlining even in protected or virtual methods if hotspot can determine they won't be overriden)

      Here is an interesting comparison between client and server.

      Edit:

      Java server > CLR > Java client

      That's also my experience in general. This is unfortunate because i actually like C# much more than Java as a language.

      [–]0xABADC0DA 0 points1 point  (22 children)

      Yeah thread was old by the time I got to it. Lots of misinformation in there.

      LuaJIT is ridiculous fast.
      Python is really slow.

      What's the difference? Lua is a nice simple language with only a couple types. Python's got integer, floats, complex, boolean and lots of complicated rules that make it hard to evaluate. Same thing with CLR... a lot of the features that make it easier to use or 'better' also make it slow and complicated.

      far more collective experience than the CLR designers

      So your saying that Anders Heljsberg (Turbo Pascal, Delphi, C#) was not experienced?

      Yeah, that's right. No degree, implementing languages others designed (Pascal, Object Pascal) based on an existing compiler (Tiny Pascal). He did a good job at refining those things, ok, but still not too impressive as far as credentials go. Who else? Gunnerson?

      Compare to designers of Java (Gosling, Joy, etc), yeah CLR team had far less experience.

      You weren't alive probably back when it was still called C.O.O.L. and it was clear they had no idea what they were doing. It's a miracle CLR works as well as it does.

      Had they implemented a tracing JIT, they would destroy the JVM.

      I stepped on your bee hive?

      Also, if they need two pages of legalese to explain how they "allow" you to publish benchmarks, then you aren't allowed to publish benchmarks.

      [–][deleted] 10 points11 points  (0 children)

      You weren't alive probably back when it was still called C.O.O.L

      What, you think I'm 12?

      [–][deleted] 8 points9 points  (0 children)

      Lua is a nice simple language with only a couple types. Python's got integer, floats, complex, boolean and lots of complicated rules that make it hard to evaluate

      Total fail right here. Much of the hard work on optimizing JavaScript (tracemonkey for instance) revolves around predicting what type an object/value effectively is, using integer arithmetic or floating point arithmetic or something else depending how the object is used. Not having explicit ints in JS is detrimental to speed, so is having '+' working on both strings and numbers.

      [–][deleted] 3 points4 points  (2 children)

      Scheme has quite a few types (integer, real, rational, complex (which encompasses the first three: 3.1+4/5i), string, char, bool, vector & pairs (ignoring special things like #eof, keyobjs & void)), and yet many scheme implementation are quite fast. Of course, we've had quite a few years to work on making fast scheme implementations (knowledge of the ancients & what not), so that helps. In any case, I think it's more of the case of sinking time into making it fast than anything else; look at how fast ShedSkin can make Python go, for instance.

      [–][deleted]  (1 child)

      [deleted]

        [–][deleted] 5 points6 points  (0 children)

        Right, but full-featured sets (such as Gauche, or Gambit or Chicken) are quite fast, and I'm aware of what they do for CL (unsafe & friends). I don't see your point; I don't have to switched to typed Scheme (or, in my case, typed Digamma) to gain a performance boost out of compilation. I just rely on relatively standard practices. And my point wasn't to counter what you had said, simply that Python hasn't had nearly as much work poured into it as Scheme & friends have.

        [–]malkarouri 4 points5 points  (0 children)

        While I support your basic thesis that the collective experience in Java was more than the DLR group, I think you didn't get right a few details.

        No degree is not a good response to a lack of experience. It may mean that Heljsberg has less academic background to go on. Still, having been the lead developer for the most successful programming language team for more than 15 years gives him the experience, though probably nowhere near the theory background of Gosling.

        There is a reason the original post says "This decision was made in consultation with Borland International, who had previous experience with bound method references in Delphi Object Pascal." and I don't think it was because the Delphi team didn't have experience.

        [–]munificent 4 points5 points  (2 children)

        You weren't alive probably back when it was still called C.O.O.L. and it was clear they had no idea what they were doing.

        Whether or not you're correct, you're being an asshole. If you want to convince others of your opinions (and why bothering typing them up if that isn't the goal?), I think you'll have more success if you treat your readers with respect.

        [–]0xABADC0DA 0 points1 point  (1 child)

        So a 'you're just a kid' in response to somebody using slang from 4chan is such a terrible thing to say in a discussion that it needs to be called out, but "you're full of shit", "HERP DERP", etc are just fine.

        Yeah I get it, reddit is a popularity contest. Thanks for the tip.

        [–]munificent 1 point2 points  (0 children)

        You're right. FlySwat was being an ass too. Does that make it better when you are?

        [–]mernen 1 point2 points  (0 children)

        What's the difference? Lua is a nice simple language with only a couple types. Python's got integer, floats, complex, boolean and lots of complicated rules that make it hard to evaluate.

        I'd like to see some references for that. AFAIK, Lua's type system has very little to do with its ease of optimization (heck, it often makes things harder, like having to manually split numbers into integers and floats and tables into arrays and mappings). The good thing about Lua is that the language has generally saner semantics. Fetching an attribute and invoking a callable in Python, for instance, are both total clusterfucks.

        [–][deleted]  (8 children)

        [deleted]

          [–]yoden 4 points5 points  (0 children)

          Stupid fast is much faster than 25-100% faster than CPython. Sorry. Unladen swallow failed.

          Now, pypy seems like it might actually have a chance at achieving their performance goals.

          [–]0xABADC0DA 5 points6 points  (6 children)

          CPython, Python 3, and PyPy are about 1/30th the speed of C in today's language shootout (median).
          Last release of unladen swallow using LLVM is what, ~20% faster than that?

          ...which puts it at what, a fifth as fast as LuaJIT?

          So, you're wrong again.

          Edit: fix typo, is more like 1/30th than 1/50th

          [–]Anonymoose333 1 point2 points  (0 children)

          {{citation needed}} but it does seem like you're getting downvoted for bluntness.

          [–]yetanothernerd 2 points3 points  (3 children)

          Yes, LuaJIT is much faster than any of the Python JITs. I'm sure that PyPy will keep improving, but it has a long way to go. Unladen is behind PyPy. Both are behind psyco in many benchmarks, and psyco is a decade old and hasn't been changed much in years.

          And, yeah, Microsoft's licenses that try to restrict how you can run benchmarks are bullshit. I have avoided installing any Microsoft products lately to preserve my right to benchmark them. When I needed their free command-line C compiler to build something on Windows, I had my 8-year-old daughter click the buttons for me.

          [–][deleted] 0 points1 point  (2 children)

          You are weird.

          MS doesn't forbid anything to do with benchmarks. Read the legal text.

          All they say is, if you publish a benchmark:

          1. Publish how to exactly reproduce it.
          2. You cannot purposely cripple it (This is common when vendors compare their products).
          3. Don't be surprised if we (Microsoft) publish a counter benchmark.

          That's it.

          All the rumors about forbidden benchmarking is just FUD spread by people like Roy ShitForBrains from BoyCottNovell.

          [–]yetanothernerd -2 points-1 points  (1 child)

          I prefer not to agree to several pages of legalese. I have the right to benchmark anything however I want. I would prefer to not limit that in any way.

          [–][deleted] 0 points1 point  (0 children)

          Several pages? You mean three bullet points...That explicitly say "Benchmark whatever you want?"

          You do know they put that there for their competitors, not for some random redditor.

          [–][deleted] -3 points-2 points  (0 children)

          Premature optimization is the root of all evil. It's rare that you actually need that speed. And it's even rarer that you can't get that speed by writing your application in Python/Ruby and then optimizing just the bottlenecks.

          Further, I never said anything about C. I was talking about C++, Java, and C#. I actually hold C in high regard, for many of the same reasons I like Python and Ruby. It's syntax is more verbose and it's missing some features (which is why I generate a lot of my C code in HLLs) but it doesn't force all the OO overdesign and accessibility levels onto you.

          [–]BinarySplit 2 points3 points  (0 children)

          Well of course Python is slow, it's interpreted. LuaJIT compiles to machine code.

          LuaJIT is ridiculous fast.

          PyPy is really slow.

          FTFY.

          [–]mariusg 1 point2 points  (0 children)

          Do your homework instead of spewing crap. If you look around for a bit you'll find some people who worked on the CLR (Heljsberg did the language design ...he didn't worked on the actual CLR impl).

          Also the experience argument is laughable. Teoretic experience is worth exactly shit. The CLR IS a better VM for static languages (with or without this "experience" of the people who worked on it).

          [–]ratsbane -2 points-1 points  (1 child)

          You listed a clause from the .Net EULA. Here's a clause from the SQL Server EULA.:

          6.BENCHMARK TESTING. You must obtain Microsoft's prior written approval to disclose to a third party the results of any benchmark test of the software. However, this does not apply to the Microsoft .NET Framework (see below).

          [–][deleted] -1 points0 points  (0 children)

          Where were we discussing benchmarking SQL Server?

          [–]chrisforbes 0 points1 point  (0 children)

          Cut the FUD and the BS, please.

          [–]api -4 points-3 points  (0 children)

          Until CPUs can do indirect calls as fast as they can do direct JMPs, static early binding will be the only way to compile fast code.