Qualm before the sharp.

(Forgot to ‘Publish’ this on the weekend. Re the title: I have no idea…)

I like C#. There. I said it.

It blends the feeling of a scripting language with the power of C/C++. Thanks to Mono, it also has some portability (at least, as far as the scripting bit goes).

In some ways its more like Java than C++. Luckily for me, usually in areas that I actually like about Java (such as interfaces, etc). I also tend to find that things that bothered/bother me about C++ are tackled in C#.

While I’m still a C# greenbelt, I can already see some fairly annoying facets, though.

First, foremost and pettiest:

Namespaces

(think: domain names for program components; the operating system’s I/O functions are in the System.IO namespace). What great pearl of wisdom am I about to unleash about the badness of C# namespaces? Sorry :( It just bothers me that they’re not implicit. Instead, you have to explicitly wrap your code in namespace delcarations:

namespace Foo
{
  class Bar
  {
    ...
  }
}

I’d actually like to see automatic namespacing based on the path and filename:

  Behavior.cs
    namespace  Behavior
  Behavior/Foo.cs
    namespace  Behavior/Foo
  Behavior.Internal.cs
    namespace  Behavior
  Behavior/Internals.csp  (note '.csp' for C Sharp Partial)
    namespace  Behavior

Typedef/aliasing.

C# tries very hard to improve the signal:noise ratio by cutting down lots of boilerplate stuff. But this is one area where it seems actually backwards.

When working with templated stuff (generics), you can get some rather unwieldy resulting types.

Dictionary<string, List<Dictionary<SomeNamespace.SomeSubSpace.SomeType, int>>>;

And now if you want to use one of these:

Dictionary<string, List<Dictionary<SomeNamespace.SomeSubSpace.SomeType, int>>> foo = new Dictionary<string, List<Dictionary<SomeNamespace.SomeSubSpace.SomeType, int>>>,string>();

UGH!

The var keyword helps:

var foo = new Dictionary<string, List<Dictionary<SomeNamespace.SomeSubSpace.SomeType, int>>>,string>();

You may be able to use the “using” statement to locally perform an alias

using System;
using System.Collections.Generic;
// To do it here, you have to write:
// using YourDictionary = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<System.Collections.Generic.Dictionary<SomeNamespace.SomeSubSpace.SomeType, int>>>;

namespace Foo
{
  using YourDictionary = Dictionary<string, List<Dictionary<SomeNamespace.SomeSubSpace.SomeType, int>>>;

  class Bar
  {
     ...
  }
}

But you have to do this in every module that uses the type; if the complex type is actually something required by an external or 3rd party module, then this is gonna get quite annoying, and it’s gonna suck donkey balls when the API changes and you have to go changing them all.

When you are dealing with a type or structure that you need to understand with some clarity, fair enough. It might pay to know exactly what you’re dealing with, and be exposed to the changes when the type changes.

And the argument that you should use encapsulation to hide such details when the user doesn’t – fair logic, but the amount of text required to implement such an encapsulation is ridiculous.

What you really want is…

typedef TInnerDict = Dictionary<SomeNamespace.SomeSubSpace.SomeType, int>;
typedef TListInnerDict = List<TInnerDict>;
typedef TYourDictionary = Dictionary<string, TListInnerDict>;

Which the code responsible for introducing the type can include, providing a method of interchange (TYourDictionary).

Perhaps a mechanism based on the “sealed” keyword to let you create a typename for exchanging references.

C# developers are likely to point out that the need to deal with such unwieldy type names is an indication of bad programming: Yeah, well I had to use the whole DataView hierachy in my “hOm” project, and I had to use tons of those god awful long things which just begged for a typedef. Maybe I’ll refactor them as aliases.

While this is technically cosmetic, it has the knock-on effect of breaking encapsulation. Yes, you probably *should* encapsulate your non-trivial types if you are exposing them outside of your own scope. But then it should be easier to do that.

I’ve used fancy complex examples upto now. But lets use a simpler example.

3rd party function:

  public bool ProcessSettings(ref Dictionary<string, int>)
  {
  ...
  }

Your code:

  class Setting
  {
    // This just happens to be the same format
    // as the 3rd party setting thing uses.
    public string Key { get; set; }
    public int Value { get; set; }
  }

  public bool ApplyNewSettings()
  {
    // Our settings are stored in our own format,
    // so we have to translate to 3rd partys format.
    var settings = new Dictionary<string, int>();
    foreach (Setting s in Settings)
    {
      if ( IsGlobalSetting(s) )
        settings[s.Key.ToString()] = Convert.ToInt(s.Value);
    }
    3rdParty.ProcessSettings(ref settings);
  }

The 3rd party code really isn’t going to create an entire class just to abstact Dictionary. But when they come along a year from now and change their settings type to Dictionary … I have to go plowing through my code. Ugh.

I’d much rather have some typedefs I can work with.

class Setting
{
  // Model our Setting type after the 3rdParty setting type
  // by using their typedefs.
  public 3rdParty.TSettingKey Key { get; set; }
  public 3rdParty.TSettingValue Value { get; set; }
}

public bool ApplyNewSettings()
{
  // Our settings are stored in our own format,
  // so we have to translate to 3rd partys format.
  var settings = new 3rdParty.TSettings();
  foreach (Setting s in Settings)
  {
    if ( IsGlobalSetting(s) )
      settings[s.Key] = s.Value;
  }

  3rdParty.ProcessSettings(ref settings);
}

New. New. new new new new newnewnewnew.

C# likes to boast that it largely eliminates the need for dealing with pointers. This is somewhat true. They’re actually still there, but the semantics and syntax of the language generally avoid your need to worry about dereferencing them.

  // C++: Create a Window right now, on the stack,
  // that is valid until the end of this scope.
  Window  concreteWindow;

  // Allocate a longer term Window object that
  // will remain in memory until released.
  Window* windowPointer = new Window();

  // As above, but use a "reference" so that we
  // can refer to it just a concrete Window.
  Window& windowReference = *(new Window());

  // Dereferencing a "value" (stack based) window
  concreteWindow.Show();

  // Dereferencing a pointer:
  windowPointer->Show();

  // Dereferencing a reference:
  windowReference.Show();

The fact that C and C++ still force you to use “->” for pointers instead of “.” is just 50% asshat- and 50% dick- ishness. The distinction allows you to do some unhealthy, unecessary and ridiculous things, that really don’t warrant the general benefit to mankind that just allowing “.” in all cases would be.

C# aims to let the programmer ignore this distinction between concrete and reference types. Except it doesn’t.

  throw new IOException("Out of disk space for more 'new's.");

And so begins the newfest. It seems to be amongst one of the most common keywords in every piece of C# code I’ve looked at.

Some folks suggest it’s there as a hand-me-down to migrating C++ programmers that they are creating persistent objects. That can’t be right, because C# garbage collects, so it doesn’t matter. I’m not accepting the legacy argument, sorry.

Infact, C# programmers seem to ‘new’ in excess, many not realizing that simple constructs like the following are possible under some rare circumstances:

  int[] ints = { 1, 2, 3, 4, 5 };
  string[] strings = { "hello", "world" } ;

and instead, you find code calling ‘new’ to allocate these arrays … just to be safe.

The thing that really gets me about this is the need to say

(* the introduction of the ‘var’ keyword is not pertinent here)

  Object bob = new Object("bob");

C’mon. What’s with the damn duplication?

Why can’t I just say

  Object bob("bob");

Needing the type on both sides is worse than dumb (duplication); the “var” keyword reduces the amount of code typed but really just emphasizes that this problem exists while trying to sweep it badly under the rug.

  var bob = new Object("bob");

IMO this is a misuse of implicit typing achieved by var; “bob” is really a strongly typed object. The only reason it needs ‘var’ is because the reference/pointer/value distinction we’re supposed to be saved from … is in the way.

One of the arguments for why it’s this way is that you might want to do the following:

  Object bob;
  ...
  ...
  ...
  if ( user == 'bob' )
    bob = new Object("Sir Bob") ;
  else
    bob = new Object("bob") ;

That … is a terrible argument for the case. It’s a -compiler- error in C# to use an unassigned variable, so the following code would not compile:

  Object bob ;
  if ( user == 'bob' )
    bob = new Object("Sir Bob") ;
  else if ( user == 'kate' )
    bob = new Object("Mrs Bob") ;
  Console.WriteLine(bob.Name) ;

And C# tries to save us from the whole “NULL” thing that exists in C/C++ by requiring you to explicitly state that a variable can have the null value.

What the programmer is really trying to say is:

  private string NameToUse(user)
  {
    if ( user == 'bob' )
      return "Sir Bob" ;
    else if ( user == 'kate' )
      return "Mrs Bob" ;
    else
      return "bob" ;
  }

  ...

  Object bob(NameToUse(user));

or possibly some better way of doing conditional assignment:

  string bobname = switch(user.Name)
  {
    case 'bob': "Sir Bob";
    case 'kate': "Mrs Bob";
    default: "bob";
  }

  Object bob(bobname);

On the whole…

I do like C#, and before you go burning “portability flags”, I’ve actually used C# to write several odds and ends under Linux with Mono. MonoDevelop isn’t quite Visual Studio but it’s pretty damn close. The more recent the version, the more pleasant it is to work with.

As with my recent rant about Python, I’m really focusing on what has irked me about the language thus far. There are plenty of reviews and fanboi sites out there if what you want is to hear what’s good about the languages.

I’ve already pretty much completely switched from Perl scripting stuff to using Python these days, and I’m probably converted to C# for any personal significant projects I work on.

But I think I’m gonna have to start the slow process of plotting out my own language.

5 Comments

You’ve pretty much hit the nail on the head with complex types. Look at it this way, at least if that’s the worst that cheeses you off about C# then that’s a pretty good endorsement :)

With regards namespaces though, I admit to being a little unclear about the lack of relation to something akin to classpath.

I’m putting it largely down to my lack of C/C++ experience and general Java rustiness potentially hindering my perspective, from my point of view I normally don’t have to worry about namespacing day-to-day.

Sure, the namespace is mentioned in the class, however this is primarily to allow you to override the namespace. Normally the space is derived from the assembly and internal folder structure automatically by the IDE (VS or MD).

By default if you have an assembly project called Foo, you create a folder in the IDE called Bar where you then add a Bob class, you end up with the IDE inserting a Foo.Bar namespace into the Bob class (accessible via Foo.Bar.Bob).

This namespace matches the physical folder structure in your project in both VS and MD (e.g. ~\Foo\Bar\Bob.cs).

Is this the kind of classpath style convention you’re looking for?

Yep – I can understand why you might not want enforced classpathing, and I’m ok with it not being there, but I don’t think we can’t have our cake and eat it here…

I learned to loathe data duplication very early in my coding career. What irks me is that you wind up with every C# source file in a well-formed project looking like this:

using System;
using ...;

namespace SameAsFileNameOrParentFolder
{
    class Something
    {
        public Something() // Default ctor
        {
            // Wait, this is my first line of code
            // and I'm 3x indented?
        }
    }
}

And to me, for well formed code, there’s a lot of redundancy going on here. I understand that with partials and etc, things can start to get spread out, and it’s nice that you can do that. But having mandatory explicit names requires additional management and – imo needless – boilerplate code. Tip of the hat to Visual Studio’s developers for tackling this with automation (generally if you rename one of the fields, it’ll offer to go refactor your code for you).

But that can be potentially bad – there’s a chance for error there.

I think they could add optional support – perhaps defaulted – for classpath support, so that a well formed project “Foo” in namespace “Foo” might look like this:

  Foo/
    Bar.??? <-- Defines namespace Foo { class Bar }
    Baz.??? <-- Defines namespace Foo { class Baz }
    Bob.cs <-- This could define anything it wants.
    Snafu.??? <-- Defines namespace Foo { partial class Snafu }
    Snafu.Internal.??? <-- Defines namespace Foo { partial class Snafu }
    Snafu.MoreStuff.??? < -- Defines namespace Foo { partial class Snafu }
    Net/
      Zap.??? <-- Defines namespace Foo { namespace Net { class Zap } }

I’ve used ??? because maybe C# 5.0 could add extra extensions. E.g. “.cs” continues to require explicit naming, but maybe “.csc” for csharp class, using implicit namespacing.

Foo/Bar.csc:

using /*...*/ ;
// namespace Foo: implicit, from path.
// class Bar: implicit, from path.

public Bar()  // This is actually Foo.Bar.Bar()
{
}

public string ToString() // Foo.Bar.ToString()
{
...
}

Foo/Net/Zap.csc

using /*...*/ ;
public Zap()  // This is actually Foo.Net.Zap.Zap()
{
}

public string ToString() // Foo.Net.Zap.ToString()
{
...
}

In these cases, the namespace and class names are described in the project/IDE, rather than being described twice.

With the current, non-classpathed system, if you want to know what namespace and class are in Foo/Net/Zap.cs, you have to open it and look, only to discover that it actually describes Lib::World::IRC.

– Oliver

If you like C# and like Python, you will love IronPython:
http://www.ironpython.net/

And I agree with you on most of your points and in my opinion there are even some more, but I also like that language. Anyway, there won’t be any language on this planet, which won’t have something you don’t like. There is no perfect language, unless you create your own baby :)

I’m looking forward to giving Iron Python a fair go when I’m done with the Pro C# book.

Re: “Object bob = new Object(“bob”);”

It’s useful for polymorphism. You may need a stack pointer (left side) of a more generic type but the heap variable of the more specific sub type for later. Sure, though it’s redundant 99.9% of the time. It makes more sense when you want to do this: “Person bob = new Employee(“bob”);” where Person is a supertype of Employee.

Leave a Reply

Name and email address are required. Your email address will not be published.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

You may use these HTML tags and attributes:

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <pre> <q cite=""> <s> <strike> <strong> 

%d bloggers like this: