Live data from Hacker News

I was wrong, reflecting on the .NET design choices

ayende.com

61–70 of 139 posts

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

#61
post #49

Earlier quoted context omitted.

> Neither Swift nor Rust have exceptions, checked or otherwise. The point is that both of them have generic error types which "infect" every caller (transitively) in much the way checked exceptions do. That Rust and Swift require explicitly bubbling error values should be a point in favour of checked exceptions.

As I see it, the Rust (etc) approach avoids two problems: 1. The C problem of forgetting to check error returns. Yes, exceptions (checked or not) also avoid this. 2. The C++/Java/C# problem of exceptions being more expensive than you'd like for common error situations. .NET has sprouted alternatives like `bool tryParse(String, out int)` as a workaround, but on balance I prefer the unified mechanism. What I don't like…

> The C++/Java/C# problem of exceptions being more expensive than you'd like for common error situations.

Exceptions should not be used for common error situations! This is the prime mistake of Java which pretty much required exceptions when it should (and checked exceptions to boot).

> .NET has sprouted alternatives like `bool tryParse(String, out int)` as a workaround

I don't consider that a workaround. There is a deep semantic difference between TryParse and Parse. If you see TryParse then you know the data is expected to be invalid. If you see Parse than you know it's expected to be always valid. A good C# program should have very very few try/catch blocks (ideally just one).

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

#62
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.

Could you explain why garbage collection in your use case is a bad thing? The GC vs non-GC always fascinates me, and I have no strong opinion either way.

Also, doesn't C# have the ability to limit (or pretty much disable) GC?

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

#63
post #60
post #50

Earlier quoted context omitted.

In 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.

Not 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?

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

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

#64

While 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 virtua…

It also just happens that the MS C# compiler always emits the `callvirt` instruction for instance methods, because the language spec requires that a NullReferenceException be thrown any time a method is called on a null instance, even if none of the instance fields are used in the method.

Source: https://blogs.msdn.microsoft.com/ericgu/2008/07/02/why-does-...

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

#65
post #49

Earlier quoted context omitted.

> Neither Swift nor Rust have exceptions, checked or otherwise. The point is that both of them have generic error types which "infect" every caller (transitively) in much the way checked exceptions do. That Rust and Swift require explicitly bubbling error values should be a point in favour of checked exceptions.

As I see it, the Rust (etc) approach avoids two problems: 1. The C problem of forgetting to check error returns. Yes, exceptions (checked or not) also avoid this. 2. The C++/Java/C# problem of exceptions being more expensive than you'd like for common error situations. .NET has sprouted alternatives like `bool tryParse(String, out int)` as a workaround, but on balance I prefer the unified mechanism. What I don't like…

It's not really that innocuous. It'll cause the program to crash as soon as it's discovered that there wasn't a value where you were expecting one.

In languages with exceptions, the program will crash as soon as you try to use that value (rather than when you try to unwrap it), e.g. the infamous null pointer exception. Copying bad sample code in this case might result in code that is difficult to debug because a null value might be handed off several times before something tries to dereference it.

In languages that expect but do not enforce that you check the validity of the value (like C) you'll just get undefined behaviour that will hopefully cause your program to segfault when you try to use the value, but who knows what will actually happen? Copying bad sample code in this case will cause a security vulnerability.

Copying "bad" sample rust code (using unwrap) will cause a safe crash with maximum locality, for simpler debugging.

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

#66
post #55

Earlier quoted context omitted.

> Neither Swift nor Rust have exceptions, checked or otherwise. The point is that both of them have generic error types which "infect" every caller (transitively) in much the way checked exceptions do. That Rust and Swift require explicitly bubbling error values should be a point in favour of checked exceptions.

> That Rust and Swift require explicitly bubbling error values should be a point in favour of checked exceptions I thought the explicit bubbling was the nicest thing about error handling in Rust. It's usually just a single character ('?') that the editor can easily highlight, and nicely indicates where the operations are that might fail. I'd add that checked exceptions don't play nicely with general functional/stream…

> I'd add that checked exceptions don't play nicely with general functional/stream operations like "map" which is why Java went with unchecked exceptions for their streams api in Java 8. Rust on the other hand can handle interior failures in such functions nicely, promoting them to a single overall failure easily via collect(), using the blanket FromIterator> implementation for Result.

And Swift has a `rethrows` marker to transitively do whatever a callback does, it's equivalent to "throws" if the callback throws, and to nothing if it does not. So e.g. `map(_ fn: (A) throws -> B) rethrows` will throw if the callback it is provided throws, and not throw if the callback doesn't throw.

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

#67
post #40

Earlier quoted context omitted.

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

This 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.

Java compiles to bytecode and most implementations JIT, just like .NET. JVMs are more advanced than the CLR at optimization.

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

#68
post #56

Earlier quoted context omitted.

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

Could you explain why garbage collection in your use case is a bad thing? The GC vs non-GC always fascinates me, and I have no strong opinion either way. Also, doesn't C# have the ability to limit (or pretty much disable) GC?

[deleted]

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

#69
post #56

Earlier quoted context omitted.

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

Could you explain why garbage collection in your use case is a bad thing? The GC vs non-GC always fascinates me, and I have no strong opinion either way. Also, doesn't C# have the ability to limit (or pretty much disable) GC?

OP probably wants a Concurrent/MarkAndSweep GC rather than a Generational GC. because 16 ms is too much for game dev

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

#70
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.

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

Post reply on HN