Brand Objects for Nominal Typing Timothy Jones, Michael Homer, and - - PowerPoint PPT Presentation

brand objects for nominal typing
SMART_READER_LITE
LIVE PREVIEW

Brand Objects for Nominal Typing Timothy Jones, Michael Homer, and - - PowerPoint PPT Presentation

Brand Objects for Nominal Typing Timothy Jones, Michael Homer, and James Noble Victoria University of Wellington {tim,mwh,kjx}@ecs.vuw.ac.nz July 8, 2015 Background This Talk More tagged types The intersection of first-class structural and


slide-1
SLIDE 1

Brand Objects for Nominal Typing

Timothy Jones, Michael Homer, and James Noble Victoria University of Wellington

{tim,mwh,kjx}@ecs.vuw.ac.nz July 8, 2015

slide-2
SLIDE 2

Background

This Talk

More tagged types

The intersection of first-class structural and nominal types Language design issues

Grace

Structurally typed Classes are only sugar

Brand Objects

First-class nominal types Both dynamic and static behaviour Access managed with standard OO encapsulation

1 ECOOP’15

slide-3
SLIDE 3

Background

Motivation

“structural types correspond to the conceptual model of

  • bject-oriented programming where individual objects

communicate only via their interfaces, with their implementations encapsulated”

2 ECOOP’15

slide-4
SLIDE 4

Background

Motivation

“structural types correspond to the conceptual model of

  • bject-oriented programming where individual objects

communicate only via their interfaces, with their implementations encapsulated” — Jones et al.

2 ECOOP’15

slide-5
SLIDE 5

Background

Structural Typing

Only interface matters let Person = type { name → String } def me : Person = object { method name → String { "Tim" } }

3 ECOOP’15

slide-6
SLIDE 6

Background

Structural Typing

Types are implicit let Person = type { name → String } def me = object { method name → String { "Tim" } }

3 ECOOP’15

slide-7
SLIDE 7

Background

Motivation

“often frameworks require inheriting from a specific class with specific hidden state”

4 ECOOP’15

slide-8
SLIDE 8

Background

Motivation

“often frameworks require inheriting from a specific class with specific hidden state” — Sam Tobin-Hochstadt

4 ECOOP’15

slide-9
SLIDE 9

Background

Why Grace

Why not address this problem using Racket?

First-class classes Type erasure

5 ECOOP’15

slide-10
SLIDE 10

Background

Why Grace

Why not address this problem using Racket?

First-class classes Type erasure Dialects aren’t #lang

5 ECOOP’15

slide-11
SLIDE 11

Background

Motivation

“I do not see how a number object in Grace can for sure recognize another number object in the first place” — Marco Servetto

6 ECOOP’15

slide-12
SLIDE 12

Background

Brands as Hybrids

Class names equipped with extra structural information class Window { · · · } method scrollUp(win : Window { scrollBar → ScrollBar }) { win.scrollBar.position := 0 } No structural type without a class name

Top type is Object {}

7 ECOOP’15

slide-13
SLIDE 13

Background

Brand Objects

Objects are not associated with a class let ScrollWindow = Window & type { scrollBar → ScrollBar } method scrollUp(win : ScrollWindow) { win.scrollBar.position := 0 } Structural types are a separate construct

Top type is type {}

8 ECOOP’15

slide-14
SLIDE 14

Background

Reification

Types are reified as objects at runtime instanceof checks performed with a match() method if(Person.match(me)) then { print "I’m a person!" } Type-safe branching with match() case() match(animal) case { dog : Dog → · · · } case { cat : Cat → · · · }

9 ECOOP’15

slide-15
SLIDE 15

Background

Reification

Types are reified as objects at runtime

10 ECOOP’15

slide-16
SLIDE 16

Background

Reification

Types are

  • bjects

10 ECOOP’15

slide-17
SLIDE 17

Background

Reification

Types are

  • bjects

We just happen to (occasionally) reason about them statically

10 ECOOP’15

slide-18
SLIDE 18

Brand Objects

Brand Objects

We can build new kinds of objects and treat them as types too

Brands are just objects: no language extensions needed

11 ECOOP’15

slide-19
SLIDE 19

Brand Objects

Constructing a Brand

The brand method let aSquare = brand

12 ECOOP’15

slide-20
SLIDE 20

Brand Objects

Applying Brands

Branding an object

  • bject is aSquare {

inherits shape.at(2 @ 5) method area → Number { · · · } } Uses the existing annotation system

13 ECOOP’15

slide-21
SLIDE 21

Brand Objects

Applying Brands

Branding a class class square.at(location : Point) withLength(length : Number) → Shape is aSquare { inherits shape.at(location) method area → Number { · · · } }

14 ECOOP’15

slide-22
SLIDE 22

Brand Objects

Brand Types

Brand objects are distinct from their corresponding types let Square = aSquare.Type class square.at(location : Point) withLength(length : Number) → Square is aSquare { inherits shape.at(location) method area → Number { · · · } }

15 ECOOP’15

slide-23
SLIDE 23

Brand Objects

Brand Types

Brand objects are distinct from their corresponding types let Square = aSquare.Type & Shape class square.at(location : Point) withLength(length : Number) → Square is aSquare { inherits shape.at(location) method area → Number { · · · } } Combined with structural types to build ‘full’ nominal types

15 ECOOP’15

slide-24
SLIDE 24

Brand Objects

Inheritance

Inheritance preserves subtyping def mySquare : Square = object { inherits square.at(2 @ 5) withLength(20) }

16 ECOOP’15

slide-25
SLIDE 25

Brand Objects

Extending Brands

Branding the whole shape hierarchy let aShape = brand let Shape = aShape.Type let aSquare = aShape.extend let aCircle = aShape.extend def mySquare : Square = object is aSquare {}

17 ECOOP’15

slide-26
SLIDE 26

Brand Objects

Extending Brands

Branding the whole shape hierarchy let aShape = brand let Shape = aShape.Type let aSquare = aShape.extend let aCircle = aShape.extend def mySquare : Shape = object is aSquare {}

17 ECOOP’15

slide-27
SLIDE 27

Brand Objects

Extending Brands

Multiple subtyping let aSquaredCircle = aSquare + aCircle def mySquare : Square = object is aSquaredCircle { · · · } def myCircle : Circle = mySquare

18 ECOOP’15

slide-28
SLIDE 28

Brand Objects

Extending Brands

Works in both directions let SquaredCircle = aSquaredCircle.Type def both : SquaredCircle = object is aSquare, aCircle {}

19 ECOOP’15

slide-29
SLIDE 29

Brand Objects

Permissions

See the ECMAScript strawman for Trademarks™ “Given the brander one can readily create a guard. On the other hand, one cannot obtain the brander given just the guard of a trademark. Thus the brander of a trademark is a capability.”

20 ECOOP’15

slide-30
SLIDE 30

Brand Objects

Permissions

Standard object encapsulation provides necessary restrictions let aSquare is confidential = brand let Square is public = aSquare.Type Modules are just objects

21 ECOOP’15

slide-31
SLIDE 31

Brand Objects

Branding Dialect

Is our language extensibility powerful enough to introduce radically new type constructs?

22 ECOOP’15

slide-32
SLIDE 32

Brand Objects

Branding Dialect

brand method, with dynamic behaviour Accompanying static checker All branding features also provided by the language

Dialect checking Annotations Encapsulation First-class type interface

23 ECOOP’15

slide-33
SLIDE 33

Brand Objects

Types as a Library

Building types using existing language constructs

Interesting for existing dynamically-typed languages

24 ECOOP’15

slide-34
SLIDE 34

Brand Objects

Types as a Library

We claim it would be significantly more difficult to add structural types to an existing nominally-typed (class-based) system

Syntax Infrastructure Reflection

More than just the sum

25 ECOOP’15

slide-35
SLIDE 35

Brand Objects

‘Nominal’ Typing

Names remain irrelevant

Only the identity of the brand matters

Must be bound to a name to be useful

Static checker tracks brand identities as locally-bound definitions

Names are useful!

This is true for structural types as well Mitigated with a little let magic

26 ECOOP’15

slide-36
SLIDE 36

Brand Objects

‘Nominal’ Typing

There is exactly one use case for an anonymous brand let None = brand.Type

27 ECOOP’15

slide-37
SLIDE 37

Brand Objects

Static Reasoning

Dialect reasons about brands it can statically resolve Observes each request to brand and introduces a new type let aSquare = brand The brand method returns a value of type Brand

28 ECOOP’15

slide-38
SLIDE 38

Brand Objects

Static Reasoning

Behind the scenes, the type of each application is different let aThing1 : Brand = brand let aThing2 : Brand = brand

29 ECOOP’15

slide-39
SLIDE 39

Brand Objects

Static Reasoning

Behind the scenes, the type of each application is different let aThing1 : BrandaThing1 = brand let aThing2 : BrandaThing2 = brand This isn’t really expressible in the syntax

(But it doesn’t need to be)

29 ECOOP’15

slide-40
SLIDE 40

Brand Objects

Static Reasoning

Brand is a regular type, and its values can be reasoned about method using(aThing : Brand) { let Thing = aThing.Type def thing : Thing = object is aThing { · · · } · · · }

30 ECOOP’15

slide-41
SLIDE 41

Brand Objects

Static Reasoning

We don’t have dependent types method make(aThing : Brand) → aThing.Type {

  • bject is aThing { · · · }

} Lee et al.

31 ECOOP’15

slide-42
SLIDE 42

Formal Model

Formalisation

Extension to Tinygrace

32 ECOOP’15

slide-43
SLIDE 43

Formal Model

Normalization

T ⊢ τ T ⊢ let X = τ ⊲ µX.τ

µX.τ contractive

T ⊢ B ⊲ B′ T ⊢ let X = B ⊲ B′ T ⊢ brand ⊲ β

β fresh

T ⊢ X ⊲ X

let X = B ∈ T

T ⊢ B1 ⊲ B′

1

T ⊢ B2 ⊲ B′

2

T ⊢ B1 + B2 ⊲ B′

1 + B′ 2

33 ECOOP’15

slide-44
SLIDE 44

Formal Model

Modifications

Existing + Branding Tinygrace Unity Tagging Syntax 7 + 4 9 + 5 5 + 5 Well-formedness 8 + 5 4 + 2 3 + 2 Subtyping 13 + 3 13 + 3 2 + 2 Term typing 5 + 1 9 + 2 6 + 4 Reduction 7 + 0 14 + 4 3 + 4 Total 40 + 13 49 + 16 19 + 17

34 ECOOP’15

slide-45
SLIDE 45

Formal Model

Soundness

Branding has a minimal impact on soundness

35 ECOOP’15

slide-46
SLIDE 46

Remaining Questions

Language Design Questions

What is a ‘type’? The let definition

Use cases feed back into language design

36 ECOOP’15

slide-47
SLIDE 47

Remaining Questions

Class-name types

Encode the one-brand-per-class pattern as an annotation class Shape.new is nominal { · · · }

37 ECOOP’15

slide-48
SLIDE 48

Conclusion

Types are whatever you want them to be!

So long as you can work out static reasoning for them

Libraries of types

With extensible language features

Easier to start with a structurally-typed base

Classes aren’t necessary for nominal typing

38 ECOOP’15

slide-49
SLIDE 49

Links

tim@ecs.vuw.ac.nz http://drops.dagstuhl.de/opus/volltexte/2015/5231/ http://ecs.vuw.ac.nz/~tim/publications/talks/ecoop2015.pdf

Kim’s talk tomorrow

39 ECOOP’15

slide-50
SLIDE 50

Extra Slides

40 ECOOP’15

slide-51
SLIDE 51

Case Studies

The AST

Type hierarchy does not match node hierarchy Custom pattern objects are not types rule { vn : Var → !vn.vallue.isImplicit }

41 ECOOP’15

slide-52
SLIDE 52

Case Studies

Exceptions

All exception objects have the same interface We want to have a standard catch construct catch { e : IOError → print "An IO error occurred: {e}" } Moves an internal implementation into the language

42 ECOOP’15

slide-53
SLIDE 53

Case Studies

Singleton and Empty Types

The empty structural type is the top type We can build a proper unit type by branding exactly one object let theUnit is confidential = brand let Unit is public = theUnit.Type def unit is public = object is theUnit {} The Type of an anonymous brand is guaranteed to be empty let None = brand.Type

43 ECOOP’15

slide-54
SLIDE 54

Implementation

Brands as a dialect

brand constructor, with dynamic behaviour Accompanying static checker Remainder of features provided by the language

Dialect checking Annotations First-class type interface

44 ECOOP’15

slide-55
SLIDE 55

Implementation

Brands as a case study

Is our language extensibility powerful enough? let is new

Brands aren’t types Unclear semantics for type declarations

45 ECOOP’15

slide-56
SLIDE 56

Implementation

Pre-Branding

All brands are themselves branded There must be some initial ‘pre-brand’ let BrandInterface = ObjectAnnotation & type { Type → Pattern extend → Brand +(other : Brand) → Brand } class preBrand.new → BrandInterface { · · · }

46 ECOOP’15

slide-57
SLIDE 57

Implementation

Pre-Branding

The brand constructor puts it all together let aBrand = preBrand.new let Brand = aBrand.Type & BrandInterface method brand → Brand {

  • bject is aBrand { inherits preBrand.new }

}

47 ECOOP’15

slide-58
SLIDE 58

Implementation

Matching

Each brand is equipped with a weak set When an object is branded, it is placed in the set When asked to match() against an object, a brand’s Type checks its presence in the set

48 ECOOP’15

slide-59
SLIDE 59

Implementation

‘Nominal’ Typing

Names remain irrelevant

Only the identity of the brand matters

Must be bound to a name to be useful

Static checker tracks brand identities as locally-bound definitions

Names are useful!

This is true for structural types as well Mitigated with a little let magic

49 ECOOP’15

slide-60
SLIDE 60

Lack of imagination?

“Branding was, I think, a reasonable trade-off to make in

  • 1983. I don’t think that it’s reasonable any longer.”

— Andrew Black

50 ECOOP’15

slide-61
SLIDE 61

Pre-Branding

All brands are themselves branded There must be some initial ‘pre-brand’ let BrandInterface = ObjectAnnotation & type { Type → Pattern extend → Brand +(other : Brand) → Brand } class preBrand.new → BrandInterface { · · · }

51 ECOOP’15

slide-62
SLIDE 62

Pre-Branding

The brand constructor puts it all together let aBrand = preBrand.new let Brand = aBrand.Type & BrandInterface method brand → Brand {

  • bject is aBrand { inherits preBrand.new }

}

52 ECOOP’15

slide-63
SLIDE 63

AST Nodes

AST is used by the dialect type checkers Many of the nodes have the same structural interface let Decl = Node & type { name → String value → Expression pattern → Expression } Cannot safely use types to match against different node kinds match(decl) case { varNode : Var → print "A var!" } case { defNode : Def → print "A def!" }

53 ECOOP’15

slide-64
SLIDE 64

AST Nodes

Branding the nodes provides distinct, nominal types Depends on the implementation

(Requires brands to be part of the standard language)

54 ECOOP’15

slide-65
SLIDE 65

Dialect Typing

Without brands, the node types are just run-time patterns def Var = object { inherits pattern.abstract method match(o : Object) → MatchResult { Decl.match(o).andAlso { m.kind ≡ "var" } } } The type system doesn’t know that this is a type

55 ECOOP’15

slide-66
SLIDE 66

Dialect Typing

Within a rule, the node is untyped rule { varNode : Var → if (varNode.vallue.isEmpty) then { · · · } } If the dialect is built in the branding dialect, all of the node patterns can be treated as static types

56 ECOOP’15

slide-67
SLIDE 67

Exceptions

The exception hierarchy can now be implemented in Grace class exceptionKind.name(name : String) brand(aKind : Brand) → ExceptionKind { method match(obj : Object) → MatchResult { aKind.Type.match(obj) } · · · }

57 ECOOP’15

slide-68
SLIDE 68

Exceptions

The exception hierarchy can now be implemented in Grace class exceptionKind.name(name : String) brand(aKind : Brand) → ExceptionKind { method raise(message : String) → None {

  • bject is aKind { inherits exception; raise(message) }

} · · · }

57 ECOOP’15

slide-69
SLIDE 69

Exceptions

The exception hierarchy can now be implemented in Grace class exceptionKind.name(name : String) brand(aKind : Brand) → ExceptionKind { method refine(name : String) → ExceptionKind { exceptionKind.name(name) brand(aKind.extend) } · · · }

57 ECOOP’15

slide-70
SLIDE 70

Exceptions

The top of the hierarchy: let Exception = exceptionKind.name "Exception" brand(brand)

58 ECOOP’15

slide-71
SLIDE 71

Syntax

O ::= object is B { M } (Object constructor) τ ::= type { S } | µX.τ | X | (τ | τ) | (τ & τ) | B.Type (Type) B ::= brand | B + B | X | β (Brand expression) E ::= τ | B (Static expression) T ::= let X = E (Static declaration)

59 ECOOP’15

slide-72
SLIDE 72

Well-formedness

Taking the type of any brand is well-formed T ⊢ B ⊲ B′ T ⊢ B.Type

60 ECOOP’15

slide-73
SLIDE 73

Subtyping

Reflexivity just for named brands Σ ⊢ β.Type <: β.Type Σ ⊢ B1.Type & B2.Type <: τ Σ ⊢ (B1 + B2).Type <: τ Σ ⊢ τ <: B1.Type & B2.Type Σ ⊢ τ <: (B1 + B2).Type

61 ECOOP’15

slide-74
SLIDE 74

Type Membership

· ⊢ and(type { S }, B.Type) <: τ

  • bject is B { method S { e } } ∈ τ

62 ECOOP’15

slide-75
SLIDE 75

Typing

· ⊢ type { S } Γ, self : and(type { S }, B.Type) ⊢ method S { e } Γ ⊢ object is B { method S { e } } : and(type { S }, B.Type)

63 ECOOP’15

slide-76
SLIDE 76

Gradual Guarantee

Only permit runtime type testing on brand types? Loses much of the ‘reified objects’ story

64 ECOOP’15