StaDyn is an object-oriented general-purpose programming language for the .NET platform that supports both static and dynamic typing in the same programming language.
The StaDyn compiler gathers type information for the dynamically typed code. That type information is used to detect type errors at compilation time and to perform significant optimizations. For that purpose, it provides type reconstruction (inference), flow-sensitive types, union and intersection types, constraint-based typing, alias analysis and method specialization. Its first prototype appeared in 2007, as a modification of C# 3.0. Type inference was supported by including <code>var</code> as a new type, unlike C#, which only offers <code>var</code> to define initialized local variables. Flow-sensitive types of <code>var</code> references are inferred by the compiler, providing type-safe duck typing. When a more lenient approach is required by the programmer, the <code>dynamic</code>type could be used instead of <code>var</code>. Although type inference is still performed, <code>dynamic</code> references behave closer to those in dynamic languages.
StaDyn is designed by Francisco Ortin from the University of Oviedo. The language has been implemented by different members of the Computational Reflection research group, including Miguel Garcia, Jose Baltasar GarcÃÂa Perez-Schofield and Jose Quiroga, besides Francisco Ortin.
The name StaDyn is a portmanteau of static and dynamic, denoting its aim to provide the benefits of both static and dynamic typing.
Just like dynamic languages, variables may hold different types in the same scope:
The <code>age</code> variable is first inferred as string, so it is safe to get its <code>Length</code> property. Then, it holds an integer, so <code>age++</code> is a valid expression. The compiler detects an error in the last line, since <code>Length</code> is no longer provided by <code>age</code>.
The generated code does not use a single <code>Object</code> variable to represent age, but two different variables whose types are string and int. This is achieved with a modification of the algorithm to compute the SSA form. This makes the generated code to be more efficient, since runtime type conversions are not required.
<code>var</code> and <code>dynamic</code> variables can hold flow-sensitive types:
It is safe to get the <code>Message</code> property from <code>exception</code> because both <code>ApplicationException</code> and <code>SystemException</code> provide that property. Otherwise, a compiler error is shown. In this way, StaDyn provides a type-safe static duck-typing system.
In the following program:
The <code>Message</code> property is not provided by <code>String</code>, so a compiler error is shown for <code>exception.Message</code>. However, if we declare <code>exception</code> as <code>dynamic</code>, the previous program is accepted by the compiler. <code>dynamic</code> is more lenient than <code>var</code>, following the flavor of dynamic languages. However, static type checking is still performed. This is shown in the last line of code, where the compiler shows an error for <code>exception.Unknown</code> even if <code>exception</code> is declared as <code>dynamic</code>. This is because neither of the three possible types (<code>ApplicationException</code>, <code>SystemException</code> and <code>String</code>) supports the <code>Unknown</code> message.
Although <code>dynamic</code> and <code>var</code> types can be used explicitly to obtain safer or more lenient type checking, the dynamism of single <code>var</code> references can also be modified with command-line options, XML configuration files and a plugin for Visual Studio.
<code>var</code> and <code>dynamic</code> types can be used as object fields:
The <code>Wrapper</code> class can wrap any type. Each time we call the <code>set</code> method, the type of <code>attribute</code> is inferred as the type of the argument. Each object has a potentially different type of <code>attribute</code>, so its type is stored for every single instance rather than for the whole class. In this way, the two lines indicated in the code above report compilation errors. A type-based alias analysis algorithm is implemented to support this behavior.
Let's analyze the following method:
The type of <code>parameter</code> and the function return value are inferred by the compiler. To that aim, a constraint is added to the type of the <code>upper</code> method: the argument must provide a <code>ToUpper</code> method with no parameters. At each invocation, the constraint will be checked. Additionally, the return type of <code>upper</code> will be inferred as the return type of the corresponding <code>ToUpper</code> method implemented by the argument.
The programmer may use either <code>var</code> or <code>dynamic</code> to declare <code>parameter</code>, changing the way type checking is performed upon method invocation. Let's assume that the argument passed to <code>upper</code> holds a flow-sensitive type (e.g., the <code>ApplicationException</code>, <code>SystemException</code> or <code>String</code> <code>exception</code> variable in the code above). With <code>var</code>, all the possible types of the argument must provide <code>ToUpper</code>; with <code>dynamic</code>, at least one type must provide <code>ToUpper</code>.
The type information gathered by StaDyn is used to perform significant optimizations in the generated code: the number of type inspections and type casts are reduced, reflection is avoided, frequent types are cached, and methods with constraints are specialized. The point of all the optimizations is to reduce the number of type-checking operations performed at runtime, which is the main performance penalty of most dynamic languages. Many of those type checks are undertaken earlier by the StaDyn compiler. A detailed evaluation of the runtime performance of StaDyn is detailed in.