We first start with some design goals for the language
Language Design Principles
Simplicity Syntax and semantics can easily be understood by users and implementers of the language Expressiveness: Language can (easily) express complex processes and structures, conflicting with simplicity. Safety: Language discourages errors and allows errors to be discovered and reported, ideally at compile time Modularity: Language allows modules to be type-checked and compiled separately Performance: Programs written in the language can be executed efficiently Productivity: Language leads to low costs of writing programs like Python. Backwards Compatibility: Newer language versions work and interface with programs in older versions (dependency injection for examples helps for this.)
“The basic philosophy underlying object-orientedprogramming is to make the programs as far aspossible reflect that part of the reality they are goingto treat. It is then often easier to understand and toget an overview of what is described in programs.The reason is that human beings from the outset areused to and trained in the perception of what is goingon in the real world. The closer it is possible to usethis way of thinking in programming, the easier it is towrite and understand programs.“ ~Object-oriented Programming in the BETA Programming Language
This node should be something very similar to what present in Teoria dei Tipi. But here we revise it for the master’s course in another manner.
Types allow you do something more statically detect some errors.
Message not understood
When some method does not exist we should get this kind of error, the message not understood (using the class as message passing example.) Static type systems should be able to understand this kind of messages.
Java Security Model
Code could come from arbitrary sources. For security reason, we pass code to API, and in this manner we can implement access control at this level. For this reason we don’t allo type automatic type casting like moving int to a pointer implicitly as you can do it in C. Java clearly separates the OS with some API interface, in this manner we have some sort of isolation.
Type Systems
Definition of Type System
A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute B.C. Pierce 2002
- Syntactic: Rules are based on form, not behavior
- Phrases: Expressions, methods, etc. of a program
- Kinds of values: Types
A Type and Its Properties
A type is a set of values sharing some properties.A value v has type T if v is an element of T.
We have Nominal Types based on type names, so you just define one type is equal to another based on this kind of relationships. In this case, even if they have the same functionality, but they are called differently, then they are different. And Structural Types: you say they are equivalent when they have the same methods and fields, so its based on their availability.
In the past we have defined a concept of type equivalence based on these properties, see Algebra dei tipi.
Weakly and Strongly-Typed languages
The main distinction we make here, is the difference between type and value, and the operations that you can do about those.
Untyped languages: Do not classify values into types- Example: assembly languages. This is one of the oldest and most difficult ways to deal with code, basically you don’t have any abstraction.
Weakly-typed languages: Classify values into types, but do not strictly enforce additional restrictions- Example: C, C++. In this case, you can freely convert one value with another, the system does not check constraint before execution. This is also a reason why you get segmentation faults and stuff similar to this.
Strongly-typed languages: Enforce that all operations are applied to arguments ofthe appropriate types- Examples: C#, Eiffel, Java, Python, Scala, Smalltalk
Static and Dynamic Type Checking
See Teoria dei Tipi#Dynamic and static typing. The thing you have to remember is that with static you can check at compile time while with dynamic you usually just can check at runtime.
Aspect | Advantages of Static Checking | Advantages of Dynamic Checking |
---|---|---|
Error detection | Static safety: More errors are caught at compile time, before running the program. | Expressiveness: No correct program is rejected by the type checker — fewer artificial restrictions. |
Readability & Documentation | Types serve as self-documentation, making code easier to understand. | |
Performance | Type information allows compiler optimizations, often faster execution. | No compile-time type machinery — lower upfront overhead. Higher later overhead. |
Tooling | Strong types enable better IDE support: auto-completion, refactoring, static analysis. | Simplicity: No complicated type system rules to learn or work around. |
Flexibility | Can be restrictive — some correct programs won’t type-check. | Very flexible — developers can write code without fighting the type checker. |
Static Type Safety
A programming language is called type-safe if its design prevents type errors.
Statically type-safe object-oriented languages guarantee the following type invariant:In every execution state, the value held by variable is an element of the declared type of v
Some of the errors are thus prevented in this manner.
Consider
Object[ ] oa = new Object[ 10 ];
String s = “A String”;
oa[ 0 ] = s;
...
s = (String) oa[ 0 ];
s = s.concat( “Another String” );
There is a runtime check at (String)
to check if the thing is really a string, if not it breaks.
Usually with dynamic type checking, we get much more flexibility. For example checking the safety of generated code. You cannot do that with static since you don’t know the type during compilation. In this sense dynamic type checkers are more expressive.
Bypassing type checks
dynamic v = getPythonObject( );
dynamic res = v.Foo( 5 );
This is an example in C# that does this. This is useful for inter-operation or interacting with the DOM
Gradual Typing
We call gradual typing these kind of types where we have optional type checks, when you have a type annotation, you check it. This does not give you a guarantee, but its safer compared to not having it.
For example in Python we can use type annotations and we have some optional static type checking in the code. We can also use Any
to say that it doesn’t have any static type.
Duck Typing
When I see a bird that walkslike a duck and swims like aduck and quacks like a duck,I call that bird a duck.“ ~James Whitcomb Riley
Static | Dynamic | |
---|---|---|
Nominal | C++, C#, Eiffel, Java, Scala | Individual features of nominal, static languages |
Structural | Go, OCaml | JavaScript, Python, Ruby, Smalltalk (Ducktyping) |
Subtyping
Objects of subtypes can be used wherever objects of supertypes are expected
Subtyping is a set relation between the types. And again, here we can decide nominal or structural subtyping. It depends on the properties that the types have! Again, see Algebra dei tipi.
Classification principles
We have mainly two ways to decide whether to classify the syntactic and semantic parts.
Subtyping rules
We have three main subtyping rules: Existence: Subtypes cannot remove any method or field that was present in the supertype Accessibility: We cannot make stuff less accessible.