The Software Purist |

CAT | C#

Jun/11

19

Conditional Compilation in Java

I wanted to share a trick I learned a while back, that is pretty useful. Personally, I’m not a fan of including code in your executable/bytecode that is never used, because it has the risk of exposing additional implementation, and generally makes for larger DLLs/Jars. One nice thing I can say about C# is that they did not completely remove the idea of conditional compilation. In C#, you can do the following:


#define LETS_DANCE

...

#if LETS_DANCE
// ... do something ...
#endif

However, C#’s conditional compilation is completely restricted to only being able to define a boolean, where the existence of the preprocessor symbol means it exists, and otherwise, it doesn’t. Makes sense. Conditional compilation without all the nasty misuses of them you see in C++ programs. Seems to be the best of both worlds and an obvious leg up on Java, right?

Well, actually not really. Turns out that Java has supported something similar since day one, also. In Java, the equivalent is this:


public static final LETS_DANCE = false;

...

if (LETS_DANCE)
{
// ... do something ...
}
#endif

Why is this guaranteed to work and not include the unreachable code? Turns out there is an important note in Java. Java will not output code that is obviously unreachable. To be obviously unreachable it needs to be known at compile time as a static final constant variable. So, there you go. Definitely a useful thing.

· ·

Dynamic is a new keyword that was introduced in C# 4.0. Thankfully, it hasn’t gotten a ton of press, but I can see it paving the way for all sorts of new types of abuse. By now, you’re probably familiar with my thoughts on the var keyword. Dynamic takes this one step further, by dynamically binding the class type at runtime, and determining if method calls are legal, also at runtime. Here’s an example:


public void MyMethod(dynamic param)
{
param.Call();
}

So, let’s say you pass in an instance of a class which has the method named Call. All is well, Call() will be called, albeit with a performance penalty.

Now, consider what happens if you pass in an instance of a class for which Call() doesn’t exist. It will, instead, throw an exception, which essentially states that Call() doesn’t exist for this type.

So, what’s the problem? Very simple. You’re taking a situation where you can enlist the compiler’s help, and instead pushing it off to runtime, which entails discovering it later than necessary, in some cases, much later. This increases risk and potentially increases the time to fix, since we know that at each stage later that a bug is discovered, the more expensive it is to fix. Problem 2 is that there is absolutely a performance penalty. In a lot of cases, these penalties are no so noticeable, but spread out through an entire application, they can make a serious impact. I have seen poorly written C# applications which made both heavy and improper usage of reflection that easily can operate an order of magnitude slower than well-written one which takes advantage of the type system.

Avoid dynamic in most cases. Use it for cases where it really matters. If you find yourself needing a lot of dynamic behavior, you are more well-suited to using a scripting language like Python or Ruby, where the syntax will be much cleaner and you don’t risk so much paradigm mix, therefore creating more understandable code. Otherwise, if you’re determined to use C#, then use it as the type-safe language that it can be, and don’t treat the type-system as optional, even if Microsoft got overzealous in feature overload.

What’s the solution? Instead, make the method look like this:


public interface ICall
{
void Call();
}

public void MyMethod(ICall param)
{
param.Call();
}

Using generics is also a possible solution. Just remember that when you violate the type system, you are losing the advantages of using a type-safe language.

No tags

Jan/11

24

Var/Auto is Ugly and in Some Cases, Downright Evil.

In this post, I’m going to describe a set of keywords, which effectively serve the same purpose. In C#, there is the var keyword. In C++, there is the auto keyword. Effectively, what they let you do is to automatically inter the type of a variable from the context on the right hand side. Here’s an example, in C#:


var myVar = new MyClass();

and an example in C++:


auto myVar = MyClass();

The problem I have is, while this allows you a tremendous amount of flexibility, in saving redundant typing, it also potentially nullifies some of the benefits of using a language which supports type safety, because you can do some pretty nasty things which destroy the readability and can potentially introduce some subtle bugs. Worse still, tools like Resharper encourage, potentially poor usages of var. Here’s another example of the var problem:


var myVar = new MyClass().DoThis().DoThat().DoSomethingElse().NowGet();

Ok, what’s the type? Don’t know? Me neither. I find this problematic. As such, as I’d like to establish some guidelines for better usage of var/auto, taking some common use cases. I’ll probably switch back and forth with examples from C++ and C#, just to illustrate the point. Here we go:

1) Usage case 1:


var x = new Y();

I consider this usage a minor evil, even though some like it a lot. Here’s my major problem: You have type inference on the wrong side. The point of using a language which supports type safety, is, well, you support the type system and let it help you. If you don’t want that, may I suggest a language that is dynamically typed? It would be nice, if var, instead worked this way:


Y x = new infer-this-type();

As a general rule, we would prefer to infer the type that’s on the right hand side, not the left. This feature is not available in a lot of languages, so for now, I would simply suggest not using var. Go with the old:


Y x = new Y();

2) Usage case 2:


var x = GetY();

Again, with this one, I prefer not to use var, for the same reason as before, with an added caveat. First, of all, you should avoid using var to avoid typing a simple type. Secondly, you can’t even figure out what the type is from reading the code. Not good. On a scale of 1 to evil, I consider this a significant evil.

3) Usage case 3:


for (typename std::vector::const_iterator iter = container.begin(); iter != container.end(); ++iter)
{
...
}

Becomes:


for (auto iter = container.begin(); iter != container.end(); ++iter)
{
...
}

In this case, I can justify using var/auto, so I consider using auto a minor evil. However, C++ has a better mechanism for doing this. It’s called typedef. For example:


typedef typename std::vector::const_iterator MyIter;

for (MyIter iter = container.begin(); iter != container.end(); ++iter)
{
...
}

So, in C++, I have trouble finding ANY usage, where I really like auto. However, in C#, there is no typedef, so I’m fine with usage of var, in the case of complicated nested classes.

Conclusion

Concluding, as you figured, I don’t like the usage of var or auto much. In a lot of cases, it is a minor evil. However, there are some major concerns: Readability and subverting some of the redundant checking that the type system supports. In C#, it is sometimes useful to save a lot of typing, due to the lack of the typedef keyword, while in C++, it is rarely useful. In a future article, I will tackle C#’s dynamic keyword, which I dislike far more than var. Stay tuned.

· · · ·

I was interviewing a candidate recently, and we were talking about some of the programming languages he claimed to know, which was mainly focused around C++ and C#. We started to discuss some of the types of problems he finds easier to solve in each when he said something I found very misleading: “A programming language is really just syntax”. As we talked more, I started to ponder what a shallow understanding of a language this really was. It’s kind of like questioning whether a dollar is a dollar is a dollar. Smart financial people know that the source of the dollar is very important, and so the utter simplification is misleading.

Before I get too far into this, I will note that if you’re using .Net, you can get a lot closer to making the premise of the initial argument, because the .Net languages all can support the same APIs. That wasn’t the case for this individual, as he was using C++, not C++/CLI. With that being said, let’s get into some of the real substantial differences:

1) The standard libraries that the language supports. I find this to be one of the most underrated aspects of working with a language. I think part of the reason is that when you use some languages (C++) there’s a large population of programmers who don’t really make good use of the standard libraries. In my experience, this is often because they sometimes fall into using non-portable APIs, such as Microsoft’s ATL or MFC instead of STL containers, or libraries that may be considered more suitable for an embedded environment. Anyway, I think this is a critical feature, because, again consider the example of C++: Something as commonly used as XML is not standard. This is almost unfathomable for programmers of languages like Java or C#. Meanwhile, the flipside is .Net, which is immense and becomes very difficult for a developer to be proficient in all of it.

2) Third party libraries the language supports. I would consider this almost as important as the standard libraries issue. Unlike the standard libraries, there’s a much better chance that the third party libraries have API interfaces to be used in multiple languages. This will be one of the the top things you would consider when choosing the appropriate language for a task.

3) Language Paradigms: This is another feature which gets underrated at times. Does the language properly support Object-Oriented Programming? Template Meta-Programming? Functional? How easily does it support multi-threading? Again, all of these are critical differences between languages which go well beyond syntax.

4) Static Typing or Dynamic Typing or Both (coughC#cough)? With static typing, you can potentially find a lot of structural errors during compile time and need less code coverage during your unit tests. With dynamic typing, you don’t have these luxuries, but have much better support for rapid development.

5) The tools that are supported for your language.

6) Syntax. I consider this one of the least important differences between languages. It’s very easy for a professional programmer to adjust to a new syntax, assuming it isn’t completely nonsensical.

In the end, I think of this like deciphering any sort of spoken or written language. At the end of the day, if you aren’t able to communicate effectively, then your words are meaningless. This goes far beyond sentence structure. When discussing programming languages, it goes far beyond syntax.

· · · · · · · · ·

Theme Design by devolux.nh2.me