Duck typing in C #

Marek Sirkovský
4 min readOct 31, 2016

What is a duck typing?
Every programming language and runtime has some way how to process a “type check.” You can refer any typing system as static or dynamic and weak and strong. For example, C# uses strong static typings and javascript is traditional dynamic weak language.

Nice and short explanation of static, strong, dynamic and weak typing can provide this answer on Stackoverflow.

In this blog spot, I would like you to show duck typing(better term is a structural typing) in C# and emphasize that it is not a good idea to use it in this language.

So what is the Duck Typing?
The origin of the term Duck Typing is referred to the phrase of James Whitcomb Riley:

“When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.”

Imagine you have this class(please note that this code you can’t compile in C#):

If the C# were duck typed language, it would be perfectly valid code. Class Test1 and Test2 share the same method SomeMethod with the same signature. So we can say the class Test2 looks like Test1 so this class can be put into the method “Process” instead of class Test1.
It is the “essence” of duck typings. Types are checked by their similarity, not by their names.

So you may ask how this is related to C#? Everyone does know that C# is static strongly typed language.
Yes, you are right, but there is always some but.
Even though C# is mostly strongly typed language (leaving aside the new keyword dynamic) there are some parts where the .NET uses duck typing instead of the traditional static strong type checking.

Probably the most famous example is a method GetEnumerator. I don’t know, how about you, but I always thought that keyword foreach can only be used if the object implements the interface IEnumerable or IEnumerable (just like MSDN refers).

But it is a white lie. The foreach keyword can also be used in a situation where .your object does not implement IEnumerable or IEnumberable interface. If you don’t believe you can try this. So how is it possible?

In this case, the compiler performs a semantic analysis based on the pattern (pattern-based approach). It means that the compiler does not require class which is implementing these interfaces. The compiler is satisfied by the type which has only a GetEnumerator method.

Why?
This decision of the team that developed the compiler was made at a medieval time when C # hasn’t support generics yet. Yes, I talk about everyone’s beloved version 1.1.

If we had a classic implementation of IEnumerator, it would look something like this:

And if we used this enumerator in foreach, the runtime must unbox every value in property Current.

But if IEnumerator is implemented like this:

The compiler can use faster access to data without having to unbox. So C# compiler is created that if it sees this method it uses it.

Other examples of duck typing in C #:

Initializing a new collection by curly braces.

List<int> list = new List<int>() {1, 2};

The compiler searches for a suitable method called “Add” that takes a type specified in curly braces (additional condition is that the type must implement IEnumerable).

Using the LINQ
For example in this statement:

var from result somewhere in list1
var from b in list2
select ….

The compiler looks for a certain method SelectMany. If your type has method SelectMany, you can use this query syntax.

This approach has a huge advantage. It offers a powerful way to expand the ways you can work (not only) with collections, and there is no need to change the implementation of IEnumerable.

Another example is the keyword await. It uses duck typing you can use await on types which have method GetAwaiter. This methods return type must have methods IsCompleted, OnCompleted, and GetResult.

We see lot of useful examples of duck typing in the compiler so why Duck Typing is not useful in our applications. In my humble opinion, I think that biggest problem with duck typing is that this type check is a little liar.

For example, two classes have method Run. First class is named Human and the second is Engine. Are you sure that the method named Run have the same meaning?

Let’s see this example:

It is easy to spot that if we put an instance of the class Engine in method FastTravel we make a mistake. The term “Run” can have a different meaning in different context. In this case, duck type system can’t help us.

In OOP we can use an interface:

In this solution, we can’t make the previous kind of mistake as we make with duck type. See method FastTravel(IDrivable instance).

Another thing we need to remember that using duck typing requires a deeper knowledge of our code. Furthermore, we lose clear information about method dependencies, and also it can add significant complexity and decrease readability of our code.

I can’t help, but I believe that duck typing belongs to dynamic languages ​like javascript, typescript. I am very happy that C# has a good old strong static typing.

--

--