Chapter 6

Programming Dynamically!

IN THIS CHAPTER

Bullet Understanding dynamic typing

Bullet Defining variables

Bullet Staying flexible by being dynamic

Bullet Making static operations dynamic

Dynamic programming is another one of those buzzwords that really doesn’t have a clear definition. At its loosest, it means developing something in such a way that the program makes more decisions about the way it runs while running, rather than when you compile it.

Scripting languages are a great example of this type of programming. When you write something in JavaScript (https://developer.mozilla.org/docs/Web/JavaScript/Reference), you don’t compile it at all — all the decisions are made at runtime. Ruby (https://www.ruby-lang.org/) is another good example: Most of the time, an entire program can just be typed into a command prompt and run right from there.

Remember When you declare a variable in a dynamically typed language, you don't have to say what type you are making that variable. The compiler will just figure it out for you. In a static language, such as earlier versions of C#, you do have to say what type you are making that variable. However, starting with C# 3.0, the var keyword lets you leave the decision of which type to use to the compiler.

Microsoft originally promised that dynamic types would never be in C#, but later decided that the feature had to be added. Why? Mostly it's because of the development requirements for Microsoft Office. Office uses COM, the pre-.NET structure for Microsoft applications. Additionally, the WinRT API is not based in managed code and supports JavaScript, one of the original dynamic languages. They probably added dynamic support looking forward to WinRT as well.

COM and WinRT expects that the languages that use it (like VB Classic and C++) will have dynamic types. This made developing for Microsoft Office difficult for C# programmers, which was exactly opposite of what Microsoft wanted to happen. The end result? The dynamic type.

Shifting C# Toward Dynamic Typing

So-called “dynamic languages” are a trend that keeps coming back, like ruffled tux shirts. Dynamic languages are languages that allow for loose typing, rather than static. The concept got started in the 1960s with the List Processing (LISP) language. Dynamic languages came back in the late 1980s for two reasons: network management scripting and the artificial intelligence craze. Thanks to the web, the buzzword is back yet again.

The World Wide Web, for those of you who aren't old enough to remember, was built on View Source and dynamic languages. Microsoft's original web development language, Active Server Pages, was built on VBScript (https://www.guru99.com/introduction-to-vbscript.html) — a dynamic language.

The web is better with a dynamic programming environment, so the trend is probably here to stay this time (until the next big thing, anyway). C# isn't the only language that is adding dynamic language features, and dynamic type isn't the only language feature that has been added to make it more appealing for web programmers. Several dynamic languages have been around for a while, like these:

  • LISP
  • Perl
  • Scheme
  • Smalltalk
  • Visual Basic

Although some of these aren't as popular as they once were, they are still out there and have pushed the trend in the newer languages. You can see this trend in all the new or refurbished languages that have dynamic type systems that have popped up over the last ten years. Many of them have roots in the web, while others are being newly used for the web:

  • Cold Fusion
  • Groovy
  • JavaScript
  • Lua
  • Newspeak
  • PHP
  • Python
  • Ruby

Technicalstuff Some of these languages support multiple coding styles. For example, even though Python supports a dynamic typing system, it can use the object-oriented, imperative, functional programming, and procedural coding styles. It's important to realize that the typing system doesn’t necessarily affect the coding style used by a language.

Developers who work in dynamic languages often use them for practically everything except highly structured team-build kinds of environments. Uses include:

  • Data analysis using data science techniques
  • Artificial intelligence, machine learning, and deep learning
  • Scripting infrastructure for system maintenance
  • Building tests
  • One-use utilities
  • Scripting other applications
  • Building websites
  • Biology
  • Games

Dynamic languages are popular for these kinds of tasks for two reasons. First, they provide instant feedback, because you can try a piece of code outside the constraints of the rest of the program you are writing. Second, you can start building your higher-level pieces of code without building the plumbing that makes it work.

For instance, Ruby has a command-line interface that you can simply paste a function into, even out of context, and see how it works. There is even a web version at https://www.tutorialspoint.com/execute_ruby_online.php. You can type code right in there, even if there are classes referenced that aren't defined, because Ruby will just take a guess at it. If you want a more organized environment that relies on Python, you can find it with Google Colaboratory (Colab for short) at https://colab.research.google.com/notebooks/intro.ipynb.

This ease of online use moves nicely into the next point, which is that a dynamic language enables you to build a class that refers to a type that you haven't defined elsewhere. For example, you can make a class to schedule an event, without actually having to build the underlying Event type first.

All of this lends itself to a language that is a lot more responsive to change. You can make a logic change in one place and not have to dig through reams of code to fix all the type declarations everywhere. Add this to optional and named parameters (see Book 2 Chapter 10) and you have a lot less typing to do when you have to change your program.

Other benefits to dynamic languages in general show up as you use them more. For instance, macro languages are usually dynamically typed. If you've tried to build macros in previous versions of Visual Studio, you know what a pain it is to use a static language. Making C# (and Visual Basic, for that matter) more dynamic not only makes it a better language for extending Visual Studio but also gives programmers the capability to include the language in the programs they write so that other developers can further extend those applications.

Employing Dynamic Programming Techniques

By now, you must be asking why all this talk about dynamic code is important to C# developers. When you define a new variable, you can use the dynamic keyword, and C# will let you make assumptions about the members of the variable. For example, if you want to declare a new Course object, you do it like this:

Course newCourse = new Course();
newCourse.Schedule();

This is, of course, assuming that you have a Course class defined somewhere else in your program, like this:

class Course {
public void Schedule()
{
// Something fancy here
}
}

But what if you don't know what class the new object will be? How do you handle that? You could declare it as an Object, because everything derives from Object, right? Here's the code:

Object newCourse = new Object();

Not so fast, my friend, if you make your next line this:

newCourse.Schedule();

Note that the squiggly line appears almost immediately, and you get the famous “object does not contain a definition for Schedule…” error in the design time Error List. However, you can do this:

dynamic newCourse = SomeFunction();
newCourse.Schedule();

All this code needs to have is the stub of a function that returns some value, and you are good to go. What if SomeFunction() returns a string? Well, you get a runtime error. But it will still compile!

About now you may be thinking: “This is a good thing? How!?!” For the time being, you can blame COM. You see, COM was mostly constructed using C++, which has a variant type. In C++, you could declare a variable to be dynamic, like this:

VARIANT newCourse;

It worked just like the dynamic type, except C# wasn't invented yet. Because a lot of the objects in COM used VARIANT out parameters, it was really tough to handle Interop using .NET. (Interop is short for interoperability, where you're trying to get two pieces of code to talk with each other.) Because Microsoft Office is mostly made of COM objects, and because it isn't going to change any time soon, and because Microsoft wants us all to be Office developers one day, bam, you have the dynamic type.

Say, for instance, that your newCourse is a variant out parameter from a method in a COM class. To get the value, you have to declare it an Object, like this:

CourseMarshaller cm = new CourseMarshaller(); // a COM object
int courseId = 4;
Object newCourse;
cm.MakeCourse(courseId, out newCourse);
// and now we are back to square one
newCourse.Schedule(); // This causes a 'member not found exception'

The last line will not compile, even if the Schedule method exists, because you can't assume that newCourse will always come back as a Course object, because it is declared a variant. You're stuck. With a dynamic type, though, you’re golden once again, with this code:

CourseMarshaller cm = new CourseMarshaller(); // a COM object
int courseId = 4;
dynamic newCourse;
cm.MakeCourse(courseId, newCourse);
newCourse.Schedule(); // This now compiles

However, if newCourse comes back as something that doesn't have a Schedule() method, you get a runtime error. But there are try…catch blocks for runtime errors. Nothing will help the code compile without the dynamic keyword.

Putting Dynamic to Use

When C# encounters a dynamically typed variable, like the variables you created earlier, it changes everything that variable touches into a dynamic operation. This dynamic conversion means that when you use a dynamically typed object in an expression, the entire operation is dynamic.

Classic examples

Here are six examples of how a dynamic operation works. Say you have the dynamic variable dynamicVariable. Because the dynamic variable will pass through all six examples, they will all be dispatched dynamically by the C# compiler.

  1. dynamicVariable.someMethod("a", "b", "c");: The compiler binds the method someMethod at runtime, since dynamicVariable is dynamic. No surprise.
  2. dynamicVariable.someProperty = 42;: The compiler binds the property someProperty just like it did in the first method.
  3. var newVar = dynamicVariable + 42;: The compiler looks for any overloaded operators of + with a type of dynamic. Lacking that, it outputs a dynamic type.
  4. int newNumber = dynamicVariable;: This is an implicit conversion to int. The runtime determines whether a conversion to int is possible. If not, it throws a type mismatch error.
  5. int newNumber = (int) dynamicVariable;: This is an explicit cast to int. The compiler encodes this as a cast — you actually change the type here.
  6. Console.WriteLine(dynamicVariable);: Because there is no overload of WriteLine() that accepts a dynamic type explicitly, the entire method call is dispatched dynamically.

Making static operations dynamic

If the compiler chooses to make a static operation dynamic — as it did in item 6 in the preceding section — the compiler rebuilds the code on the fly to have it handle the dynamic variable. What does that mean for you? Glad you asked.

Take item 6, Console.WriteLine(dynamicVariable);. This piece of code forces the compiler to build intermediary code, which checks for the type of variable at runtime in order to come up with something that is writable to the console. The compiled code first checks whether the input is a static type that it knows. Next, it checks for a type present in the program. Then it will just try a few things that might work. It will fail with an error if it finds nothing.

If you must use this approach to creating code as a developer, at least you can get the job done. But remember that it's slower than molasses in January (or even slower). This is why Variant got such a bad rap in Visual Basic Classic. Dynamic is something you don’t use until you need it. It puts a tremendous strain on the machine running the program, especially if all variables are dynamic.

Understanding what's happening under the covers

Using dynamic programming techniques doesn’t have to be hard. In fact, you can do so with just three functional lines of code by using this simple method:

class C
{
public dynamic MyMethod(dynamic d)
{
return d.Foo();
}
}

This is pretty straightforward stuff — a method that accepts a dynamic class and returns the results of the type's Foo method. Not a big deal. Here is the compiled C# code:

class C
{
[return: Dynamic]
public object MyMethod([Dynamic] object d)
{
if (MyMethodo__SiteContainer0.p__Site1 == null)
{
MyMethodo__SiteContainer0.p__Site1 =
CallSite<Func<CallSite, object, object>>
.Create(new CSharpCallPayload(
CSharpCallFlags.None, "Foo", typeof(object), null,
new CSharpArgumentInfo[] {
new CSharpArgumentInfo(CSharpArgumentInfoFlags.None,
null) }));
}
return MyMethodo__SiteContainer0.p__Site1
.Target(MyMethodo__SiteContainer0.p__Site1, d);
}

[CompilerGenerated]
private static class MyMethodo__SiteContainer0
{
public static CallSite<Func<CallSite, object, object>> p__Site1;
}
}

Most developers wouldn't want to try to break this code down. Fortunately, they don’t have to. That's what compilers are for, right?

Running with the Dynamic Language Runtime

There is more to dynamic languages than just the dynamic typing. You can do some powerful things. As with all power, you have to be careful not to misuse it.

The Dynamic Language Runtime — shown in Figure 6-1 — is a library added to the .NET Framework specifically to provide for adding dynamic languages (like Ruby) to the Visual Studio fold (like IronRuby), or to add dynamic language features to existing static languages (like C# 4.0).

Snapshot of the Dynamic Language Runtime.

FIGURE 6-1: The Dynamic Language Runtime.

The runtime helps the compiler to construct code in the compiled assembly that will make a lot of choices dynamically. The code block at the end of the preceding section is an example of the simplest kind. Of course, C# has similar features, so you can use dynamic programming techniques. Here's the code:

static dynamic f(dynamic x)
{
return Math.Sqrt(x) + 5.0 * Math.Pow(x, 3.0);
}

static void Main(string[] args)
{
dynamic[] array = new Array[11];

for (int i = 0; i < 11; i++)
{
array[i] = Console.ReadLine();
}

for (int i = 10; i>=0; i--)
{
dynamic y = f(array[i]);
if (y > 400.0)
{
Console.WriteLine(string.Format("{0} TOO LARGE", i));
}
else
{
Console.WriteLine("{0} : {1}", i, array[i]);
}
}

Console.ReadKey();
}

Two functions are defined in this example: f() and Main(). Main() accepts 11 numbers from the console and then moves them to an integer array using a for loop. Next, the code processes the entries. For each value in the array, it sets y equal to f(x) and then sees whether it is higher than this arbitrary value (which is 400 in this case, but you could use any value). If so, it prints “TOO LARGE”; otherwise, it prints the number.

Clearly, you could have just used double for this example, so it may not seem like there is a good reason to use dynamic programming techniques. But, use of dynamic just made the program easier to create. Try changing the array to an array of double, like this:

Double[] array = new Double[11];

Now the call to ReadLine() doesn't work. You'll just cast it to a double. Nope, can't do that; you have to use TryParse. You get the picture. Static types are hard to code with. Dynamic types are easier to code with.

What's the other side of this? Well, obviously, if the user enters a non-numeric string, the program outputs a runtime error, and that's bad. If you statically type everything, you can trap that error much more easily and handle it right on user input.

Add to that the reality that C# is making runtime decisions about every single variable throughout the entire run of the program. That's a whole lot of extra processing that you could have avoided if you had just done that static typing.

The take-home here is that using dynamic types makes your programming job much easier and your troubleshooting job much harder. If you are writing a utility script for your own use and don't care if it occasionally crashes with a type mismatch, use dynamic. If you are writing a backup script for a hospital and the lives of thousands are at stake, static types are likely better.

Using Static Anonymous Functions

A problem with dynamic programming techniques is that lambdas and anonymous functions can capture local field values and instance information, which may create error situations for your application because the compiler makes some assumptions that aren't correct. For example, the function may create an offset in an output value based on the previous state of the function. C# 9.0 and above allows you to get past this problem by adding the static keyword to lambdas and anonymous functions. Here are some of the trade-offs to consider when using the static keyword:

  • You can now access static members, including constants, of an enclosing scope.
  • You can't access these members of an enclosing scope:
    • nameof()
    • Local variables
    • Parameters
    • this
    • base
  • Accessibility rules change to match those of static members of an enclosing scope.
  • There’s no guarantee that the static anonymous function will actually appear as a static method in the metadata after compilation because this detail is left to the compiler.
  • A non-static anonymous function can capture state from the enclosing static anonymous function, but it can’t capture state from outside the enclosing static anonymous function scope.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.196.175