TL10: Dynamic Languages on .NET

gayheadtibburInternet and Web Development

Feb 5, 2013 (4 years and 8 months ago)

351 views



Jim Hugunin


Partner Architect


Microsoft Corporation

TL10

By: public.resource.org

http://flickr.com/photos/publicresourceorg/493955228/

Dynamic

Languages

Simple and succinct

Implicitly typed

Meta
-
programming

No compilation

Static

Languages

Robust

Performant

Intelligent tools

Better scaling

Python

Binder

Ruby

Binder

COM

Binder

JavaScript

Binder

Object

Binder

Dynamic Language Runtime

Expression Trees

Dynamic Dispatch

Call Site Caching

IronPython

IronRuby

C#

VB.NET

Others…














H
igher

numbers are better

0K
20K
40K
60K
80K
100K
IronPython

0.1

Python

2.3

IronPython

1.0

Python

2.5

Python

2.1

46K

90K

80K

50K

36K

#include <
Python.h
>


typedef

struct

{


PyObject_HEAD


PyObject

*first; /* first name */


PyObject

*last; /* last name */


int

number;

}
Noddy
;


static
PyTypeObject

noddy_NoddyType

= {


PyObject_HEAD_INIT
(NULL
)


0, /*
ob_size
*/


"
noddy.Noddy
", /*
tp_name
*/


sizeof
(
noddy_NoddyObject
),
/*
tp_basicsize
*/


0, /*
tp_itemsize
*/


0, /*
tp_dealloc
*/


0, /*
tp_print
*/


0, /*
tp_getattr
*/


0, /*
tp_setattr
*/


0, /*
tp_compare
*/


0, /*
tp_repr
*/


0, /*
tp_as_number
*/


0, /*
tp_as_sequence
*/


0, /*
tp_as_mapping
*/


0, /*
tp_hash

*/


0, /*
tp_call
*/


0, /*
tp_str
*/


0, /*
tp_getattro
*/


0, /*
tp_setattro
*/


0, /*
tp_as_buffer
*/


Py_TPFLAGS_DEFAULT
, /*
tp_flags
*/


"
Noddy

objects
", /*
tp_doc

*/

};

static
PyMethodDef

noddy_methods
[] = {


{NULL} /* Sentinel */

};


#
ifndef

PyMODINIT_FUNC

/* declarations for DLL import/export */

#define
PyMODINIT_FUNC

void

#
endif

PyMODINIT_FUNC

initnoddy
(void)

{


PyObject
* m;



noddy_NoddyType.tp_new

=
PyType_GenericNew
;


if (
PyType_Ready
(&
noddy_NoddyType
) < 0)


return;



m = Py_InitModule3("
noddy
",
noddy_methods
,


"Example module that creates an extension type.");



Py_INCREF
(&
noddy_NoddyType
);


PyModule_AddObject
(m, "
Noddy
", (
PyObject

*)&
noddy_NoddyType
);

}



static void

Noddy_dealloc
(
Noddy
* self)

{


Py_XDECREF
(self
-
>first);


Py_XDECREF
(self
-
>last);


self
-
>
ob_type
-
>
tp_free
((
PyObject
*)
self);

}


static
PyObject

*

Noddy_new
(
PyTypeObject

*type,
PyObject

*
args
,
PyObject

*
kwds
)

{


Noddy

*self;



self = (
Noddy

*)type
-
>
tp_alloc
(type, 0);


if (self != NULL) {


self
-
>first =
PyString_FromString
("");


if (self
-
>first == NULL)


{


Py_DECREF
(self);


return NULL;


}




self
-
>last =
PyString_FromString
("");


if (self
-
>last == NULL)


{


Py_DECREF
(self);


return NULL;


}



self
-
>number = 0;


}



return (
PyObject

*)self;

}

static
int

Noddy_init
(
Noddy

*self,
PyObject

*
args
,
PyObject

*
kwds
)

{


PyObject

*first=NULL, *last=NULL, *
tmp
;



static char *
kwlist
[] = {"first", "last", NULL};



if (!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
, "|OO",
kwlist
,


&first, &last))


return
-
1;



if (first) {


tmp

= self
-
>first;


Py_INCREF
(first);


self
-
>first = first;


Py_XDECREF
(
tmp
);


}



if (last) {


tmp

= self
-
>last;


Py_INCREF
(last);


self
-
>last = last;


Py_XDECREF
(
tmp
);


}



return 0;

}



static
PyMemberDef

Noddy_members
[] = {


{"first", T_OBJECT_EX,
offsetof
(
Noddy
, first), 0,


"first name"},


{"last", T_OBJECT_EX,
offsetof
(
Noddy
, last), 0,


"last name"},


{NULL} /* Sentinel */

};

static
int

Noddy_init
(
Noddy

*self,
PyObject

*
args
,
PyObject

*
kwds
)

{


PyObject

*first=NULL, *last=NULL, *
tmp
;



static char *
kwlist
[] = {"first", "last", NULL};



if (!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
, "|OO",
kwlist
,


&first, &last))


return
-
1;



if (first) {


tmp

= self
-
>first;


Py_INCREF
(first);


self
-
>first = first;


Py_XDECREF
(
tmp
);


}



if (last) {


tmp

= self
-
>last;


Py_INCREF
(last);


self
-
>last = last;


Py_XDECREF
(
tmp
);


}



return 0;

}

namespace

noddy

{


public

class

Noddy

{


public

string

first, last;


public

Noddy
(
string

first,
string

last) {


this
.first

= first;


this
.last

= last;


}


}

}

Python
Objects

C
-
Based

Objects

py1

c2

.NET Objects

py1

c2























My Own Story

TL44:
IronRuby
: The Right Language for the Right Job

John Lam in Room 515B

Today at 5:15PM


Just after this talk!

.NET ?.?

DLR2

.NET 4.0

.NET 3.5

LINQ

DLR

.NET 2.0

.NET 1.0

GC

BCL

Reflection

JIT

Generics

In Runtime

Expression

Trees

Extension

Methods

Expression

Trees v2

Call Site
Caching

Dynamic

Dispatch

Dynamic

Codegen

Verifier

Sandbox

Silverlight

Fast

Delegates

Dynamic

Methods

Script
Hosting

Compiler as

a Service

???

Calculator

calc =
GetCalculator
();

int

sum =
calc.Add
(10, 20);

object

calc =
GetCalculator
();

Type

calcType

=
calc.GetType
();

object

res =
calcType.InvokeMember
(
"Add"
,


BindingFlags.InvokeMethod
,
null
,


new

object
[] { 10, 20 });

int

sum = Convert.ToInt32(res);

ScriptObject

calc =
GetCalculator
();

object

res =
calc.Invoke
(
"Add"
, 10, 20);

int

sum =
Convert
.ToInt32(res);

dynamic

calc =
GetCalculator
();

int

sum =
calc.Add
(10, 20);

Statically

typed to
be dynamic

Dynamic method
invocation

Dynamic
conversion

Object

Binder

Python

Binder

Ruby

Binder

COM

Binder

Dynamic Language Runtime

GetMember

Name=“
Foo
”,
IgnoreCase
=false

IronPython

x.Foo

IronRuby

x.Foo

C#

x.Foo

VB.NET

x.Foo

Others…

$x{
Foo
}, …

Your

Binder

?

Action

Python

Ruby

C#

VB.NET

GetMember

x.Foo

x.Foo

x.Foo

x.Foo

SetMember

x.Foo

=

y

x.Foo

= y

x.Foo

= y

x.Foo

= y

DeleteMember

del
d.Foo

x.send

:
remove_instance_variable

:@
foo

No syntax

No syntax

UnaryOperation

-
x

-
x

-
x

-
x

BinaryOperation

x + y

x + y

x + y

x + y

Convert

No syntax

No syntax

(
Foo
)x

CType
(
x,
Foo
)

InvokeMember

x.Foo
(
a,b
)
2

x.Foo
(
a,b
)

x.Foo
(
a,b
)

x.Foo
(
a,b
)

Invoke

x(
a,b
)

x.call
(
a,b
)
1

x(
a,b
)

x(
a,b
)

CreateInstance

X(
a,b
)

X.new
(
a,b
)

new X(
a,b
)

Not dynamic

New X(
a,b
)

Not

dynamic

GetIndex

x[
a,b
]

x[
a,b
]

x[
a,b
]

x(
a,b
)

SetIndex

x[
a,b
] = y

x[
a,b
] = y

x[
a,b
] = y

X(
a,b
) = y

DeleteIndex

del x[
a,b
]

No syntax

No syntax

No syntax

1: Calling a proc rather than a method; 2: this is always a
GetMember

followed by a Invoke

public

abstract

class

DynamicObject

:
IDynamicObject

{


public

virtual

object

GetMember
(
GetMemberBinder

info){…}


public

virtual

void
SetMember
(
SetMemberBinder

info,
object

value){…}


public

virtual

void
DeleteMember
(
DeleteMemberBinder

info){…}



public

virtual

object

UnaryOperation
(
UnaryOperationBinder

info){…}


public

virtual

object

BinaryOperation
(
BinaryOperationBinder

info,
object

arg
){…}


public

virtual

object

Convert(
ConvertBinder

info){…}



public

virtual

object

Invoke(
InvokeBinder

info,
object
[]
args
){…}


public

virtual

object

InvokeMember
(
InvokeMemberBinder

info,
object
[]
args
){…}


public

virtual

object

CreateInstance
(
CreateInstanceBinder

info,
object
[]
args
){…}



public

virtual

object

GetIndex
(
GetIndexBinder

info,
object
[] indices){…}


public

virtual

void
SetIndex
(
SetIndexBinder
,
object
[] indices,
object

value){…}


public

virtual

void
DeleteIndex
(
DeleteIndexBinder

info,
object
[] indices){…}



public

MetaObject

IDynamicObject
.GetMetaObject
() { … }

}






Return

If

Parameter

n

Constant

0

BinaryOp

-

BinaryOp

==

MethodCall

Program.fact

BinaryOp

*

Constant

1

Parameter

n

Parameter

n

Constant

1

Return

static
int

fact(
int

n) {


if
(n == 0) {


return
1;


} else

{


return n *
fact(n
-

1
);


}

}

Return

If

Parameter

n

Constant

0

Dynamic

CSharpOp
[
-
]

Dynamic

CSharpOp
[==]

MethodCall

Program.fact

Dynamic

CSharpOp
[*]

Constant

1

Parameter

n

Parameter

n

Constant

1

Return

static dynamic fact(dynamic n) {


if
(n == 0) {


return
1;


} else

{


return n *
fact(n
-

1
);


}

}

def
fact(n
):


if n
==
0
:


return 1


else:


return n *
fact(n
-

1)

Return

If

Parameter

n

Constant

0

Dynamic

PythonOp
[
-
]

Dynamic

PythonOp
[==]

Dynamic

PythonInvoke

Dynamic

PythonOp
[*]

Constant

1

Parameter

n

Parameter

n

Constant

1

Return

Property

Value

Field

$
global.fact

def
fact(n)


if n
== 0


1


else


n
*
fact(n
-

1
)


end

end

If

Parameter

n

Constant

0

MethodCall

Ruby.IsTrue

Dynamic

RubyOp
[
-
]

Dynamic

RubyOp
[==]

Dynamic

RubyCall
[fact]

Dynamic

RubyOp
[*]

Parameter

self

Constant

1

Parameter

n

Parameter

n

Constant

1

x

* 2

Assume x = 2,000,000,000

In Python

x

* 2 = 4,000,000,000

In Ruby

x

* 2 = 4,000,000,000

My 7 year old daughter

x

* 2 = 4,000,000,000

In C#

x

* 2
=
-
294,967,296 //typed as
int


Or
OverflowException

//checked

Or 4,000,000,000 //typed as long














static

CallSite
<
Func
<
CallSite
,
object
,
int
,
bool
>
>
_site = …;

if

(_
site.Target
(_site, x, 0)) { … }

if

(x == 0) { … }

static

bool

_0(
Site

site
,
object

x,
int

y) {


return

site.Update
(site, x, y); //
tailcall

}

static

CallSite
<
Func
<
CallSite
,
object
,
int
,
bool
>
>
_site = …;

if

(_
site.Target
(_site, x, 0)) { … }

if

(x == 0) { … }

static

bool

_1(
Site

site
,
object

x,
int

y) {


if

(x is
int
) {


return

(
int
)x == y;


}
else

{


return

site.Update
(site, x, y); //
tailcall


}

}

static

CallSite
<
Func
<
CallSite
,
object
,
int
,
bool
>
>
_site = …;

if

(_
site.Target
(_site, x, 0)) { … }

if

(x == 0) { … }

static

bool

_2(
Site

site
,
object

x,
int

y) {


if

(x is
int
) {


return

(
int
)x == y;


}
else

if

(x
is

BigInteger
) {


return

BigInteger
.op_Equality
((
BigInteger
)x, y);


}
else

{


return

site.Update
(site, x, y); //
tailcall


}

}

Generic

Update

Target

Test

Parameter

x

BinaryOp

==

TypeIs

int

Cast

int

Parameter

y

Parameter

x

If

Field

Update

MethodCall

Invoke

Parameter

site

Parameter

x

Parameter

y

Parameter

x

BinaryOp

==

TypeIs

int

Cast

int

Parameter

y

Parameter

x

If

Field

Update

MethodCall

Invoke

Parameter

site

Parameter

x

Parameter

y

Parameter

x

MethodCall

Op_Equality

TypeIs

BigInteger

Cast

BigInteger

Parameter

y

Parameter

x

If

MetaObject

Target

Test

Parameter

x

BinaryOp

==

TypeIs

int

Cast

int

Parameter

y

Parameter

x

Test

Parameter

x

TypeIs

List

Target

Property

Count

Cast

List

Parameter

x

Test

Parameter

x

TypeIs

DynamicObject

Target

MethodCall

GetMember

Cast

DynamicObject

Constant

GetMemberBinder
(“Count”)

Parameter

x


Target

Test

Parameter

x

Property

Slot0

TypeIs

FastBag

Cast

FastBag

Parameter

x

public

abstract

class

MetaObject

{


public

Restrictions
Restrictions

{ get; }


public

Expression
Expression

{ get; }



public

virtual

MetaObject

BindGetMember
(
GetMemberBinder

info){…}


public

virtual

MetaObject

BindSetMember
(
SetMemberBinder

info,
MetaObject

value){…}


public

virtual

MetaObject

BindDeleteMember
(
DeleteMemberBinder

info){…}



public

virtual

MetaObject

BindUnaryOperation
(
UnaryOperationBinder

info){…}


public

virtual

MetaObject

BindBinaryOperation
(
BinaryOperationBinder

info,
MetaObject

arg
){…}


public

virtual

MetaObject

BindConvert
(
ConvertBinder

info){…}



public

virtual

MetaObject

BindInvoke
(
InvokeBinder

info,
MetaObject
[]
args
){…}


public

virtual

MetaObject

BindInvokeMember
(
InvokeMemberBinder

info,
MetaObject
[]
args
){…}


public

virtual

MetaObject

BindCreateInstance
(
CreateInstanceBinder

info,
MetaObject
[]
args
){…}



public

virtual

MetaObject

BindGetIndex
(
GetIndexBinder

info,
MetaObject
[]
indices){…}


public

virtual

MetaObject

BindSetIndex
(
SetIndexBinder
,
MetaObject
[]
inds
,
MetaObject

value){…}


public

virtual

MetaObject

BindDeleteIndex
(
DeleteIndexBinder

info,
MetaObject
[]
indices
){…}

}

Parameter

z

BinaryOp

==

TypeIs

int
[]

Constant

Map Function

Parameter

x

AndAlso

Parameter

y

TypeIs

Func
<
int,object
>

map(f,
my_ints
)

Python

Binder

Ruby

Binder

COM

Binder

JavaScript

Binder

Object

Binder

Dynamic Language Runtime

Expression Trees

Dynamic Dispatch

Call Site Caching

IronPython

IronRuby

C#

VB.NET

Others…



http://codeplex.com/ironpython






http://codeplex.com/ironpython




www.microsoftpdc.com

©
2008 Microsoft
Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademar
ks
and/or trademarks in the U.S. and/or other countries.

The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the
dat
e of this presentation. Because Microsoft must respond to changing market
conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accu
rac
y of any information provided after the date of this presentation.

MICROSOFT
MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.