A Couple Neat C# Features

Picking up any new programming language takes some time. Each language, no matter how similar to others, has its own idiosyncrasies and idioms. The process of learning a new language often is eased by having a background in other languages. By finding similarities and differences, the particularities of the new language are more easily understood. Furthermore, learning a new language can change the way one thinks about problem-solving while programming. I definitely thought more about the advantages and tradeoffs of the functional programming paradigm while learning some Haskell recently. The lessons I learned can be applied in a different language like Javascript. C# was not wildly out of my comfort zone, as I have prior Java and C++ experience. However, there were a few surprises and neat features that I really appreciate in a programming language. Here are some of the highlights of C# that I encountered working with it this term.

Async/Await, Tasks, and Static Typing

I imagine the programming language that first comes to mind for the majority of programmers who hear “async/await” is Javascript, simply due to its immense popularity. However, Javascript introduced these keywords in 2017, far after C#, which introduced them in 2012. These two keywords make it easier to program using asynchronous tasks, which C# represents using the Task class. A Task in C# is somewhat analogous to a Promise in Javascript–both represent processes that can be executed asynchronously and have completion statuses.

One advantage of programming using Tasks in C# over Promises in Javascript is brought out by another feature of C#: its use of static typing and generics. Static typing provides signposts and guardrails for what a Task will eventually resolve to. Because Javascript is not statically typed and there are no required type signatures on functions, an async Javascript function could resolve to anything! This ambiguity, combined with the additional complexity of asynchronous design, sometimes causes issues for me in Javascript. However, C# has a Task<TResult> class that makes apparent what type the eventual task result will be. To illustrate, take a look at this example from the Microsoft docs:

We know the Task that is returned from the call to FryEggsAsync(2) will resolve to an object of type Egg. Then when we await the task, we can be sure that the type of the object we are awaiting is Egg. Because TResult in Task<TResult> is just a type parameter, we can specify which types of objects our asynchronous functions will eventually return and what our Tasks will eventually resolve to. Here is another great example from the same docs:

We can be certain that eggsTask will resolve to an Egg, baconTask will resolve to a Bacon, and toastTask will resolve to a Toast. This certainty is an extension of the static typing present in C#, and it is exceptionally useful within the confusing context of asynchronous programming.

LINQ

One neat feature I encountered in C# that I haven’t encountered anywhere else is the integration of a multipurpose query language into C# itself. This query language can be used to get query results from Strings, File Structures, Data Structures that implement the IEnumerable interface such as ArrayLists, and even SQL databases! I only have been working with C# for a month or so, but I imagine an experienced C# developer would really appreciate having a unified way to query all these sources. The syntax is simple and reminiscent of SQL. Below is an example from the Microsoft docs illustrating a simple query.

Note that the variable scoreQuery gets its value assigned by the programmer instructing the program about the criteria necessary for a score to be included in scoreQuery instead of directly telling the program how to loop through scores. For contrast, the same result can be achieved by looping through scores with a foreach statement and writing to console if score > 80.

These contrasting ways of approaching the problem illustrate the difference between two different types of programming: imperative and declarative. Imperative programming involves the writing of step-by-step instructions that will result in the desired result. An imperative way to approach the problem above would be to write a for or foreach loop and specify what should be done at each step of the loop. A declarative way to approach the problem would be to simply lay out a set of expectations for scoreQuery using a query language and letting the compiler figure out how exactly to meet those expectations. Most common programming languages are able to accommodate both paradigms to some extent. Python has declarative list comprehensions, and Javascript has the declarative map and filter functions. However, LINQ is a neat design choice in C# because it aims to standardize the way imperative, query-like code is written. What’s so exciting about LINQ is that it’s not just for lists but for all sorts of instances where writing a query would be useful.

Conclusion

Programming in a new language is a learning experience, but not just for the language one is currently using. Thinking about language design choices helps one become a better programmer in many ways. Knowing what tool is right for which kind of job is a sign of being experienced in a craft. Considering the advantages and limitations of a language helps one think about how to approach problems. Trying out a different paradigm and taking away its lessons can change how one writes code in other languages too. Utilizing C# has been a fun experience, and I am always astounded by the ingenuity that goes into designing a programming language.

Print Friendly, PDF & Email

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *