C+ Language Design
Download
Report
Transcript C+ Language Design
C# Language Design
Peter Hallam
Software Design Engineer
C# Compiler
Microsoft Corporation
Overview
Introduction to C#
Design Problems
Future Directions
Questions
Hello World
using System;
class Hello
{
static void Main()
{
Console.WriteLine("Hello, world!");
}
}
C# Program Structure
Namespaces
Type declarations
Classes, structs, interfaces, enums,
and delegates
Members
Contain types and other namespaces
Constants, fields, methods, operators,
constructors, destructors
Properties, indexers, events
Organization
No header files, code written “in-line”
Program Structure Example
namespace System.Collections
{
using System;
public class Stack: Collection
{
Entry top;
public void Push(object data) {
top = new Entry(top, data);
}
public object Pop() {
if (top == null) throw new InvalidOperationException();
object result = top.data;
top = top.next;
return result;
}
}
}
Predefined Types
C# predefined types
The “root”
Logical
Signed
Unsigned
Floating-point
Textual
object
bool
sbyte, short, int, long
byte, ushort, uint, ulong
float, double, decimal
char, string
Textual types use Unicode (16-bit characters)
C# Classes
Single inheritance
Can implement multiple interfaces
Members
Constants, fields, methods, operators,
constructors, destructors
Properties, indexers, events
Nested types
Static and instance members
Member access
public, protected, internal, private
Interfaces
Can contain method declarations; no
code or data
Defines a “contract” that a class must
support
Classes have one base class, but can
implement many interfaces
interface IFormattable {
string Format(string format);
}
class DateTime: IFormattable {
public string Format(string format) {…}
}
Statements and
Expressions
Very similar to C++, with some changes to increase
robustness
No ‘->’ or ‘::’; all qualification uses ‘.’
Local variables must be initialized before use
if, while, do require bool condition
goto can’t jump into blocks
switch statement – no fall through
Expression statements must do something useful
(assignment or call)
void Foo() {
i == 1;
}
// error
void Foo() {
if (i = 1) // error
...
C# Design Goals
Simple, Extensible Type System
1st Class Component Support
Robust and Versionable
Preserve existing investments
Problem:
How to Unify the Type System
A single universal base type (“object”)
All types ultimately inherit from object
Object variable can hold any value
Any piece of data can be stored,
transported, and manipulated with no
extra work
Unification enables:
Calling virtual functions on any value
Collection classes for any type
Unifying the Type System
Desired Picture:
Stream
MemoryStream
object
Hashtable
int
double
FileStream
How to deal with the primitive types
without losing performance?
How to create user-defined types that
are as efficient as “int” or “double”?
How to Unify:
A traditional approach (SmallTalk)
Make everything a real object
Performance implications
All objects have a type descriptor or virtual
function table
May require all object to be heap-allocated to
prevent dangle pointers
Behavior and expectation mismatch
“int” variables can be “null”
How to Unify:
Don’t do it (Eiffel, Java)
Intrinsic types are not classes
Good performance
Can’t convert “int” to “Object” – the
primitive types are in a separate world
Requires special wrapper classes (e.g.,
“Integer”) to “wrap” a primitive type so
that it works in the “Object” world.
Not extensible – the set of primitive types
is fixed.
How to Unify:
C# Approach
Types are divides into two kinds:
Reference types and Value types
Reference types are full-featured:
Always allocated in heap
Arbitrary derivation
Value types have restrictions:
Only inherit from object
Can’t be used as base classes
Allocated from stack or inline inside other
objects
Assignment copies value, not reference
Unification
Value types don’t need type
descriptors or vtables (efficient!)
“object” does need a type descriptor,
because it can contain any type
Value types become reference types
when they are converted to “object”
Value is copied to heap, type descriptor
attached
Process is called “boxing”
When cast back to value type, “unboxing”
occurs, value is copied out of heap
Boxing and Unboxing
“Everything is an object”
Any type can can be stored as an object
int i = 123;
object o = i;
int j = (int)o;
i
123
o
“int”
?
j
123
123
} “Boxing”
}
“Unboxing”
User-Defined Types
C# allows user-defined types to be
either reference or value types
Classes (reference)
Used for most objects
Structs (value)
Objects that are like primitive data (Point,
Complex, etc).
struct Point { int x, y; ... }
Point sp = new Point(10, 20);
C# Type System
Natural User Model
Extensible
Performant
Problem:
Additional Declarative Information
How do you associate information with
types and members?
XML persistence mapping for a type
External code interop information
Remoting information
Transaction context for a method
Visual designer information (how should
property be categorized?)
Security contraints (what permissions are
required to call this method?)
Other Approaches
Add keyword or pragma
Use external file
Requires updating the compiler for each
new piece of information
Information clumsy to find/see
Require duplication of names
Example: IDL files for remote procedures
Use naming patterns
Create a new class or constant that
describes the class/members
Example: Java “BeanInfo” classes
C# Solution: Attributes
Attach named attributes (with optional
arguments) to language element
Uses simple bracketed syntax
Arguments must be constants of
string, number, enum, type-name
Attributes - Examples
public class OrderProcessor {
[WebMethod]
public void SubmitOrder(PurchaseOrder order) {...}
}
public class PurchaseOrder
[XmlElement("shipTo")]
[XmlElement("billTo")]
[XmlElement("items")]
[XmlAttribute("date")]
}
{
public
public
public
public
Address ShipTo;
Address BillTo;
Item[] Items;
DateTime OrderDate;
public class Button {
[Category(Categories.Layout)]
public int Width { get {…} set {…} }
[Obsolete(“Use DoStuff2 instead”)]
public void DoStuff() {…}
}
Attributes
Attributes
Attached to types, members, parameters, and
libraries
Present in the compiled metadata
Can by examined by the common language
runtime, by compilers, by the .NET Frameworks, or
by user code (using reflection)
Extensible
Type-safe
Extensively used in .NET Frameworks
XML, Web Services, security, serialization,
component model, transactions, external code
interop…
Creating an Attribute
Attributes are simply classes
Derived from System.Attribute
Class functionality = attribute
functionality
Attribute arguments are constructor
arguments
public class ObsoleteAttribute : System.Attribute
{
public ObsoleteAttribute () { … }
public ObsoleteAttribute (string descrip) { … }
}
Using the Attribute
[Obsolete]
void Foo() {…}
[Obsolete(“Use Baz instead”)]
void Bar(int i) {…}
When a compiler sees an attribute it:
1. Finds the constructor, passing in args
2. Checks the types of arguments against
the constructor
3. Saves a reference to the constructor and
values of the arguments in the metadata
Querying Attributes
Use reflection to query attributes
Type type = typeof(MyClass);
foreach(Attribute attr in type.GetCustomAttributes())
{
if ( attr is ObsoleteAttribute ) {
ObsoleteAttribute oa = (ObsoleteAttribute) attr;
Console.WriteLine(“{0} is obsolete: {1}”,
type, attr.Description;
}
}
Problem : Versioning
Once a class library is released, can we add
functionality without breaking users of the
class library?
Very important for system level components!
Versioning Problems
Versioning is overlooked in most languages
C++ and Java produce fragile base classes
Users unable to express versioning intent
Adding a virtual method can break a derived
class
If the derived class already has a method of the
same name, breakage can happen
Versioning: C# solution
C# allows intent to be expressed
Methods are not virtual by default
C# keywords “virtual”, “override” and “new”
provide context
Adding a base class member never breaks a
derived class
Adding or removing a private member never
breaks another class
C# can't guarantee versioning
Can enable (e.g., explicit override)
Can encourage (e.g., smart defaults)
Versioning Example
class Base
// version 2
1
{
} public virtual void Foo() {
Console.WriteLine("Base.Foo");
}
}
class Derived: Base
// version 2b
1
2a
{
new public
public
virtual
override
virtual
void
void
void
Foo()
Foo()
Foo()
{{ {
Console.WriteLine("Derived.Foo");
base.Foo();
} Console.WriteLine("Derived.Foo");
} }
}
Interface Implementation
Private interface implementations
Resolve interface member conflicts
interface I {
void foo();
}
interface J {
void foo();
}
class C: I, J {
void I.foo() { /* do one thing */
}
void J.foo() { /* do another thing */ }
}
foreach Statement
Iteration of arrays
public static void Main(string[] args) {
foreach (string s in args) Console.WriteLine(s);
}
Iteration of user-defined collections
foreach (Customer c in customers.OrderBy("name")) {
if (c.Orders.Count != 0) {
...
}
}
Extending foreach
IEnumerable
interface IEnumerable {
IEnumerator GetEnumerator();
}
interface IEnumerator {
bool MoveNext();
object Current { get; }
}
Extending foreach
IEnumerable
foreach (int v in collection) {
// use element v …
}
(IEnumerable) ie = (IEnumerable)
collection;
IEnumerator e = ie.GetEnumerator();
while (e.MoveNext()) {
int v = (int) e.Current;
…
}
foreach
Problems with IEnumerable
no compile time type checking
boxing when enumerating value types
Solution : A pattern-based approach
The C# compiler looks for:
GetEnumerator() on the collection
bool MoveNext() on the enumerator type
Strongly typed Current on the enumerator
type
foreach - Summary
Some Complexity
Extensible
User collections can plug into foreach
User Model
interface
pattern
Compile-time type checking
Performance
Value type access without boxing
Future Directions
Generics - Prototype
Implemented by MSR Cambridge
Don Syme
Andrew Kennedy
Published Paper at PLDI 2001
Generics - Prototype
class Stack<T>
{
T[ ] data;
void Push(T top) { …}
T Pop() { … }
}
Stack<string> ss = new Stack<string>;
ss.Push(“Hello”);
Stack<int> si = new Stack<int>;
ss.Push(4);
Other Approaches – C++
Templates are really typed macros
Compile time instantiations only
Require source for new instantiations
Type Parameter Bounds Infered
Good Execution Speed
Bad Code Size
Other Approaches - Java
Type Erasure
No VM modifications
Compile time type checking
No instantiations on primitive types
Execution Speed – Casts
Good Code Size
Type Identity Problems
List<String> vs. List<Object>
C# .NET Generics Prototype
prototype .NET runtime is generics
aware
All objects carry exact runtime type
Instantiations on reference and value
types
Type Parameters bounded by base
class and/or interfaces
Runtime performs specialization
C# .NET Generics Prototype
Compile Time Experience
Separate compilation of generic types
Instantiations checked at compile time
Can Instantiate on all types – int, string
Runtime Experience
Dynamic Type Specialization
Execution Speed – No Extra Casts
Code Size – Code Sharing reduces bloat