C# is fine. Like if your pants have some dried mud on them but you're not going anywhere fancy -- it's fine. Every language is designed with trade-offs, leaving parts that aren't so great. There's no way around that. But C# screws other things up for no reason. And there's the terrible C# internet community.
One of the steps to being a real C# programmer is taking time to make fun of it.
new
'sPart-I of this is a warm-up. C# is an older language and
copied Java. They still uses new
to allocate space. Newer languages infer it: Cat c=Cat();
. That works since Cat is a reference type. We know what the line must do.
C# requires the slightly
longer and unecessary Cat=new Cat();
. But again,
that's fine -- it's an older language.
But this next thing is fully their screw-up. For their value-type version of class, named struct, they decided
it needs new
. It's a value-type, which can't use new
, but you have to type out n,e,w. Here Cat is a class and Dog is a struct:
Cat c1; // a reference to a Cat, currently null // create a real cat: c1=new Cat(); Dog d1; // a struct. d1 is fully allocated on the stack // initialize using the contructor: d1=Dog(); // error -- makes too much sense d1=new Dog(); // <- aarrg! This is the line
The goal was to give structs and classes the same syntax. We can declare a Dog without even knowing what structs are. But that's stupid -- attempting to use a value-type as if it were a reference-type just makes a mess. And when C#'ers learn structs
their first question is "hey, why does it use new
?"
ref
keywordHere's a C# swap function:
void swap(ref int n1, ref int n2) { int temp=n1; n1=n2; n2=temp; }
Not bad. The keyword ref
is longer than C++'s
&
, but it's fine. Now here's
a call:
swap(ref a, ref b);
Arrg! Why are those dag-nabbit ref
's required?
The function already knows they're being passed-by-reference. They make it look like the caller can choose normal or by-reference.
The purpose is probably safety. Call-by-ref is
considered an advanced C# feature that most people won't have seen. Requiring typed-out ref
's is like asking "are you sure you want this function? It uses call-by-ref you know".
C# has a shortcut for short functions. Short things don't need shortcuts. And it's only 1 word shorter:
double cube(double x) => x*x*x; // the shortcut double cube(double x) { return x*x*x; } // normal way
This is useful because ... well, it's not.
It's for people who only use lambda functions, such as A.Find(c=>c.age<10).sortBy(c=>c.name.length)
.
They aren't comfortable writing functions the normal way.
It's a stupid idea since we can already write them using
Func<double,double> cube = x=>x*x*x;
. And if you need
to write out a function, you'll eventually need a multi-line one, which "expression-bodied functions" can't do.
delegate
In C# 1.0, delegates were special typedefs. They were the only way to create a function pointer:
delegate int fct(int n); // fct is a type for an int(int) function fct f; // f is a function variable of type int(int)
In 2.0 delegate also became the keyword for creating an anonymous function. So now, besides a type, a delegate can be an object:
f=delegate(n) { return n*2; }
In 3.0 delegate
for anonymous functions was phased out. They got a new syntax and called them lambda functions. But people still called them delegates, since the old syntax still worked and made the same thing:
f= n => n*2; // a lambda function, but also a delegate
Also in 3.0 they added an immediate way to declare function types. We no longer needed delegate-as-a-type, but could still use it. How to directly declare a function type:
Func<int,int> f = n => n*2; // f is an int(int) function pointer
So now we've got delegate
as an alternate way to define a type, or an obsolete syntax, or a general description of an anonymous function. That makes reading the docs oh so much fun.
These are long ways to create something which is in every way identical to a public variable:
class A { public int n1; // a normal variable // an automatic property doing the exact same thing: public int n1 { get; set; }
They were created to solve an old linker bug. When you change a public variable into a property it should be seamless, but you have to remember to recompile the clients. The "fix" was to never do that -- never turn a variable into a property. Instead, start everything as a property. Clever right? After that it turned into a weird superstition. Everyone wrote every variable out as a pass-through do-nothing property:
int _n; public int n { get {return _n;} set(_n=value;}}
That's tedious. Microsoft could have said "hey, it's safe to declare public variables now". Instead they created a shortcut so you can appease the god of useless properties in fewer keystrokes.
In C++ you have to add virtual
in the base class. In Java you don't do anything at all. In C# you not only
write virtual
on top, you need to add override
everywhere else. If you don't, that one function isn't virtual. This is so you can write a subclass, decide not to override a virtual function, and then say "my boss The Joker wants me to write a normal function with that same name".
As a bonus, same-name-but-not-an-override functions are
supposed to have new
in front of them. Sure, let's
re-purpose a completely unrelated keyword for this.
It's to avoid a very specific oddball problem. Suppose you have a base class and users have already written subclasses. Then you add a new virtual function, in your base class, which accidentally shares a name with a normal function a user added to their subclass. The user's function would mistakenly, with no warning, become the override. But with C#'s fine-grained rules it won't.
That could happen, but hardly seems common enough to justify torturing us to avoid it.
Now we're onto a different but equally annoying part of C#. Trying to look things up. Searches find the worst blogs, or the awful microsoft site. Every language has a certain amount of annoying, outspoken clowns, but C# is extra clowny
The desciption of even the most minor feature starts with several paragraphs about how great it is. If C# was a hardware store and started selling yellow nails, the manual would start out explaining how this new technology allows us attach boards together. It's impossible to find out what anything actually does or why it was added.
The var
keyword is for a very specific special case. But it's new, so naturally every example of everything
uses it. It's all that way. Every example has every new feature inappropriately
ram-rodded in, making them impossible to read. Especially since
checking the manual simply says "they're great!"
The standard way of writing a C# class is to choose your internal variables and expose every single one as a property:
class Widget { int privateVar1 { get; set; } string privateVar2 { get; set; }
Their reasoning is that the sole rule for OOP is "no public variables". They don't understand the part about hiding the
implementation details. They don't know that making variables
private
is meant to accomplish something. Their OOP begins and ends with "no public variables".
If you don't know what information hiding is, or course you
don't understand interfaces. But C# makes it better, then worse. C# uses interface
as a keyword for a fully-abstract class. This confuses C#'ers. To them, an interface means something clearly labelled "interface". Classes don't have
interfaces because -- no interface keyword.
The weird thing is that they correctly understand the
interface concept for the things that say interface
.
They understand that clients are supposed to only look at those
functions, ignoring implementations. They just can't transfer
that idea to writing a class.
A C# convertion is to start all interface
's
with a capital I. That way you can tell them apart from normal
classes. But there's no reason we should care. Consider a function
which clearly takes subclasses as input:
void doStuff(Animal a) { a.eat(); ... a.sleep(); ... }
Animal could be a base class, or an interface. a.eat()
will be found by the same rules either way.
That stupid "I" prefix makes you think C# interfaces aren't fully interchangeable with abstract classes. But they are.
For real, structs are easy. Even C# structs. They're simple value-types. But languages with reference types are taught a certain way which makes structs difficult to understand.
Firt they learn forms like Car c=new Cat; c.name="steve";
. Then that Cat cp=c;
acts as a pointer. And that's enough for most things.
After that, it's difficult to explain why you'd need structs. They're only a speed trick. As to the implications of "value-type classes", C#'ers don't have the background yet. Structs are where they learn heap, stack and formal pointer theory, all at once. Effectively. structs in C# are very complicated.
If you're a native C# coder wondering how structs could ever not be complicated, here's how: First learn ints, doubles, and strings. Then learn structs. Now you're thinking "but you need references to write a useful program". That's right. We learn the basics using simple programs, then learn how references work and we're ready to go. It takes longer to be a semi-useful programmer, but the end result is better.
C# programmers think of everything as it's own
thing. They think while
, for
, do-while
and foreach
are different. They
don't realize they're all just loops with small tweaks.
Everything is like that. They'll explain a minor change from the ground up, paragraphs and paragraphs until near the end you realize "oh, it's alternate syntax for doing X".
In C# you rarely need call-by-reference. That's because you pass around classes, changing the contents through the copied reference. That's good enough for most things. They only need call-by-reference for oddball special-cases.
But when they get to it, they already have a firm idea of what "reference" means. They've been saying reference variable and get a reference for a long time. They can't see "call-by-reference" without imagining a reference variable, which that is not. The microsoft C# site even once got it confused, saying reference variables are always passed by reference (no, that's not true).
As we know, call-by-ref has two common forms: parameters as input-output,
or as output-only. C# formalizes this with keywords ref
and
out
. They get slightly different rules -- it's actually quite clever. For example out
variables
don't need to be initialized and can't be read from.
C#'ers learn these as 2 similar but unrelated features. They don't understand the underlying mechanism is identical -- a hard link back to an L-value.
This is just a general complaint about any language using
refertnce types. You can't tell the difference between an owner
and a reference. In C++ you write Cat C[10]
for an
array of 10 Cats. You clearly own them, since they're in you.
An array of 10 links to other cats is Cat* C[10]
.
These are clearly links to cats we don't own, otherwise we wouldn't
have needed to turn them into pointers.
Meanwhile in C# everything is Cat[] C=new Cat[10];
.
We can't tell if it's intended to own 10 Cats, or merely link
to someone else's. And since there's no syntax for it, it's difficult to talk to C# coders about the difference.
The point of properties is creating virtual variables in a nicer way than
getter/setter functions. We may store the angle in degrees, but offer p1.radians=5
as a property, nicer than
the alternative p1.setRadians(5)
.
But C# coders love properties and can't resist using them for more complex operations that always cause problems.
They'll have r1.lowerLeft=5;
as a property changing several other variables. When we get a bug it takes extra-long to realize "oh, that's a function call". If you'd write it like a normal person: r1.setLowerLeft(5);
we've have fewer problems.
Comments. or email adminATtaxesforcatses.com