[OT] Sharp Regrets: Top 10 Worst C# Features

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Tue Aug 18 19:04:34 PDT 2015


On Wed, Aug 19, 2015 at 01:12:33AM +0000, Adam D. Ruppe via Digitalmars-d wrote:
> I just saw this link come by my desktop and I thought it was an
> interesting read because D does a lot of these things too, and avoids
> some of them:
> 
> http://www.informit.com/articles/article.aspx?p=2425867
> 
> I don't agree they are all mistakes, but it is a pretty quick and
> interesting read.

The point about the empty statement (#10) is interesting... never really
thought about it before.

#9 is something that D (almost) gets right: it's generally a bad idea to
make <, <=, ==, >, >= individually overloadable (ahem, C++), 'cos it's a
lot of redundant typing (lots of room for typos and bugs) and most
combinations don't make sense anyway. D did the right thing by
consolidating <, <=, >, >= into opCmp. However, D still differentiates
between opCmp and opEquals, and if those two are inconsistent, strange
things will happen. Andrei's argument is that we want to support general
partial orders, not just linear orders, but IMO this falls in the "too
much flexibility for only marginal benefit" trap. I mean, when was the
last time you badly needed a partial order to be expressed by *built-in*
comparison operators, as opposed to dedicated member functions?  When
people see <, <=, >, >= in your code, they generally expect the usual
linear order of numerical types, not something else. This causes
confusion and suffers from the same problems as using + for string
concatenation.

#8: ah, the good ole controversial bitshift operators... esp. the still
unresolved controversy surrounding the behaviour of >> vs. >>> (sorry,
forgot the bug number, but it's in bugzilla).  IMO, we should ditch
these operators and use int intrinsics for the assembly instructions
instead. What's the use of built-in operators that are only occasionally
used in system code?  Something like 1.shiftLeft(2) would work just fine
in expressions, and simplify the lexer by having less token types.

I'm not sure about making a separate type for ints-as-bits, though. That
seems a bit extreme, and would almost imply that non-bitarray numbers
would have to be BigInt by default.

#7: did C# copy delegate literal syntax from D, or did D copy from C#?

#6: Hooray for std.typecons.BitFlags! :-)  On another note, the remark
about breaking code NOW rather than having to live with a flaw for the
foreseeable future of the language, surely applies to D. Sure, nobody
likes their code broken, but if it means breaking a small number of
projects today for a much better language in the future, vs. not
breaking anything today and having to live with a huge number of
projects later, I think breaking code is more worth it.

#5: seems like just syntax nitpicking... though in the case of D, the
current schizophrenic split between attributes on the left vs.
attributes on the right is another example of needlessly convoluted
syntax.

#4: D suffers from the same problem. People have complained about this,
but it was decided not worth changing. Still, it represents a hole in
the language that could have done better.

#3: thanks to foreach and ranges, I find myself only rarely needing
++/-- these days. Still, I don't see what's the big deal of having them.

#2: argh... dtors / finalizers + GC == headache. In D, this is where you
tread a veritable minefield of surprising behaviour, counterintuitive
semantics, unexpected GC interactions, and compiler bugs. Especially
when you start sticking dtors on structs, which are supposed to be
freely-copyable int-like values, which breaks a lot of assumptions in
generic template code and just cause general nuisance.

#1: D doesn't suffer from this, thanks to classes being reference types
by design.


T

-- 
Why are you blatanly misspelling "blatant"? -- Branden Robinson


More information about the Digitalmars-d mailing list