Live data from Hacker News

I was wrong, reflecting on the .NET design choices

ayende.com

111–120 of 139 posts

Re: I was wrong, reflecting on the .NET design choices

#111
post #27

Earlier quoted context omitted.

>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 deba…

We use regions to standardize the layouts of our classes. Except for trivial classes, you will find the same regions in the same positions making it eas(ier) to find, for example, all methods implementing an interface, or all of the private helper methods.

Regions are just useless visual clutter most of the time. You can put the methods/fields in the same order without using the regions. In my experience regions are a very bad practice used only to mask bad design that produced gigantic classes. The only place where I think they may be helpful is when you are writing a library and your class must be huge because you are implementing for example a Trie or some other collection or some other object pretty complicated that doesn't make sense to divide in smaller classes. And even in that case I would first try really really hard to split it in smaller entities rather than just having a thousands lines class with some regions around.

Re: I was wrong, reflecting on the .NET design choices

#112
post #72
post #70

Earlier quoted context omitted.

It's getting easier with every release to not allocate, with things like ref returns and locals[1] and new types like Span [2]. I think there are more things like that coming in the pipeline[3]. [1] https://github.com/dotnet/roslyn/issues/118 [2] https://github.com/dotnet/corefxlab/blob/master/docs/specs/s... [3] https://github.com/dotnet/roslyn/issues/10378

Here's a comment that mirrors my own thoughts, from the comments on that third link[1]: "C# heap allocations aren't expensive and are faster than C/C++. They are even faster than stack allocations (if the stack alloc is too large to be a register) as the stack needs to zero out the memory first; whereas the heap has done this ahead of time. However, they do come at a cost, which is deallocation. C/C++ have both an al…

Yes, someone always brings up the fact that alloc/dealloc isn't free in any language. But that doesn't change the particular animosity between real-time and GC. Manual is like a flexible payment plan. GC is a debt-collector appearing at your bathroom window while you're on the can.

Re: I was wrong, reflecting on the .NET design choices

#113
post #53
post #8

Earlier quoted context omitted.

I'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.

That's where every Visual Studio dev will see them used, because it's been a VS pattern since the beginning. But I create them manually often enough. Overall I use them sparingly, but there are cases where you definitely want a set of things in one class for code-organization, but still want to think of them as different modules for human-organization.

If you want to think of them as different modules then most likely they should be completely separated entities. Why on earth you would want something completely different to live in the same class? It is just screaming that it wants to be a separate class. Namespaces are the correct tool for code organisations, certainly not partial classes.

Re: I was wrong, reflecting on the .NET design choices

#114
post #104
post #99

Earlier quoted context omitted.

You are right that the type system waters are muddied by a variety of technologies and perhaps that isn't the best line to draw. I think your focus on the semantics of static vs dynamic dodges much of my point. The crux of my argument was the larger and more complex the work the more important it is to find errors early. It seems obvious to me that languages like Java, C++ and Rust do much more to catch errors early…

This is why I think workflows matter too, at least as much as the language itself. If you write Python like you write Java, of course you're going to not catch some errors that Java would have caught before you ship, and you're probably going to be frustrated when you're at a company where everyone writes Python like Java. But if you write Python like Python (you can't write Java like Python), you'll find many of you…

The type system is your friend, not your enemy. You are comparing the type errors to the null pointer exceptions, aka the billion dollar error. You can have an extremely powerful type system, with very low ceremonies, that checks continuously that you are not shooting your foot AND having a REPL. For example using F#. Your code will be extremely expressive and creating DSL can be a breeze, with the huge benefit that even your DSL will be type checked at compile time.

Re: I was wrong, reflecting on the .NET design choices

#115
post #53
post #8

Earlier quoted context omitted.

I'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.

That's where every Visual Studio dev will see them used, because it's been a VS pattern since the beginning. But I create them manually often enough. Overall I use them sparingly, but there are cases where you definitely want a set of things in one class for code-organization, but still want to think of them as different modules for human-organization.

I did that once where I had a complicated class with a docile public API that controlled a not so docile long running threaded 'machine' of sorts. Having them in two files made thinking about stuff easier.

Re: I was wrong, reflecting on the .NET design choices

#116
post #53

Earlier quoted context omitted.

That's where every Visual Studio dev will see them used, because it's been a VS pattern since the beginning. But I create them manually often enough. Overall I use them sparingly, but there are cases where you definitely want a set of things in one class for code-organization, but still want to think of them as different modules for human-organization.

If you want to think of them as different modules then most likely they should be completely separated entities. Why on earth you would want something completely different to live in the same class? It is just screaming that it wants to be a separate class. Namespaces are the correct tool for code organisations, certainly not partial classes.

It's very interesting that you were able to see my use cases and come to this conclusion...

Re: I was wrong, reflecting on the .NET design choices

#117

Earlier quoted context omitted.

While it's true that Swift and Rust don't unwind the stack, this is just an implementation detail. The comparison to Go is very misleading. Neither Swift nor Rust require you to return a value on error like Go does, nor do they allow you to simply ignore errors. The semantics, not the implementation, is what matters. Swift's error handling is not "syntax sugar." try/catch in Swift are not macros that desugar into nor…

I have absolutely no experience with Rust, but I know it normally depends on libunwind, isn't that for unwinding the stack?

Perhaps to implement https://doc.rust-lang.org/std/panic/fn.catch_unwind.html

But also just to display traces on asserts/panics, even if not "unwound" per se.

Re: I was wrong, reflecting on the .NET design choices

#118
post #104

Earlier quoted context omitted.

This is why I think workflows matter too, at least as much as the language itself. If you write Python like you write Java, of course you're going to not catch some errors that Java would have caught before you ship, and you're probably going to be frustrated when you're at a company where everyone writes Python like Java. But if you write Python like Python (you can't write Java like Python), you'll find many of you…

The type system is your friend, not your enemy. You are comparing the type errors to the null pointer exceptions, aka the billion dollar error. You can have an extremely powerful type system, with very low ceremonies, that checks continuously that you are not shooting your foot AND having a REPL. For example using F#. Your code will be extremely expressive and creating DSL can be a breeze, with the huge benefit that…

That's my point, all that is in favor of F#, not static typing in general. I'm not opposed to type systems -- Lisp's is particularly nice, I like Nim's -- but having static types or not isn't enough of a clue that such a language really is suitable for large systems or can catch/prevent worse errors quicker.

Re: I was wrong, reflecting on the .NET design choices

#119
post #56

Java 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 l…

As a low-level game dev, I consider C# a nearly perfect, wonderful language, tragically self-defeated by garbage collection.

As a game developer having used C# for two large scale projects, I can tell you that the garbage collector was the least of our worries.

Just be a good citizen and don't trash like crazy and the GC will never block in the action phase.

Also, don't use the default mono GC, that one is terrible.

Re: I was wrong, reflecting on the .NET design choices

#120
post #116

Earlier quoted context omitted.

If you want to think of them as different modules then most likely they should be completely separated entities. Why on earth you would want something completely different to live in the same class? It is just screaming that it wants to be a separate class. Namespaces are the correct tool for code organisations, certainly not partial classes.

It's very interesting that you were able to see my use cases and come to this conclusion...

Regardless of the use case this is what the official documentation says about namespaces:

The namespace keyword is used to declare a scope that contains a set of related objects. You can use a namespace to organize code elements and to create globally unique types.

And about partial classes:

There are several situations when splitting a class definition is desirable: When working on large projects, spreading a class over separate files enables multiple programmers to work on it at the same time. When working with automatically generated source, code can be added to the class without having to recreate the source file. Visual Studio uses this approach when it creates Windows Forms, Web service wrapper code, and so on. You can create code that uses these classes without having to modify the file created by Visual Studio.

As you can see partial classes are not the right tool to organise code.

Post reply on HN