14 ms·
I was wrong, reflecting on the .NET design choices
- hdhzy 9y agoI think it's valuable to read interviews with Anders Hejlsberg [0] about the design process for both .NET and C#. They are old but clearly communicate why certain decisions have been made (spoilers: compatibility). [0]: http://www.artima.com/intv/anders.html http://www.artima.com/intv/anders.html
- marsrover 9y agoI'm surprised the creator of RavenDB took this long to come around on composition vs inheritance. Good on him for admitting his transgressions, however.
- sevensor 9y ago> Another issue is that my approach to software design has significantly changed. Where I would previously do a lot of inheritance and explicit design patterns, I’m far more motivated toward using composition, instead. I picked up on this too; object-oriented design patterns have lost a lot of mindshare over the last ten to fifteen years. There was a time when it seemed like design patterns were taking over the world. We're still living with some of the monstrosities spawned during that era. I wonder if design patterns can ever be rehabilitated.
- jasode 9y agoIf I attempt to generalize it, I think most of C#'s differences in language design that have opposites in Java are superior. Examples include: + not virtual by default (so base classes can be changed more easily without breaking/recompiling downstream clients that the base class writer doesn't know about; specifying something as "virtual" should be a deliberate conscious decision by the class author) + value types (for speed, because J Gosling's idea that "_everything_ is an object is 'simpler' for programmers" has a cost -- the boxing & unboxing, and inefficient cache-unfriendly pointer-chasing containers) + no checked exceptions (checked exceptions have benefits in theory but real-world practice shows that it forces programmers to copy-paste mindless boilerplate to satisfy the checked-constraint) + unsigned types (very handy for P/Invoke API boundaries because legacy Win32 has unsigned params everywhere; yes, yes, Gosling said that unsigned types are confusing and dangerous but nevertheless, they are still very useful) + many other examples This doesn't mean that Anders Hejlsberg's C# language team was smarter than J Gosling's Java team. They simply had 7 years to observe how Java programmers (mis)used the language and therefore, could correct some design mistakes. Nevertheless, C# still made some dubious decisions such as renaming "finalizers" to "destructors". Java had the better name and C# should have kept the original terminology.
- namelezz 9y agoWhat do you think of partial classes and methods in term of code quality?
- jasode 9y agoI've always thought of "partial classes" as a language feature motivated by code generators not stomping on programmers' manually entered code. E.g. Winforms generates some declarations in one partial class while the programmer codes UI handlers in the other partial class.
- namelezz 9y agoWhen I first learned C#, I was having a hard time to navigate the code due to partial methods. So I have always wondered what C# developers think of having their methods spread out in different files.
- aanm1988 9y agoIt's a tool to use. Like others have said, it makes working with generated code easier.
- dragonwriter 9y agoPartial classes and partial methods exist specifically to support having code that is automatically generated paired with a human-managed source file. While you could use the support for them to split human-managed code across separate source files, that would be a horrible practice that I've never encountered in the wild, even in .NET shops with otherwise-atrocious practices and code quality.
- jasode 9y ago>While you could use the support for them to split human-managed code across separate source files, that would be a horrible practice To continue that type of advice, some say "#region/#endregion" is another language feature that's intended for code generators so that the IDE can collapse specific lines of code and hide it from view. Programmers should not be hand-coding "#region" themselves. That said, there is debate on that: https://softwareengineering.stackexchange.com/questions/53086/are-regions-an-antipattern-or-code-smell https://softwareengineering.stackexchange.com/questions/5308...
- dahart 9y ago> However, given that I’m working on a database engine now, not on business software, I can see a whole different world of constraints. This might be my own confirmation bias, but this is my takeaway: point of view and the constraints that you see or believe are there are the main determinant of choices, and not whether some particular pattern or feature of a language is intrinsically good. The older I get and the more code I write, the more I find this to be true. I change my own mind about things I used to argue fiercely over and things I thought were tautologically true. I think (hope) this is making me more open minded as I go, more willing to listen to opposing points of view, and more able to ask questions about what someone else's constraints are rather than debating about the results. But, who knows, I might be wrong.
- ska 9y agoI think it is hard to separate this from developing more maturity in the field also. For example, people learning OO seem to almost have to go through a phase of over reliance on inheritance. Pointing back at yourself over 10 years is pointing to a different place, sure, but it is also a different person.
- nickbauman 9y agoI have many years of programming in Java under my belt. Until I started using dynamic languages I thought static typing was really important. It's not.
- sqeaky 9y agoIt rules out certain categories of bugs, makes it hard to assign a string to an int, etc... If you are writing a small one time use script to accomplish a task clearly this that kind of protection is of low value. If you are trying to write or maintain a system intended to last 20 years and keeps bugs out of 100 millions lines of code, every kind of check that can be automated has extremely high value. Most projects are somewhere between these two extremes. The nature of the cutoff point where strong static typing helps or does not is what we should be debating, not its inherent value as Dahart suggested.
- martamoreno 9y agoThe bigger question is why the hell a post like this makes it on top of hacker news? This was by far the most pointless read ever. On top of that arguing that non-virtual by default is worse than virtual by default is completely superfluous. Just add the damn keyword everywhere and you have virtual everywhere. Same for final. But Java has everything non-final and virtual by default, which sucks badass because both require great care when implementing the method. Extending code that was not designed to be extended is very common in Java, because you can. Adding final can easily be forgotten. Removing final, which is required in C#, will only be done IF you intended to make that method extendable, same for virtual. Yes a great gain. Now I need to argue for each final I add to Java classes and methods, because you know, it seems wasteful to add it, while in fact it is crucial, since maybe just 1% of any code I write was meant to be replaceable by a third-party. Mostly, you want to use other mechanism for extension, like decoration & composition. If it took ten years to learn that falsehood (non-virtual is worse than virtual by default), then we talk about one hell of a regression huh.
- danburgo 9y agoWhat this guy said! thank you
- moomin 9y agoThe short answer is a) it's interesting because the author is very notable in the .NET space and b) he's not exactly known for admitting to being wrong about anything.
- mihular 9y agoVirtual methods are also significantly slower to invoke.
- sqeaky 9y agoSignificantly? Have any benchmarks to back that up? Last time I benchmarked in the language I use most (C++) I couldn't get a difference distinguishable from my margin of error.
- oop17 9y agoOne of the greatest lingering flaws in both C# and Java is the lack of metaclasses. Because classes aren't real objects and therefore not necessarily also instances of other classes (their metaclasses) as they would be in Smalltalk, there is no class-side equivalent of "self/this," nor of "super." In effect, you cannot write static (class) methods that call other static methods without explicitly referencing the classes on which those other methods are defined, completely breaking class-side inheritance and rendering class behavior (and instance creation in particular) needlessly brittle. I believe the explosion of factories, abstract factories, and just generally over-engineered object construction and initialization schemes in Java and C# would have been side-stepped if both languages had always had a proper metaclass hierarchy paralleling the regular class hierarchy, as well as some form of local type inference.
- ska 9y agoWhatever the reasons behind it, it is clear that a lot of the effective and high impact industrial languages at various levels of the stack (e.g. c++, ada, Java/C#, python, perl, javascript,etc.) have not managed to incorporate some of the real wisdom learned in earlier systems (e.g. smalltalk an some lisps for OO, etc.) If this was in fact avoidable, it is a sad fact.
- le-mark 9y agoThis type stupid bloviating is why programming will never be a proper engineering discipline. There are two ways to implement oop: classes aka "object templates" or prototypes. Educate your selves people!
- marktangotango 9y agoThis a valid observation, why have no down voters commented? Oop implementation was studied extensively in 80's, CLOS was very contentious in fact. The lack of training and perspective is stunning.
- ska 9y agoThe tone makes it difficult to tell, but I think you are supporting my thesis - mistakes of the past are, in fact, being repeated. Engineering disciplines succeed by a) learning the science and b) applying it properly. We do not do that well in programming. So yes, educate yourself, and then take the lessons to heart.
- klodolph 9y agoJava and C# are seen as "old news" by some here on HN but there's a trove of software engineering wisdom in there. It was a huge boon for Microsoft to be able to learn from Sun's mistakes when they were designing a language that, on paper, is basically the same thing. C#, Java, and Go are all "wonderfully boring" languages which is a divisive topic, but they're all very good at being boring languages. It's not just language features that made C# an improvement over Java, either. CIL is a fair bit more elegant than JVM bytecode. JVM bytecode has type-specific operations to speed up bytecode interpreters, which turns out to be irrelevant since nobody cares about bytecode performance these days.
- emodendroket 9y agoI'm not sure C# is even really in the "boring" category; they were way ahead of Java 8 with the functional collection stuff in Linq and they're borrowing lots of concepts from Scala for the latest versions.
- m_fayer 9y agoIn addition to the functional stuff, C# has a lot of syntactic sugar that I wouldn't associate with a "boring" language. If you aggressively use all the syntactic sugar from the latest version of C# and compare that to similarly up-to-date Java code, they'll be worlds apart. The C# will look terse, and to more conservative programmers, rather weird.
- Faark 9y agoNot to mention they still have/invent multiple ways to do the same. The old Tuple<>, anonymous types and new ValueTuples are pretty much different attempts/iterations to achieve a similar goal. I wonder if/how they will unify them or phase some of them out. Btw, i kinda like java's Anonymous Classes. Do we know any reason for C# not to adopt this as well?
- pikzen 9y ago>Do we know any reason for C# not to adopt this as well? Because delegates are a much easier way of dealing with things? Especially with lambda functions. Unless you're talking about the java pattern of passing an entire anonymous class for, let's say, a formatter or something. The reason for C# not to adopt that seems to be that: - It's so terribly awful, who in his right mind is happy to implement yet another anonymous class? - API design is different and .NET manages to avoid the need of those quite gracefully.
- andrewvc 9y agoYou never really learn a language, and you never really are an expert in using it. While you may know a lot about what the language is, how it works, and accepted ways of using it, your opinions on how to do things will always be evolving (hopefully). Sometimes all the experts who use a language will be behind the times. For a long time experts championed strong OO design. Now all the experts champion hybrid OO/FP style things (witness Java 8!). This too shall pass, and we should have the humility to realize that no-one knows for certain what will be the next evolution of software development.
- hyperpape 9y agoWhile I'm inclined to suspect that non-virtual by default is better from a design perspective‡, don't assume the point about performance is overwhelming. HotSpot has done devirtualization for a long time. You can detect not only when a method is never overridden, but also when it's never overridden at a particular call site. A virtual method that's never overridden can sometimes have no extra overhead, while a virtual method that is overridden may have sufficiently small overhead that it rarely matters. http://insightfullogic.com/2014/May/12/fast-and-megamorphic-what-influences-method-invoca/ http://insightfullogic.com/2014/May/12/fast-and-megamorphic-... ‡ I've used non-OO languages, but never an OO language without virtual by default.
- kjksf 9y agoSince we're talking about performance: the time it takes HotSpot to perform this optimization is also a perf hit for your program. At the end of the day, the fastest code is one that doesn't have to run. HotSpot is an impressive technology but the optimizations it has to do to overcome Java's design really only pay for themselves in most frequently executed code paths and only after some time to gather necessary info to perform the optimizations. It's ok for long-running server code but not good for, say, short-lived command-line program. Or to put it differently: a language that has perf-friendly design, like Go, matches Java's speed with 10% of engineering time and resources spent on the compiler and optimizations. Perf friendly design means it has to do 10% of the work to achieve the same end result.
- hyperpape 9y agoThis may be true in general, but the CLR uses bytecode and a JIT compiler, so that point may be a lot less relevant to it. In addition, devirtualization is apparently valuable enough that they're going to add it to the CLR, per the article.
- MichaelGG 9y agoJava compiles to bytecode and most implementations JIT, just like .NET. JVMs are more advanced than the CLR at optimization.
- PaulHoule 9y agoJava is not "virtual by default", it is virtual-only, except for private methods, which don't participate in inheritence. I like the Java convention, for one thing, because it is one less decision for programmers to make. I've seen many C# programmers who are oblivious to what virtual means.
- 0x0 9y agoWhat about "protected final"?
- matchagaucho 9y ago"Another issue is that my approach to software design has significantly changed. Where I would previously do a lot of inheritance and explicit design patterns, I’m far more motivated toward using composition, instead." This, more than anything, has dramatically improved the quality of my designs... and made coding fun again. Immutability and Lambda functions have also had a tremendous impact on my designs. Is the term Object-Oriented-Programming relevant anymore?
- jameslk 9y agoI don't see how preferring composition over inheritance makes OOP less relevant. In fact, GoF even suggests using composition over inheritance in OOP. Nor do I see how immutability and lambda functions are mutually exclusive to OOP either. You can have all of these things and still reap plenty of benefits from OOP. The benefits of OO polymorphism and several decades worth of architectural design patterns are not irrelevant just because functional programming concepts exist. Both should be used advantageously and when appropriate.
- matchagaucho 9y agoIt's possible to do Functional Programming with an OO language these days using anonymous methods/Lambdas. The GoF patterns either need updating or perhaps we're on the verge of calling this hybrid environment something completely different (?)
- amag 9y ago"Someone was wrong on the Internet, it was me."