The introduction of static type checking represented an important milestone in the history of programming languages. In the 1970s, languages such as Pascal and C started enforcing static types and strong type checking. With static type checking, the compiler will produce an error for any call that fails to pass a method argument of the appropriate type. Likewise, you should expect a compiler error if you attempt to call a missing method on a type instance. Other languages that push forward the opposite approach dynamic type checking have come along over the years. Dynamic type checking contradicts the idea that the type of a variable has to be statically determined at compile time and can never change while the variable is in scope. Note, however, that dynamic type checking doesn t confer wholesale freedom to mix types, pretend ing they re the same. For example, even with dynamic type checking, you still can t add a Boolean value to an integer. The difference with dynamic type checking is that the check occurs when the program executes rather than when it compiles.
Statically Typed or Dynamically Typed
Visual Studio 2010 and C# 4.0 provide a new keyword, dynamic, that enables dynamic typing in what has traditionally been a statically typed language. Before diving into the dynamic aspects of C# 4.0, though, we need to get some basic terminology down.Let s define a variable as a storage location that s restricted to values of a particular type. Next, let s specify four fundamental properties of a statically typed language:
- Every expression is of a type known at compile time.
- Variables are restricted to a type known at compile time.
- The compiler guarantees that type restrictions on assignments of expressions into variables meet the restrictions on the variables.
- Semantic analysis tasks, such as overload resolution, occur at compile time and the results are baked into the assembly.
A dynamic language has the opposite properties. Not every expression is of a known type at compile time, nor is every variable. Storage restrictions, if any, are checked at run time and ignored at compile time. Semantic analysis occurs only at run time. A statically typed language does let you make some operations dynamic. The cast operator exists so you can attempt a type conversion as a runtime operation. Th e conversion is part of the program code, and you can summarize the semantic expressed by the cast operator as dynamically check the validity of this conversion at run time. However, concerning attributes such as dynamic and static (or perhaps strong and weak): Today they re better applied to individual features of a programming language than to the language as a whole.
Let s briefly consider Python and PHP. Both are dynamic languages, let you use variables, and allow the runtime environment to figure out the actual type stored in it. But with PHP you can store, say, integers and strings in the same variable in the same scope. In this regard, PHP (like JavaScript) is a weakly typed, dynamic language.
On the other hand, Python gives you only one chance to set the type of a variable, which makes it more strongly typed. You can dynamically assign the type to a variable and have the runtime infer it from the assigned value. Aft er that, though, you re not allowed to store any value of an inappropriate type in that variable.
Dynamic Types in C#
C# 4.0 has features that make it both dynamic and static, as well as both weakly and strongly typed. Th ough born as a statically typedlanguage, C# becomes dynamically typed in any context in which you use the dynamic keyword, such as this:
And because dynamic is a contextual keyword, not a reserved one, this still holds if you have existing variables or methods named dynamic. Note that C# 4.0 doesn t force you to use dynamic, in the same way that C# 3.0 didn t force you to use var, lambdas or object initializers.
C# 4.0 provides the new dynamic keyword specifically to make a few well-known scenarios easier to deal with. The language remains essentially statically typed, even though it has added the ability to interact in a more eff ective way with dynamic objects.
Why would you want to use a dynamic object? First, you may not know the type of the object you re dealing with. You may have clues but not the certainty to statically type a given variable which is just what happens in many common situations, such as when you work with COM objects, or when you use reflection to grab instances. In this context, the dynamic keyword makes some situations less painful to deal with. Code written with dynamic is easier to read and write, making for an application that s easier to understand and maintain.
Second, your object may have an inherently changing nature. You may be working with objects created in dynamic programmingenvironments such as IronPython and IronRuby. But you can also use this functionality with HTML DOM objects (subject to expando properties) and the Microsoft .NET Framework 4 objects specifically created to have dynamic natures.
Using dynamic
It s important to understand the concept that in the C# type system, dynamic is a type. It has a very special meaning, but it s definitely a type and it s important to treat it as such. You can indicate dynamic as the type of a variable you declare, the type of items in a collection or the return value of a method. You can also use dynamic as the type of a method parameter. Conversely, you can t use dynamic with the typeof operator and you can t use it as the base type of a class.
The following code shows how to declare a dynamic variable in the body of a method:
If you know enough about the type of the object being returned by the GetCalculator method, you can declare the variable calc of that type, or you can declare the variable as var, letting the compiler figure out the exact details. But using var or an explicit static type would require you to be certain that a method Sum exists on the contract exposed by the type GetCalculator returns. If the method doesn t exist, you get a compiler error.
With dynamic, you delay any decision about the correctness of the expression at execution time. The code compiles and is resolved at run time as long as a method Sum is available on the type stored in the variable calc.
You can also use the keyword to defi ne a property on a class. In doing so, you can decorate the member with any visibility modifier you like, such as public, protected, and even static.
Figure 1 shows the versatility of the dynamic keyword. In the main program I have a dynamic variable instantiated with the return value of a function call. Th at would be no big deal if it weren t for the fact that the function receives and returns a dynamic object. It s interesting to see what happens when, as in the example, you pass a number, then try to double it within the function. If you feed in a value of 2 and try this code, you receive a value of 4. If you feed in 2 as a string, you ll get 22 instead. Within the function, the + operator is resolved dynamically based on the run time type of the operands. If you change the type to System.Object, you get a compile error, because the + operator isn t defined onSystem.Object. The dynamic keyword enables scenarios that weren t possible without it.
dynamic vs. System.Object
Until the .NET Framework 4, having a method return different types according to diff erent conditions was possible only by resorting to a common base class. You ve probably solved this problem by resorting to System.Object. A function that returns System.Object makes available to the caller an instance that can be cast to nearly anything. So how is using dynamic better than using ystem.Object?
In C# 4, the actual type behind the variable that s declared dynamic is resolved at run time, and the compiler simply assumes that the object in a variable declared dynamic just supports any operations. Th is means you can really write code that calls a method on the object you expect to be there at run time, as illustrated here:
In C# 4.0, the compiler won t complain about that code. The analogous code using System.Object won t compile and requires some hackson your own refl ection or adventurous casting in order to work.
var vs. dynamic
The keywords var and dynamic are only apparently similar. Var indicates that the type of the variable has to be set to the compiletime type of the initializer.
But dynamic means that the type of the variable is the dynamic type as available in C# 4.0. In the end, dynamic and var have quite opposite meanings. Var is about reinforcing and improving static typing. It aims to ensure that the type of a variable is inferred by the compiler looking at the exact type being returned by the initializer.
The keyword dynamic is about avoiding static typing altogether. When used in a variable declaration, dynamic instructs the compiler to stop working out the type of the variable at all. The type has to be intended as the type it happens to have at run time. With var, your code is as statically typed as it would have been had you opted for the classic approach of using explicit types in a variable declaration.
Another difference between the two keywords is that var can only appear within a local variable declaration. You can t use var to define a property on a class, nor can you use it to specify the return value or a parameter of a function.
As a developer, you use the dynamic keyword with variables expected to contain objects of uncertain type such as objects returned from a COM or DOM API; obtained from a dynamic language (IronRuby, for example); from reflection; from objects built dynamically in C# 4.0 using the new expand capabilities.
The dynamic type doesn t bypass type checks, though. It only moves them all to run time. If type incompatibilities are discoveredat run time, then exceptions are thrown.
DINO ESPOSITOis the author of the upcoming Programming ASP.NET MVC from Microsoft Press and coauthor of Microsoft .NET: Architecting Applicationsfor the Enterprise (Microsoft Press, 2008). Esposito, who is based in Italy, is a frequentspeaker at industry events worldwide.