c# language design peter hallam software design engineer c# compiler microsoft corporation
Post on 21-Dec-2015
223 views
TRANSCRIPT
C# Language DesignC# Language Design
Peter HallamPeter HallamSoftware Design EngineerSoftware Design EngineerC# CompilerC# CompilerMicrosoft CorporationMicrosoft Corporation
OverviewOverview
Introduction to C#Introduction to C# Design ProblemsDesign Problems Future DirectionsFuture Directions QuestionsQuestions
Hello WorldHello World
using System;using System;
class Helloclass Hello{{ static void Main() static void Main() { { Console.WriteLine("Hello, world!");Console.WriteLine("Hello, world!"); }}}}
C# Program StructureC# Program Structure NamespacesNamespaces
Contain types and other namespacesContain types and other namespaces
Type declarationsType declarations Classes, structs, interfaces, enums, Classes, structs, interfaces, enums,
and delegatesand delegates
MembersMembers Constants, fields, methods, operators, Constants, fields, methods, operators,
constructors, destructorsconstructors, destructors Properties, indexers, eventsProperties, indexers, events
OrganizationOrganization No header files, code written “in-line”No header files, code written “in-line”
Program Structure ExampleProgram Structure Example
namespace System.Collectionsnamespace System.Collections{{ using System;using System;
public class Stack: Collectionpublic class Stack: Collection {{ Entry top;Entry top;
public void Push(object data) {public void Push(object data) { top = new Entry(top, data);top = new Entry(top, data); }}
public object Pop() {public object Pop() { if (top == null) throw new InvalidOperationException();if (top == null) throw new InvalidOperationException(); object result = top.data;object result = top.data; top = top.next;top = top.next; return result;return result; }} }}}}
Predefined TypesPredefined Types
C# predefined typesC# predefined types The “root”The “root” object object LogicalLogical bool bool SignedSigned sbyte, short, int, long sbyte, short, int, long Unsigned Unsigned byte, ushort, uint, ulong byte, ushort, uint, ulong Floating-pointFloating-point float, double, decimal float, double, decimal TextualTextual char, string char, string
Textual types use Unicode (16-bit characters)Textual types use Unicode (16-bit characters)
C# ClassesC# Classes Single inheritanceSingle inheritance Can implement multiple interfacesCan implement multiple interfaces MembersMembers
Constants, fields, methods, operators, Constants, fields, methods, operators, constructors, destructorsconstructors, destructors
Properties, indexers, events Properties, indexers, events Nested typesNested types Static and instance membersStatic and instance members
Member accessMember access public, protected, internal, privatepublic, protected, internal, private
InterfacesInterfaces
Can contain method declarations; no Can contain method declarations; no code or datacode or data
Defines a “contract” that a class must Defines a “contract” that a class must supportsupport
Classes have one base class, but can Classes have one base class, but can implement many interfacesimplement many interfacesinterface IFormattable {interface IFormattable { string Format(string format);string Format(string format);}}
class DateTime: IFormattable {class DateTime: IFormattable { public string Format(string format) {…}public string Format(string format) {…}}}
Statements and Statements and ExpressionsExpressions Very similar to C++, with some changes to increase Very similar to C++, with some changes to increase
robustnessrobustness No ‘No ‘->->’ or ‘’ or ‘::::’; all qualification uses ‘’; all qualification uses ‘..’’ Local variables must be initialized before useLocal variables must be initialized before use ifif, , whilewhile, , dodo require bool condition require bool condition gotogoto can’t jump into blocks can’t jump into blocks switchswitch statement – no fall through statement – no fall through Expression statements must do something useful Expression statements must do something useful
(assignment or call)(assignment or call)
void Foo() { void Foo() {void Foo() { void Foo() { i == 1; // error if (i = 1) // error i == 1; // error if (i = 1) // error } ...} ...
C# Design GoalsC# Design Goals
Simple, Extensible Type System Simple, Extensible Type System
11stst Class Component Support Class Component Support
Robust and VersionableRobust and Versionable
Preserve existing investmentsPreserve existing investments
Problem:Problem:How to Unify the Type SystemHow to Unify the Type System A single universal base type (“object”)A single universal base type (“object”)
All types ultimately inherit from objectAll types ultimately inherit from object Object variable can hold Object variable can hold anyany value value Any piece of data can be stored, Any piece of data can be stored,
transported, and manipulated with no transported, and manipulated with no extra workextra work
Unification enables:Unification enables: Calling virtual functions on any valueCalling virtual functions on any value Collection classes for any typeCollection classes for any type
Unifying the Type SystemUnifying the Type System
Desired Picture:Desired Picture:
StreamStream
MemoryStreamMemoryStream FileStreamFileStream
HashtableHashtable doubledoubleintint
objectobject
How to deal with the primitive types How to deal with the primitive types without losing performance?without losing performance?
How to create user-defined types that How to create user-defined types that are as efficient as “int” or “double”?are as efficient as “int” or “double”?
How to Unify:How to Unify:A traditional approach (SmallTalk)A traditional approach (SmallTalk)
Make everything a real objectMake everything a real object Performance implicationsPerformance implications
All objects have a type descriptor or virtual All objects have a type descriptor or virtual function tablefunction table
May require all object to be heap-allocated to May require all object to be heap-allocated to prevent dangle pointersprevent dangle pointers
Behavior and expectation mismatchBehavior and expectation mismatch ““int” variables can be “null”int” variables can be “null”
How to Unify:How to Unify:Don’t do it (Eiffel, Java)Don’t do it (Eiffel, Java)
Intrinsic types are not classesIntrinsic types are not classes Good performanceGood performance Can’t convert “int” to “Object” – the Can’t convert “int” to “Object” – the
primitive types are in a separate worldprimitive types are in a separate world Requires special wrapper classes (e.g., Requires special wrapper classes (e.g.,
“Integer”) to “wrap” a primitive type so “Integer”) to “wrap” a primitive type so that it works in the “Object” world.that it works in the “Object” world.
Not extensible – the set of primitive types Not extensible – the set of primitive types is fixed.is fixed.
How to Unify:How to Unify:C# ApproachC# Approach Types are divides into two kinds: Types are divides into two kinds: ReferenceReference types and types and ValueValue types types
Reference types are full-featured:Reference types are full-featured: Always allocated in heapAlways allocated in heap Arbitrary derivationArbitrary derivation
Value types have restrictions:Value types have restrictions: Only inherit from objectOnly inherit from object Can’t be used as base classesCan’t be used as base classes Allocated from stack or inline inside other Allocated from stack or inline inside other
objectsobjects Assignment copies value, not referenceAssignment copies value, not reference
UnificationUnification Value types don’t need type Value types don’t need type
descriptors or vtables (efficient!)descriptors or vtables (efficient!) ““object” does need a type descriptor, object” does need a type descriptor,
because it can contain any typebecause it can contain any type Value types become reference types Value types become reference types
when they are converted to “object”when they are converted to “object” Value is copied to heap, type descriptor Value is copied to heap, type descriptor
attachedattached Process is called “boxing”Process is called “boxing” When cast back to value type, “unboxing” When cast back to value type, “unboxing”
occurs, value is copied out of heapoccurs, value is copied out of heap
Boxing and UnboxingBoxing and Unboxing
““Everything is an object”Everything is an object” Any type can can be stored as an objectAny type can can be stored as an object
int i = 123;int i = 123;
123123i
o
123123
““int”int” }} ““Boxing”Boxing”
j }} ““Unboxing”Unboxing”
??
123123
object o = i;object o = i;int j = (int)o;int j = (int)o;
User-Defined TypesUser-Defined Types C# allows user-defined types to be C# allows user-defined types to be eithereither reference or value types reference or value types
Classes (reference)Classes (reference) Used for most objectsUsed for most objects
Structs (value)Structs (value) Objects that are like primitive data (Point, Objects that are like primitive data (Point,
Complex, etc).Complex, etc).
struct Point { int x, y; ... }struct Point { int x, y; ... }Point sp = new Point(10, 20);Point sp = new Point(10, 20);
C# Type SystemC# Type System
Natural User ModelNatural User Model ExtensibleExtensible PerformantPerformant
Problem: Problem: Additional Declarative InformationAdditional Declarative Information
How do you associate information with How do you associate information with types and members?types and members? XML persistence mapping for a typeXML persistence mapping for a type External code interop informationExternal code interop information Remoting informationRemoting information Transaction context for a methodTransaction context for a method Visual designer information (how should Visual designer information (how should
property be categorized?)property be categorized?) Security contraints (what permissions are Security contraints (what permissions are
required to call this method?)required to call this method?)
Other ApproachesOther Approaches Add keyword or pragmaAdd keyword or pragma
Requires updating the compiler for each Requires updating the compiler for each new piece of informationnew piece of information
Use external fileUse external file Information clumsy to find/seeInformation clumsy to find/see Require duplication of namesRequire duplication of names Example: IDL files for remote proceduresExample: IDL files for remote procedures
Use naming patterns Use naming patterns Create a new class or constant that Create a new class or constant that
describes the class/membersdescribes the class/members Example: Java “BeanInfo” classesExample: Java “BeanInfo” classes
C# Solution: AttributesC# Solution: Attributes
Attach named attributes (with optional Attach named attributes (with optional arguments) to language elementarguments) to language element
Uses simple bracketed syntaxUses simple bracketed syntax Arguments must be constants of Arguments must be constants of
string, number, enum, type-namestring, number, enum, type-name
Attributes - ExamplesAttributes - Examplespublic class OrderProcessor {public class OrderProcessor { [WebMethod][WebMethod] public void SubmitOrder(PurchaseOrder order) {...}public void SubmitOrder(PurchaseOrder order) {...}}}
public class PurchaseOrder {public class PurchaseOrder { [XmlElement("shipTo")] public Address ShipTo;[XmlElement("shipTo")] public Address ShipTo; [XmlElement("billTo")] public Address BillTo;[XmlElement("billTo")] public Address BillTo; [XmlElement("items")] public Item[] Items;[XmlElement("items")] public Item[] Items; [XmlAttribute("date")] public DateTime OrderDate;[XmlAttribute("date")] public DateTime OrderDate;}}
public class Button {public class Button { [Category(Categories.Layout)][Category(Categories.Layout)] public int Width { get {…} set {…} }public int Width { get {…} set {…} }
[Obsolete(“Use DoStuff2 instead”)][Obsolete(“Use DoStuff2 instead”)] public void DoStuff() {…}public void DoStuff() {…}}}
AttributesAttributes AttributesAttributes
Attached to types, members, parameters, and Attached to types, members, parameters, and librarieslibraries
Present in the compiled metadataPresent in the compiled metadata Can by examined by the common language Can by examined by the common language
runtime, by compilers, by the .NET Frameworks, or runtime, by compilers, by the .NET Frameworks, or by user code (using reflection)by user code (using reflection)
ExtensibleExtensible Type-safeType-safe Extensively used in .NET FrameworksExtensively used in .NET Frameworks
XML, Web Services, security, serialization, XML, Web Services, security, serialization, component model, transactions, external code component model, transactions, external code interop…interop…
Creating an AttributeCreating an Attribute
Attributes are simply classesAttributes are simply classes Derived from System.AttributeDerived from System.Attribute Class functionality = attribute functionalityClass functionality = attribute functionality Attribute arguments are constructor Attribute arguments are constructor
argumentsarguments
public class ObsoleteAttribute : System.Attribute public class ObsoleteAttribute : System.Attribute { { public ObsoleteAttribute () { … }public ObsoleteAttribute () { … } public ObsoleteAttribute (string descrip) { … }public ObsoleteAttribute (string descrip) { … }}}
Using the Attribute Using the Attribute [Obsolete] [Obsolete] void Foo() {…}void Foo() {…}
[Obsolete(“Use Baz instead”)] [Obsolete(“Use Baz instead”)] void Bar(int i) {…}void Bar(int i) {…}
When a compiler sees an attribute it:When a compiler sees an attribute it:1.1. Finds the constructor, passing in argsFinds the constructor, passing in args2.2. Checks the types of arguments against Checks the types of arguments against
the constructorthe constructor3.3. Saves a reference to the constructor and Saves a reference to the constructor and
values of the arguments in the metadatavalues of the arguments in the metadata
Querying AttributesQuerying Attributes
Use reflection to query attributesUse reflection to query attributes
Type type = typeof(MyClass); Type type = typeof(MyClass);
foreach(Attribute attr in type.GetCustomAttributes()) foreach(Attribute attr in type.GetCustomAttributes()) { { if ( attr is ObsoleteAttribute ) {if ( attr is ObsoleteAttribute ) { ObsoleteAttribute oa = (ObsoleteAttribute) attr;ObsoleteAttribute oa = (ObsoleteAttribute) attr; Console.WriteLine(“{0} is obsolete: {1}”, Console.WriteLine(“{0} is obsolete: {1}”, type, attr.Description; type, attr.Description; }}}}
Problem : VersioningProblem : Versioning
Once a class library is released, can we add Once a class library is released, can we add functionality without breaking users of the functionality without breaking users of the class library?class library?
Very important for system level components!Very important for system level components!
Versioning ProblemsVersioning Problems
Versioning is overlooked in most languagesVersioning is overlooked in most languages C++ and Java produce fragile base classes C++ and Java produce fragile base classes Users unable to express versioning intentUsers unable to express versioning intent
Adding a virtual method can break a derived Adding a virtual method can break a derived classclass If the derived class already has a method of the If the derived class already has a method of the
same name, breakage can happensame name, breakage can happen
Versioning: C# solutionVersioning: C# solution
C# allows intent to be expressedC# allows intent to be expressed Methods are not virtual by defaultMethods are not virtual by default C# keywords “virtual”, “override” and “new” C# keywords “virtual”, “override” and “new”
provide contextprovide context Adding a base class member never breaks a Adding a base class member never breaks a
derived classderived class Adding or removing a private member never Adding or removing a private member never
breaks another classbreaks another class
C# can't guarantee versioningC# can't guarantee versioning Can enable (e.g., explicit override)Can enable (e.g., explicit override) Can encourage (e.g., smart defaults)Can encourage (e.g., smart defaults)
Versioning ExampleVersioning Example
class Derived: Baseclass Derived: Base // version 1// version 1{{ public virtual void Foo() {public virtual void Foo() { Console.WriteLine("Derived.Foo"); Console.WriteLine("Derived.Foo"); }}}}
class Derived: Baseclass Derived: Base // version 2a// version 2a{{ new public virtual void Foo() {new public virtual void Foo() { Console.WriteLine("Derived.Foo"); Console.WriteLine("Derived.Foo"); }}}}
class Derived: Baseclass Derived: Base // version 2b// version 2b{{ public override void Foo() {public override void Foo() { base.Foo();base.Foo(); Console.WriteLine("Derived.Foo"); Console.WriteLine("Derived.Foo"); }}}}
class Baseclass Base // version 1// version 1{{}}
class Base class Base // version 2 // version 2 {{ public virtual void Foo() {public virtual void Foo() { Console.WriteLine("Base.Foo"); Console.WriteLine("Base.Foo"); }}}}
Interface ImplementationInterface Implementation
Private interface implementationsPrivate interface implementations Resolve interface member conflictsResolve interface member conflicts
interface I {interface I { void foo();void foo();}}interface J {interface J { void foo();void foo();}}
class C: I, J {class C: I, J { void I.foo() {void I.foo() { /* do one thing */ /* do one thing */ }} void J.foo() {void J.foo() { /* do another thing */ /* do another thing */ }}}}
foreach Statementforeach Statement
Iteration of arraysIteration of arrays
Iteration of user-defined collectionsIteration of user-defined collections
foreach (Customer c in customers.OrderBy("name")) {foreach (Customer c in customers.OrderBy("name")) { if (c.Orders.Count != 0) {if (c.Orders.Count != 0) { ...... }}}}
public static void Main(string[] args) {public static void Main(string[] args) { foreach (string s in args) Console.WriteLine(s);foreach (string s in args) Console.WriteLine(s);}}
Extending foreachExtending foreachIEnumerableIEnumerable
interface IEnumerable {interface IEnumerable {
IEnumerator GetEnumerator();IEnumerator GetEnumerator();
}}
interface IEnumerator {interface IEnumerator {
bool MoveNext();bool MoveNext();
object Current { get; }object Current { get; }
}}
Extending foreachExtending foreachIEnumerableIEnumerable
foreach (int v in collection) {foreach (int v in collection) {// use element v …// use element v …
}}
(IEnumerable) ie = (IEnumerable) (IEnumerable) ie = (IEnumerable) collection;collection;
IEnumerator e = ie.GetEnumerator();IEnumerator e = ie.GetEnumerator();while (e.MoveNext()) {while (e.MoveNext()) {
int v = (int) e.Current;int v = (int) e.Current;……
}}
foreachforeach
Problems with IEnumerableProblems with IEnumerable no compile time type checkingno compile time type checking boxing when enumerating value typesboxing when enumerating value types
Solution : A pattern-based approachSolution : A pattern-based approach The C# compiler looks for:The C# compiler looks for:
GetEnumerator() on the collectionGetEnumerator() on the collection bool MoveNext() on the enumerator typebool MoveNext() on the enumerator type Strongly typed Current on the enumerator Strongly typed Current on the enumerator
typetype
foreach - Summaryforeach - Summary
Some ComplexitySome Complexity interfaceinterface patternpattern
ExtensibleExtensible User collections can plug into foreachUser collections can plug into foreach
User ModelUser Model Compile-time type checkingCompile-time type checking
PerformancePerformance Value type access without boxingValue type access without boxing
Future DirectionsFuture Directions
Generics - PrototypeGenerics - Prototype
Implemented by MSR CambridgeImplemented by MSR Cambridge Don SymeDon Syme Andrew KennedyAndrew Kennedy
Published Paper at PLDI 2001Published Paper at PLDI 2001
Generics - PrototypeGenerics - Prototypeclass Stack<T>class Stack<T>{{
T[ ] data;T[ ] data; void Push(T top) { …}void Push(T top) { …}
T Pop() { … }T Pop() { … }}}
Stack<string> ss = new Stack<string>;Stack<string> ss = new Stack<string>;ss.Push(“Hello”);ss.Push(“Hello”);
Stack<int> si = new Stack<int>;Stack<int> si = new Stack<int>;ss.Push(4);ss.Push(4);
Other Approaches – C++Other Approaches – C++
Templates are really typed macrosTemplates are really typed macros Compile time instantiations onlyCompile time instantiations only Require source for new instantiationsRequire source for new instantiations Type Parameter Bounds InferedType Parameter Bounds Infered
Good Execution SpeedGood Execution Speed Bad Code SizeBad Code Size
Other Approaches - JavaOther Approaches - Java
Type ErasureType Erasure No VM modificationsNo VM modifications Compile time type checkingCompile time type checking No instantiations on primitive typesNo instantiations on primitive types Execution Speed – CastsExecution Speed – Casts Good Code SizeGood Code Size Type Identity Problems Type Identity Problems
List<String> vs. List<Object>List<String> vs. List<Object>
C# .NET Generics PrototypeC# .NET Generics Prototype
prototype .NET runtime is generics prototype .NET runtime is generics awareaware
All objects carry exact runtime typeAll objects carry exact runtime type Instantiations on reference and value Instantiations on reference and value
typestypes Type Parameters bounded by base Type Parameters bounded by base
class and/or interfacesclass and/or interfaces Runtime performs specializationRuntime performs specialization
C# .NET Generics PrototypeC# .NET Generics Prototype
Compile Time ExperienceCompile Time Experience Separate compilation of generic typesSeparate compilation of generic types Instantiations checked at compile timeInstantiations checked at compile time Can Instantiate on all types – int, stringCan Instantiate on all types – int, string
Runtime ExperienceRuntime Experience Dynamic Type SpecializationDynamic Type Specialization Execution Speed – No Extra CastsExecution Speed – No Extra Casts Code Size – Code Sharing reduces bloatCode Size – Code Sharing reduces bloat