CSC/ECE 517 Fall 2010/ch3 3i ls

From Expertiza_Wiki
Jump to navigation Jump to search

Mixing static and dynamic code other than Ruby and Java

Definition

What is The Type System?

A programming language is a notation for writing programs, which are specifications of a computation or algorithm. Some, but not all, authors restrict the term "programming language" to those languages that can express all possible algorithms. A type system defines how a programming language classifies values and expressions into types, how it can manipulate those types and how they interact. The goal of a type system is to verify and usually enforce a certain level of correctness in programs written in that language by detecting certain incorrect operations. Any decidable type system involves a trade-off: while it rejects many incorrect programs, it can also prohibit some correct, albeit unusual programs. In order to bypass this downside, a number of languages have type loopholes, usually unchecked casts that may be used by the programmer to explicitly allow a normally disallowed operation between different types. In most typed languages, the type system is used only to type check programs, but a number of languages, usually functional ones, perform type inference, which relieves the programmer from writing type annotations. The formal design and study of type systems is known as type theory.

Classification of Type Checking

The process of verifying and enforcing the constraints of types – type checking – may occur either at compile-time (a static check) or run-time (a dynamic check). In static typing all expressions have their types determined prior to the program being run (typically at compile-time). For example, 1 and (2+2) are integer expressions; they cannot be passed to a function that expects a string, or stored in a variable that is defined to hold dates. Statically typed languages can be either manifestly typed or type-inferred. In the first case, the programmer must explicitly write types at certain textual positions (for example, at variable declarations). In the second case, the compiler infers the types of expressions and declarations based on context. Most mainstream statically typed languages, such as C++, C# and Java, are manifestly typed. Complete type inference has traditionally been associated with less mainstream languages, such as Haskell and ML. However, many manifestly typed languages support partial type inference; for example, Java and C# both infer types in certain limited cases.

Dynamic typing, also called latent typing, determines the type-safety of operations at runtime; in other words, types are associated with runtime values rather than textual expressions.As with type-inferred languages, dynamically typed languages do not require the programmer to write explicit type annotations on expressions. Among other things, this may permit a single variable to refer to values of different types at different points in the program execution. However, type errors cannot be automatically detected until a piece of code is actually executed, making debugging more difficult. Ruby, Lisp, JavaScript, and Python are dynamically typed.

Mixing Static and Dynamic Typing

The presence of static typing in a programming language does not necessarily imply the absence of all dynamic typing mechanisms. For example, Java, and various other object-oriented languages, while using static typing, require for certain operations, the support of runtime type tests, a form of dynamic typing.

As of the 4.0 Release, the .NET Framework supports a variant of dynamic typing via the System.Dynamic namespace whereby a static object of type 'dynamic' is a placeholder for the .NET runtime to interrogate its dynamic facilities to resolve the object reference.

Fundamentals

In computer science, a type system may be defined as a tractable syntactic framework for classifying phrases according to the kinds of values they compute. A type system associates types with each computed value. By examining the flow of these values, a type system attempts to prove that no type errors can occur. The type system in question determines what constitutes a type error, but a type system generally seeks to guarantee that operations expecting a certain kind of value are not used with values for which that operation makes no sense.

Assigning data types (typing) gives meaning to sequences of bits. Types usually have associations either with values in memory or with objects such as variables. Because any value simply consists of a sequence of bits in a computer, hardware makes no intrinsic distinction even between memory addresses, instruction code, characters, integers and floating-point numbers, being unable to discriminate between them based on bit pattern alone. Associating a sequence of bits and a type informs programs and programmers how that sequence of bits should be understood.

Major functions provided by type systems include:

  • Safety: Use of types may allow a compiler to detect meaningless or probably invalid code.
  • Optimization – Static type-checking may provide useful compile-time information.Optimization – Static type-checking may provide useful compile-time information.
  • Abstraction (or modularity) – Types allow programmers to think about programs at a higher level than the bit or byte, not bothering with low-level implementation.

Type safety contributes to program correctness, but cannot guarantee it unless the type checking itself becomes an undecidable problem. Depending on the specific type system, a program may give the wrong result and be safely typed, producing no compiler errors. For instance, division by zero is not caught by the type checker in most programming languages; instead it is a runtime error. To prove the absence of more general defects, other kinds of formal methods, collectively known as program analysis, are in common use, as well as software testing—a widely used empirical method for finding errors that the type checker cannot detect.

Static Typing vs. Dynamic Typing

Static Typing

A programming language is said to use static typing when type checking is performed during compile-time as opposed to run-time. Static typed programming languages are those in which variables need not be defined before they're used. This implies that static typing has to do with the explicit declaration (or initialization) of variables before they're employed. Java is an example of a static typed language; C and C++ are also static typed languages. Note that in C (and C++ also), variables can be cast into other types, but they don't get converted; you just read them assuming they are another type.

Static typing does not imply that you have to declare all the variables first, before you use them; variables maybe be initialized anywhere, but developers have to do so before they use those variables anywhere. Consider the following example:

                  /* C code */
             static int num, sum; // explicit declaration
             num = 5; // now use the variables
             sum = 10;
             sum = sum + num;

The above code fragment is an example of how variable declaration in static typed languages generally appears. Note that in the above code, static has nothing to do with static typing; it has been used along with int only to initialize num and sum to zero.

Dynamic Typing

A programming language is said to be dynamically typed when the majority of its type checking is performed at run-time as opposed to at compile-time. Dynamic typed programming languages are those languages in which variables must necessarily be defined before they are used. This implies that dynamic typed languages do not require the explicit declaration of the variables before they're used. Python is an example of a dynamic typed programming language, and so is PHP. Consider the following example:

               /* Python code */
             num = 10 // directly using the variable


Static Typing and Dynamic Typing versus Strong Typing and Weak Typing

Static and dynamic typing, and strong and weak typing, are two totally different concepts, which, unfortunately, are very often confused. It is erroneous to say that a language that is static or dynamic typed cannot be strong or weak typed. Static and dynamic typing, and strong and weak typing, are different forms of classification of programming languages, and one of each class necessarily characterizes a given language. It is thus imperative to discuss strong and weak typing vis-a-vis static and dynamic typing.

Programming languages that exhibit "strong typing" are "strong typed," and those that exhibit "weak typing" are "weak typed".

Mixing Static and Dynamic Typing

The presence of static typing in a programming language does not necessarily imply the absence of all dynamic typing mechanisms. For example, Java, and various other object-oriented languages, while using static typing, require for certain operations (downcasting) the support of runtime type tests, a form of dynamic typing. See programming language for more discussion of the interactions between static and dynamic typing.

As of the 4.0 Release, the .NET Framework supports a variant of dynamic typing via the System.Dynamic namespace whereby a static object of type 'dynamic' is a placeholder for the .NET runtime to interrogate its dynamic facilities to resolve the object reference.

The choice between static and dynamic typing requires trade-offs.

Static typing can find type errors reliably at compile time. This should increase the reliability of the delivered program. However, programmers disagree over how commonly type errors occur, and thus what proportion of those bugs which are written would be caught by static typing. Static typing advocates believe programs are more reliable when they have been well type-checked, while dynamic typing advocates point to distributed code that has proven reliable and to small bug databases. The value of static typing, then, presumably increases as the strength of the type system is increased. Advocates of dependently typed languages such as Dependent ML and Epigram have suggested that almost all bugs can be considered type errors, if the types used in a program are properly declared by the programmer or correctly inferred by the compiler.

Static typing usually results in compiled code that executes more quickly. When the compiler knows the exact data types that are in use, it can produce optimized machine code. Further, compilers for statically typed languages can find assembler shortcuts more easily. Some dynamically typed languages such as Common Lisp allow optional type declarations for optimization for this very reason. Static typing makes this pervasive. See optimization.

By contrast, dynamic typing may allow compilers to run more quickly and allow interpreters to dynamically load new code, since changes to source code in dynamically typed languages may result in less checking to perform and less code to revisit. This too may reduce the edit-compile-test-debug cycle.

Statically typed languages which lack type inference (such as Java and C) require that programmers declare the types they intend a method or function to use. This can serve as additional documentation for the program, which the compiler will not permit the programmer to ignore or permit to drift out of synchronization. However, a language can be statically typed without requiring type declarations (examples include Haskell, Scala and to a lesser extent C#), so this is not a necessary consequence of static typing.

Dynamic typing allows constructs that some static type checking would reject as illegal. For example, eval functions, which execute arbitrary data as code, become possible. Furthermore, dynamic typing better accommodates transitional code and prototyping, such as allowing a placeholder data structure (mock object) to be transparently used in place of a full-fledged data structure (usually for the purposes of experimentation and testing).

Dynamic typing is used in Duck typing which can support easier code reuse.

Dynamic typing typically makes metaprogramming more effective and easier to use. For example, C++ templates are typically more cumbersome to write than the equivalent Ruby or Python code.[citation needed] More advanced run-time constructs such as metaclasses and introspection are often more difficult to use in statically typed languages.

The following table shows the type system cross reference list.

type system cross reference list.
type system cross reference list.

.

Examples

Is Dynamic Typing Good?

In a dynamic typed language, you don't have to initialize variables, which is a big bonus for many developers. Programmers like the fact that you can use a variable at will when required (without having to initialize it). Dynamic typing is characteristic of many of the scripting languages: Perl, PHP, Python, etc. Dynamic typing, in fact, does save you from writing a few "extra" lines of code, which, in turn, means less time spent writing code.

The very characteristic of dynamic typed languages that appeals to many developers is also a pitfall, and a major one at that. Consider the following simple example:

/* Python code */ my_variable = 10 while my_variable > 0:

      i = foo(my_variable)
      if i < 100:
              my_variable++
      else
              my_varaible = (my_variable + i) / 10 // spelling error intentional

As you can see in the above code, my_varaible is a spelling mistake that the programmer could have very well made. The problem here is that, since Python is dynamically typed, it will not return an error, but instead will create a new variable called my_varaible. So, now we have two variables: my_variable and my_varaible. This obviously is a serious problem; some would suggest that forced variable declaration is an important requirement in any programming language.

Static Typed Behavior in Dynamic Typed Languages

Perl is a dynamic typed programming language. However, it provides a means to "simulate" static typing by means of a pragma called strict. Consider the following Perl example:

/* Perl code */

     $sum = 10;
     print $sum;

The above code will run without any problem, and will print 10 to the console. Note that here, we have not initialized the variable sum; this exemplifies the dynamic typing characteristic of Perl. To enforce variable declaration, we make use of the strict pragma as follows:

/* Perl code */

    use strict;
    $sum = 10;
    print $sum;

The above code fragment will return the following error when you try to run it:

Global symbol "$num" requires explicit package name at perl.pl line 2. Execution of perl.pl aborted due to compilation errors.

To rectify the above error, we are forced to declare the variable num as follows:

/* Perl code */

  use strict;
  my $num; // forced declaration
  $sum = 10;
  print $sum;

The above codes are specific to Perl; not all programming languages have a way to enforce variable declaration: Python, for example doesn't have a way to enforce variable declaration. However, there is a tool, called "pychecker" (available here), that can be used to "detect" stray variables; this is, of course, far from a desirable solution.

Polymorphism and types

The term "polymorphism" refers to the ability of code to act on values of multiple types, or to the ability of different instances of the same data-structure to contain elements of different types. Type systems that allow polymorphism generally do so in order to improve the potential for code re-use: in a language with polymorphism, programmers need only implement a data structure such as a list or an associative array once, rather than once for each type of element with which they plan to use it. For this reason computer scientists sometimes call the use of certain forms of polymorphism generic programming. The type-theoretic foundations of polymorphism are closely related to those of abstraction, modularity and (in some cases) subtyping.

Duck Typing

In "duck typing", a statement calling a method m on an object does not rely on the declared type of the object; only that the object, of whatever type, must implement the method called. One way of looking at this is that in duck typing systems the type of an object is intrinsic to the object and is determined by what methods it implements, and hence that a duck typing system is by definition type-safe since one can only invoke operations an object actually implements. Another way of looking at this is that the object is a member of several types, including a type that describes the fact that it "has a method m." Type checking however occurs only on demand at runtime, every time the method m needs to be executed, not at compile-time or load-time.

Duck typing differs from structural typing in that, if the part (of the whole module structure) needed for a given local computation is present at runtime, the duck type system is satisfied in its type identity analysis. On the other hand, a structural type system would require the analysis of the whole module structure at compile-time to determine type identity or type dependence.

Duck typing differs from a nominative type system in a number of aspects. The most prominent ones are that, for duck typing, type information is determined at runtime (as contrasted to compile-time) and the name of the type is irrelevant to determine type identity or type dependence; only partial structure information is required for that, for a given point in the program execution.

Initially coined by Alex Martelli in the Python community, duck typing uses the premise that (referring to a value) "if it walks like a duck, and quacks like a duck, then it is a duck".

Programming Style

Some programmers prefer statically typed languages; others prefer dynamically typed languages. Statically typed languages alert programmers to type errors during compilation, and they may perform better at runtime. Advocates of dynamically typed languages claim they better support rapid prototyping and that type errors are only a small subset of errors in a program. Likewise, there is often no need to manually declare all types in statically typed languages with type inference; thus, the need for the programmer to explicitly specify types of variables is automatically lowered for such languages; and some dynamic languages have run-time optimisers that can generate fast code approaching the speed of static language compilers, often by using partial type inference.

Summary

There are a lot of discussions all over the internet about static vs dynamic languages. Dynamic programming language is a term used broadly in computer science to describe a class of high-level programming languages that execute at runtime many common behaviors that other languages might perform during compilation, if at all. Static typing and dynamic typing, are topics of programming language design that are not always clearly defined and, as a result, are not very well understood, especially for languages with mixing static and dynamic typing. For example, Perl is a dynamic typed programming language. However, it provides a means to "simulate" static typing by means of a pragma called strict. This article has given you an insight into the concepts of static and dynamic typing.

Reference

[1] Introduction to Static and Dynamic Typing, Premshree Pillai, June, 2004.

[2] Type system, from Wikipedia.

[3] Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages, Erik Meijer and Peter Drayton.

[4] Template:Type system cross reference list, from Wikipedia.

[5] Dynamic vs. Static Typing — A Pattern-Based Analysis, Pascal Costanza, March, 2004.

[6] Including both static and dynamic typing in the same programming language, Ortin, F.; Zapico, D.; Perez-Schofield, J.B.G.; Garcia, M.; Aug, 2010.

[7] Typing: Strong vs. Weak, Static vs. Dynamic, by Aahz, July, 2003.

[8] Dynamic type languages versus static type languages, Sep, 2009.