Slide 1

Slide 1 text

Nonhierarchical OOP Shawn M Moore @sartak Best Practical Solutions 1 Sunday, April 25, 2010

Slide 2

Slide 2 text

"Object" 2 Sunday, April 25, 2010 Before we get into the thick of it let's talk about the _essence_ of object-oriented programming. What is an object? The best definition I've heard is that an object has "state", "behavior", and "identity". I got this definition from Pascal Costanza, a Lisper, but he got it from this book. Probably a good book but I haven't read it.

Slide 3

Slide 3 text

"Object" •state 2 Sunday, April 25, 2010 Before we get into the thick of it let's talk about the _essence_ of object-oriented programming. What is an object? The best definition I've heard is that an object has "state", "behavior", and "identity". I got this definition from Pascal Costanza, a Lisper, but he got it from this book. Probably a good book but I haven't read it.

Slide 4

Slide 4 text

"Object" •state •behavior 2 Sunday, April 25, 2010 Before we get into the thick of it let's talk about the _essence_ of object-oriented programming. What is an object? The best definition I've heard is that an object has "state", "behavior", and "identity". I got this definition from Pascal Costanza, a Lisper, but he got it from this book. Probably a good book but I haven't read it.

Slide 5

Slide 5 text

"Object" •state •behavior •identity 2 Sunday, April 25, 2010 Before we get into the thick of it let's talk about the _essence_ of object-oriented programming. What is an object? The best definition I've heard is that an object has "state", "behavior", and "identity". I got this definition from Pascal Costanza, a Lisper, but he got it from this book. Probably a good book but I haven't read it.

Slide 6

Slide 6 text

"Object" •state •behavior •identity Object Oriented Design with Applications - Grady Booch 2 Sunday, April 25, 2010 Before we get into the thick of it let's talk about the _essence_ of object-oriented programming. What is an object? The best definition I've heard is that an object has "state", "behavior", and "identity". I got this definition from Pascal Costanza, a Lisper, but he got it from this book. Probably a good book but I haven't read it.

Slide 7

Slide 7 text

state •attributes •member variables •properties •values •slots 3 Sunday, April 25, 2010 Hopefully you recognize at least one of these terms. It's unfortunate that the OOP community as a whole hasn't embraced a common lexicon for this concept. Each language seems to invent its own terminology. State is information that each object carries. It doesn't even have to be inside the object's data structure, as Perl's inside-out objects demonstrate.

Slide 8

Slide 8 text

state •attributes •member variables •properties •values •slots •Ξοτ෺ 4 Sunday, April 25, 2010 Ruby rocks, just sayin

Slide 9

Slide 9 text

behavior •methods 5 Sunday, April 25, 2010 I don't know of any language that calls the unit of behavior something else. Yay! Mission accomplished.

Slide 10

Slide 10 text

identity 6 Sunday, April 25, 2010 Identity is a little more nebulous. Say we have a merchant named Fanty. And we have another merchant named Mingo. They're not the same merchant, so comparison between them returns false. So identity basically it means that two objects, even if they have the same state and behavior, are distinct. Just because Fanty and Mingo have the same state - that their job is merchant - and the same behavior - which is no behavior - they are still separate objects. They are different instances. They each were created by separate calls to a constructor.

Slide 11

Slide 11 text

identity var fanty = { job: 'merchant', }; 6 Sunday, April 25, 2010 Identity is a little more nebulous. Say we have a merchant named Fanty. And we have another merchant named Mingo. They're not the same merchant, so comparison between them returns false. So identity basically it means that two objects, even if they have the same state and behavior, are distinct. Just because Fanty and Mingo have the same state - that their job is merchant - and the same behavior - which is no behavior - they are still separate objects. They are different instances. They each were created by separate calls to a constructor.

Slide 12

Slide 12 text

identity var fanty = { job: 'merchant', }; var mingo = { job: 'merchant', }; 6 Sunday, April 25, 2010 Identity is a little more nebulous. Say we have a merchant named Fanty. And we have another merchant named Mingo. They're not the same merchant, so comparison between them returns false. So identity basically it means that two objects, even if they have the same state and behavior, are distinct. Just because Fanty and Mingo have the same state - that their job is merchant - and the same behavior - which is no behavior - they are still separate objects. They are different instances. They each were created by separate calls to a constructor.

Slide 13

Slide 13 text

identity var fanty = { job: 'merchant', }; var mingo = { job: 'merchant', }; fanty == mingo // false 6 Sunday, April 25, 2010 Identity is a little more nebulous. Say we have a merchant named Fanty. And we have another merchant named Mingo. They're not the same merchant, so comparison between them returns false. So identity basically it means that two objects, even if they have the same state and behavior, are distinct. Just because Fanty and Mingo have the same state - that their job is merchant - and the same behavior - which is no behavior - they are still separate objects. They are different instances. They each were created by separate calls to a constructor.

Slide 14

Slide 14 text

identity var fanty = { job: 'merchant', }; var mingo = { job: 'merchant', }; fanty == mingo // false x x 7 Sunday, April 25, 2010 Sorry for the syntax error. I do this a LOT because I'm a Perl guy. Just ask Cornelius and Gugod who keep fixing my Javascript.

Slide 15

Slide 15 text

identity mingo.job = 'investor'; fanty.job // still merchant 8 Sunday, April 25, 2010 If objects did not have identity, then changing Mingo's job might change Fanty's as well, and that would become really confusing. Talk about heisenbugs.

Slide 16

Slide 16 text

"Object" •state •behavior •identity 9 Sunday, April 25, 2010 So this gives us a very broad definition of object-oriented programming. I'd say this is all you *really* need to call a language object-oriented.

Slide 17

Slide 17 text

"Object" Unnecessary: 10 Sunday, April 25, 2010 So what did we leave out? You don't need classes for OOP. For example, Javascript. Though it has classes, they're kind of a pain. Javascript programmers seem happier to forsake class-based OOP for prototype-based OOP. You also don't need inheritance. I looked into it, the only existent OOP language that lacked inheritance is early versions of Visual Basic. Inheritance is useful for structuring medium and large programs, for sure, but I could easily envision a modern OOP language without inheritance. We'll talk more about what kind of design it might use. Finally you also don't need polymorphism, which lets an object act in place of another as long as it is sufficiently similar. There are various ways to do this, such as duck typing, interfaces, and roles. We'll be talking a lot about these today. They're all certainly useful, don't get me wrong, but it is useful to examine what we stand to gain by stretching them or even ignoring them entirely.

Slide 18

Slide 18 text

•classes "Object" Unnecessary: 10 Sunday, April 25, 2010 So what did we leave out? You don't need classes for OOP. For example, Javascript. Though it has classes, they're kind of a pain. Javascript programmers seem happier to forsake class-based OOP for prototype-based OOP. You also don't need inheritance. I looked into it, the only existent OOP language that lacked inheritance is early versions of Visual Basic. Inheritance is useful for structuring medium and large programs, for sure, but I could easily envision a modern OOP language without inheritance. We'll talk more about what kind of design it might use. Finally you also don't need polymorphism, which lets an object act in place of another as long as it is sufficiently similar. There are various ways to do this, such as duck typing, interfaces, and roles. We'll be talking a lot about these today. They're all certainly useful, don't get me wrong, but it is useful to examine what we stand to gain by stretching them or even ignoring them entirely.

Slide 19

Slide 19 text

•classes •inheritance "Object" Unnecessary: 10 Sunday, April 25, 2010 So what did we leave out? You don't need classes for OOP. For example, Javascript. Though it has classes, they're kind of a pain. Javascript programmers seem happier to forsake class-based OOP for prototype-based OOP. You also don't need inheritance. I looked into it, the only existent OOP language that lacked inheritance is early versions of Visual Basic. Inheritance is useful for structuring medium and large programs, for sure, but I could easily envision a modern OOP language without inheritance. We'll talk more about what kind of design it might use. Finally you also don't need polymorphism, which lets an object act in place of another as long as it is sufficiently similar. There are various ways to do this, such as duck typing, interfaces, and roles. We'll be talking a lot about these today. They're all certainly useful, don't get me wrong, but it is useful to examine what we stand to gain by stretching them or even ignoring them entirely.

Slide 20

Slide 20 text

•classes •inheritance •polymorphism "Object" Unnecessary: 10 Sunday, April 25, 2010 So what did we leave out? You don't need classes for OOP. For example, Javascript. Though it has classes, they're kind of a pain. Javascript programmers seem happier to forsake class-based OOP for prototype-based OOP. You also don't need inheritance. I looked into it, the only existent OOP language that lacked inheritance is early versions of Visual Basic. Inheritance is useful for structuring medium and large programs, for sure, but I could easily envision a modern OOP language without inheritance. We'll talk more about what kind of design it might use. Finally you also don't need polymorphism, which lets an object act in place of another as long as it is sufficiently similar. There are various ways to do this, such as duck typing, interfaces, and roles. We'll be talking a lot about these today. They're all certainly useful, don't get me wrong, but it is useful to examine what we stand to gain by stretching them or even ignoring them entirely.

Slide 21

Slide 21 text

•classes •inheritance •polymorphism "Object" Unnecessary: but useful! 10 Sunday, April 25, 2010 So what did we leave out? You don't need classes for OOP. For example, Javascript. Though it has classes, they're kind of a pain. Javascript programmers seem happier to forsake class-based OOP for prototype-based OOP. You also don't need inheritance. I looked into it, the only existent OOP language that lacked inheritance is early versions of Visual Basic. Inheritance is useful for structuring medium and large programs, for sure, but I could easily envision a modern OOP language without inheritance. We'll talk more about what kind of design it might use. Finally you also don't need polymorphism, which lets an object act in place of another as long as it is sufficiently similar. There are various ways to do this, such as duck typing, interfaces, and roles. We'll be talking a lot about these today. They're all certainly useful, don't get me wrong, but it is useful to examine what we stand to gain by stretching them or even ignoring them entirely.

Slide 22

Slide 22 text

Inheritance 11 Sunday, April 25, 2010 Inheritance is definitely a good way to enable code reuse and extensibility. As long as your code is well-factored, users will be able to reuse your code and change the parts of it that they need to.

Slide 23

Slide 23 text

Inheritance •reuse 11 Sunday, April 25, 2010 Inheritance is definitely a good way to enable code reuse and extensibility. As long as your code is well-factored, users will be able to reuse your code and change the parts of it that they need to.

Slide 24

Slide 24 text

Inheritance •reuse •extensibility 11 Sunday, April 25, 2010 Inheritance is definitely a good way to enable code reuse and extensibility. As long as your code is well-factored, users will be able to reuse your code and change the parts of it that they need to.

Slide 25

Slide 25 text

Inheritance Devel::StackTrace 12 Sunday, April 25, 2010 Devel::StackTrace is a Perl module that provides a nice interface for creating and inspecting stack traces. It gives you an object-oriented API for looking at a stack and each of the frames inside it.

Slide 26

Slide 26 text

Inheritance Devel::StackTrace Devel::StackTrace::WithLexicals 13 Sunday, April 25, 2010 I extended it using the black-magic module PadWalker to produce Devel::StackTrace::WithLexicals. This captures the lexical variables of each stack frame. Handy for writing a debugger or a more advanced error display. Extending Devel::StackTrace let me reuse its code to capture a stack trace, and whatnot. It also let me override individual pieces, like extending the capturing to include PadWalker's lexical inspection. Finally, polymorphism lets anyone use Devel::StackTrace::WithLexicals in place of Devel::StackTrace and everything will just work, since Devel::StackTrace::WithLexicals fulfills all of Devel::StackTrace's API.

Slide 27

Slide 27 text

Inheritance ☺ 14 Sunday, April 25, 2010 So inheritance is pretty good!

Slide 28

Slide 28 text

Inheritance Devel::StackTrace Devel::StackTrace::Profiled 15 Sunday, April 25, 2010 But it's not useful in all cases. Inheritance has its limits. Say we wanted to create a new subclass of Devel::StackTrace that includes timing information for each stack frame.

Slide 29

Slide 29 text

Inheritance Devel::StackTrace::WithLexicals ::AndProfile 16 Sunday, April 25, 2010 What if we wanted to have lexical variables AND a profile in the stack trace?

Slide 30

Slide 30 text

Inheritance 17 Sunday, April 25, 2010 Unfortunately we can only inherit from ONE of these classes.

Slide 31

Slide 31 text

Inheritance Devel::StackTrace::Profiled Devel::StackTrace::WithLexicals Devel::StackTrace::WithLexicals ::AndProfile 17 Sunday, April 25, 2010 Unfortunately we can only inherit from ONE of these classes.

Slide 32

Slide 32 text

Inheritance Devel::StackTrace::WithLexicals + Profiled Devel::StackTrace::WithLexicals ::AndProfile 18 Sunday, April 25, 2010 We could subclass WithLexicals and reimplement Profiled...

Slide 33

Slide 33 text

Inheritance Devel::StackTrace::Profiled + Lexicals Devel::StackTrace::WithLexicals ::AndProfile 19 Sunday, April 25, 2010 Or we could do it the other way around, we could subclass Profiled and reimplement WithLexicals...

Slide 34

Slide 34 text

Inheritance ☹ 20 Sunday, April 25, 2010 This sucks, we can't reuse the code we've already implemented! Reusing code is one of the two major ideals of OOP. So simple inheritance is not powerful enough for real-world problems that we encounter.

Slide 35

Slide 35 text

Multiple Inheritance 21 Sunday, April 25, 2010 So we can just say that Devel::StackTrace::WithLexicals::AndProfile subclasses both WithLexicals and Profiled. That way we can reuse the code of both modules.

Slide 36

Slide 36 text

Multiple Inheritance Devel::StackTrace::Profiled Devel::StackTrace::WithLexicals Devel::StackTrace::WithLexicals ::AndProfile 21 Sunday, April 25, 2010 So we can just say that Devel::StackTrace::WithLexicals::AndProfile subclasses both WithLexicals and Profiled. That way we can reuse the code of both modules.

Slide 37

Slide 37 text

Multiple Inheritance 22 Sunday, April 25, 2010 But this probably won't actually work. WithLexicals and Profiled need to override the same _record_caller_data method to capture information about each stack frame.

Slide 38

Slide 38 text

Multiple Inheritance Devel::StackTrace::WithLexicals after _record_caller_data { ... } 22 Sunday, April 25, 2010 But this probably won't actually work. WithLexicals and Profiled need to override the same _record_caller_data method to capture information about each stack frame.

Slide 39

Slide 39 text

Multiple Inheritance Devel::StackTrace::Profiled Devel::StackTrace::WithLexicals after _record_caller_data { ... } after _record_caller_data { ... } 22 Sunday, April 25, 2010 But this probably won't actually work. WithLexicals and Profiled need to override the same _record_caller_data method to capture information about each stack frame.

Slide 40

Slide 40 text

Multiple Inheritance WithLexicals Profiled Devel::StackTrace 23 Sunday, April 25, 2010 This is the well-known "diamond problem". When we call _record_caller_data, we have to call both WithLexicals and Profiled's overrides or we lose information.

Slide 41

Slide 41 text

Multiple Inheritance $self->_record_caller_data($frame); WithLexicals Profiled Devel::StackTrace 23 Sunday, April 25, 2010 This is the well-known "diamond problem". When we call _record_caller_data, we have to call both WithLexicals and Profiled's overrides or we lose information.

Slide 42

Slide 42 text

Multiple Inheritance WithLexicals Profiled Devel::StackTrace 24 Sunday, April 25, 2010 So typically when you call _record_caller_data, you only call one of the two methods. If we only call WithLexicals, then we won't get timing.

Slide 43

Slide 43 text

Multiple Inheritance $self->_record_caller_data($frame); WithLexicals Profiled Devel::StackTrace 24 Sunday, April 25, 2010 So typically when you call _record_caller_data, you only call one of the two methods. If we only call WithLexicals, then we won't get timing.

Slide 44

Slide 44 text

Multiple Inheritance WithLexicals Profiled Devel::StackTrace 25 Sunday, April 25, 2010 If we only call Profiled then we won't get the lexical variables.

Slide 45

Slide 45 text

Multiple Inheritance $self->_record_caller_data($frame); WithLexicals Profiled Devel::StackTrace 25 Sunday, April 25, 2010 If we only call Profiled then we won't get the lexical variables.

Slide 46

Slide 46 text

Multiple Inheritance 26 Sunday, April 25, 2010 One way to fix this is to explicitly call each of our superclasses' methods.

Slide 47

Slide 47 text

Multiple Inheritance Devel::StackTrace::WithLexicals::AndProfile method _record_caller_data { $self->WithLexicals::_record_caller_data(@_); $self->Profiled::_record_caller_data(@_); } 26 Sunday, April 25, 2010 One way to fix this is to explicitly call each of our superclasses' methods.

Slide 48

Slide 48 text

Multiple Inheritance WithLexicals Profiled Devel::StackTrace 27 Sunday, April 25, 2010 But this sucks because now the Devel::StackTrace's capturing is called twice! Both of the intermediate classes call it. This could cause all sorts of problems. Even if it had no side effects, it would also be a little slower.

Slide 49

Slide 49 text

Multiple Inheritance $self->_record_caller_data($frame); WithLexicals Profiled Devel::StackTrace 27 Sunday, April 25, 2010 But this sucks because now the Devel::StackTrace's capturing is called twice! Both of the intermediate classes call it. This could cause all sorts of problems. Even if it had no side effects, it would also be a little slower.

Slide 50

Slide 50 text

Multiple Inheritance 28 Sunday, April 25, 2010 Furthermore this is a maintenance sink. It breaks encapsulation. Just sucks.

Slide 51

Slide 51 text

Multiple Inheritance Devel::StackTrace::WithLexicals::AndProfile method _record_caller_data { $self->WithLexicals::_record_caller_data(@_); $self->Profiled::_record_caller_data(@_); } 28 Sunday, April 25, 2010 Furthermore this is a maintenance sink. It breaks encapsulation. Just sucks.

Slide 52

Slide 52 text

Multiple Inheritance 29 Sunday, April 25, 2010 Multiple inheritance is a pretty naive attempt at making OOP more flexible. It's just no good.

Slide 53

Slide 53 text

Multiple Inheritance ☹ 29 Sunday, April 25, 2010 Multiple inheritance is a pretty naive attempt at making OOP more flexible. It's just no good.

Slide 54

Slide 54 text

Multiple Inheritance ☹ ☹ ☹ 29 Sunday, April 25, 2010 Multiple inheritance is a pretty naive attempt at making OOP more flexible. It's just no good.

Slide 55

Slide 55 text

Multiple Inheritance ☹ ☹ ☹ ☹☹☹ 29 Sunday, April 25, 2010 Multiple inheritance is a pretty naive attempt at making OOP more flexible. It's just no good.

Slide 56

Slide 56 text

Multiple Inheritance ☹ ☹ ☹ ☹☹☹ ☹☹☹ 29 Sunday, April 25, 2010 Multiple inheritance is a pretty naive attempt at making OOP more flexible. It's just no good.

Slide 57

Slide 57 text

Multiple Inheritance http://www.flickr.com/photos/xwrn/525198268/ 30 Sunday, April 25, 2010 Look at how happy Schwern is that he's using multiple inheritance.

Slide 58

Slide 58 text

MULTIPLE INHERITANCE MUST DIE 31 Sunday, April 25, 2010

Slide 59

Slide 59 text

•Ruby++ •Java++ •C#++ Multiple Inheritance 32 Sunday, April 25, 2010 Thankfully a lot of languages are eschewing multiple inheritance. So we're making progress.

Slide 60

Slide 60 text

•Ruby++ •Java++ •C#++ Multiple Inheritance •PHP++ 32 Sunday, April 25, 2010 Thankfully a lot of languages are eschewing multiple inheritance. So we're making progress.

Slide 61

Slide 61 text

•Ruby++ •Java++ •C#++ Multiple Inheritance •Perl-- •Python-- •CLOS-- •PHP++ 32 Sunday, April 25, 2010 Thankfully a lot of languages are eschewing multiple inheritance. So we're making progress.

Slide 62

Slide 62 text

•Ruby++ •Java++ •C#++ Multiple Inheritance •Perl-- •Python-- •CLOS-- •PHP++ •C++-- 32 Sunday, April 25, 2010 Thankfully a lot of languages are eschewing multiple inheritance. So we're making progress.

Slide 63

Slide 63 text

Other Solutions • Mixins • Traits/Roles 33 Sunday, April 25, 2010 There are two primary solutions for the diamond problem. There are mixins, which are prominently featured in Ruby, but also exist in Python and many other languages. And there are traits/roles, which are new, but have been implemented in Smalltalk, Perl, Scala, and Fortress.

Slide 64

Slide 64 text

Mixins 34 Sunday, April 25, 2010 In short, a mixin is a module. Mixins are not classes, so you are not allowed to instantiate them. And its superclass is parameterized, which is the real magic of mixins. Mixins still make use of inheritance, but each instance of a mixin has its own superclass. This can replace some designs where you would need to resort to multiple inheritance.

Slide 65

Slide 65 text

Mixins •Module 34 Sunday, April 25, 2010 In short, a mixin is a module. Mixins are not classes, so you are not allowed to instantiate them. And its superclass is parameterized, which is the real magic of mixins. Mixins still make use of inheritance, but each instance of a mixin has its own superclass. This can replace some designs where you would need to resort to multiple inheritance.

Slide 66

Slide 66 text

Mixins •Module •No instantiation (no "new") 34 Sunday, April 25, 2010 In short, a mixin is a module. Mixins are not classes, so you are not allowed to instantiate them. And its superclass is parameterized, which is the real magic of mixins. Mixins still make use of inheritance, but each instance of a mixin has its own superclass. This can replace some designs where you would need to resort to multiple inheritance.

Slide 67

Slide 67 text

Mixins •Module •No instantiation (no "new") •Parameterized superclass 34 Sunday, April 25, 2010 In short, a mixin is a module. Mixins are not classes, so you are not allowed to instantiate them. And its superclass is parameterized, which is the real magic of mixins. Mixins still make use of inheritance, but each instance of a mixin has its own superclass. This can replace some designs where you would need to resort to multiple inheritance.

Slide 68

Slide 68 text

Mixins 35 Sunday, April 25, 2010 If WithLexicals and Profiled are mixins, then our subclass can use both of them. Because a mixin lets you choose its superclass, there is no diamond. It's all just single inheritance so everything works.

Slide 69

Slide 69 text

Mixins Profiled WithLexicals WithLexicals::AndProfile Devel::StackTrace 35 Sunday, April 25, 2010 If WithLexicals and Profiled are mixins, then our subclass can use both of them. Because a mixin lets you choose its superclass, there is no diamond. It's all just single inheritance so everything works.

Slide 70

Slide 70 text

Mixins 36 Sunday, April 25, 2010 The _record_caller_data overrides of both Profiled and WithLexicals are called, and the original Devel::StackTrace method is called only once. This is exactly what we want.

Slide 71

Slide 71 text

Mixins $self->_record_caller_data($frame); 36 Sunday, April 25, 2010 The _record_caller_data overrides of both Profiled and WithLexicals are called, and the original Devel::StackTrace method is called only once. This is exactly what we want.

Slide 72

Slide 72 text

Mixins $self->_record_caller_data($frame); Profiled 36 Sunday, April 25, 2010 The _record_caller_data overrides of both Profiled and WithLexicals are called, and the original Devel::StackTrace method is called only once. This is exactly what we want.

Slide 73

Slide 73 text

Mixins $self->_record_caller_data($frame); Profiled WithLexicals 36 Sunday, April 25, 2010 The _record_caller_data overrides of both Profiled and WithLexicals are called, and the original Devel::StackTrace method is called only once. This is exactly what we want.

Slide 74

Slide 74 text

Mixins $self->_record_caller_data($frame); Profiled WithLexicals Devel::StackTrace 36 Sunday, April 25, 2010 The _record_caller_data overrides of both Profiled and WithLexicals are called, and the original Devel::StackTrace method is called only once. This is exactly what we want.

Slide 75

Slide 75 text

Mixins ☺ 37 Sunday, April 25, 2010 Mixins are a great improvement over multiple inheritance.

Slide 76

Slide 76 text

Mixins 38 Sunday, April 25, 2010 Mixins reuse the inheritance mechanism. On one hand, this is nice because inheritance has been around for a while, and people understand it. But mixins use inheritance in an unusual way, so there are some gotchas in the details.

Slide 77

Slide 77 text

Mixins • uses inheritance 38 Sunday, April 25, 2010 Mixins reuse the inheritance mechanism. On one hand, this is nice because inheritance has been around for a while, and people understand it. But mixins use inheritance in an unusual way, so there are some gotchas in the details.

Slide 78

Slide 78 text

Mixins • uses inheritance • ☺ 38 Sunday, April 25, 2010 Mixins reuse the inheritance mechanism. On one hand, this is nice because inheritance has been around for a while, and people understand it. But mixins use inheritance in an unusual way, so there are some gotchas in the details.

Slide 79

Slide 79 text

Mixins • uses inheritance • ☹ • ☺ 38 Sunday, April 25, 2010 Mixins reuse the inheritance mechanism. On one hand, this is nice because inheritance has been around for a while, and people understand it. But mixins use inheritance in an unusual way, so there are some gotchas in the details.

Slide 80

Slide 80 text

Mixins 39 Sunday, April 25, 2010 Let's say we define a mixin for recording lexicals for Devel::StackTrace. We wrap the method that collects data for each frame, which calls a helper method for actually extracting the lexical variables from the stack frame.

Slide 81

Slide 81 text

Mixins mixin WithLexicals 39 Sunday, April 25, 2010 Let's say we define a mixin for recording lexicals for Devel::StackTrace. We wrap the method that collects data for each frame, which calls a helper method for actually extracting the lexical variables from the stack frame.

Slide 82

Slide 82 text

Mixins mixin WithLexicals after _record_caller_data { $self->_record_extra_data } 39 Sunday, April 25, 2010 Let's say we define a mixin for recording lexicals for Devel::StackTrace. We wrap the method that collects data for each frame, which calls a helper method for actually extracting the lexical variables from the stack frame.

Slide 83

Slide 83 text

Mixins mixin WithLexicals after _record_caller_data { $self->_record_extra_data } method _record_extra_data { # extract lexicals } 39 Sunday, April 25, 2010 Let's say we define a mixin for recording lexicals for Devel::StackTrace. We wrap the method that collects data for each frame, which calls a helper method for actually extracting the lexical variables from the stack frame.

Slide 84

Slide 84 text

Mixins mixin Profiled after _record_caller_data { $self->_record_extra_data } method _record_extra_data { # profiling } 40 Sunday, April 25, 2010 And we do the exact same with Profiled.

Slide 85

Slide 85 text

Mixins $self->_record_extra_data($frame); 41 Sunday, April 25, 2010 When the Profiled mixin's wrapper is called, it calls _record_extra_data. The Profiled mixin's _record_extra_data method is called. But not WithLexical's.

Slide 86

Slide 86 text

Mixins $self->_record_extra_data($frame); Profiled 41 Sunday, April 25, 2010 When the Profiled mixin's wrapper is called, it calls _record_extra_data. The Profiled mixin's _record_extra_data method is called. But not WithLexical's.

Slide 87

Slide 87 text

Mixins $self->_record_extra_data($frame); Profiled WithLexicals 41 Sunday, April 25, 2010 When the Profiled mixin's wrapper is called, it calls _record_extra_data. The Profiled mixin's _record_extra_data method is called. But not WithLexical's.

Slide 88

Slide 88 text

Mixins $self->_record_extra_data($frame); 42 Sunday, April 25, 2010 When the WithLexical's mixin's wrapper is called, it again calls _record_extra_data. But there's only a single namespace for methods! The Profiled mixin's _record_extra_data method is called again. But not WithLexical's.

Slide 89

Slide 89 text

Mixins $self->_record_extra_data($frame); Profiled 42 Sunday, April 25, 2010 When the WithLexical's mixin's wrapper is called, it again calls _record_extra_data. But there's only a single namespace for methods! The Profiled mixin's _record_extra_data method is called again. But not WithLexical's.

Slide 90

Slide 90 text

Mixins $self->_record_extra_data($frame); Profiled WithLexicals 42 Sunday, April 25, 2010 When the WithLexical's mixin's wrapper is called, it again calls _record_extra_data. But there's only a single namespace for methods! The Profiled mixin's _record_extra_data method is called again. But not WithLexical's.

Slide 91

Slide 91 text

Mixins ☹ 43 Sunday, April 25, 2010 So mixins have a problem similar to diamond inheritance.

Slide 92

Slide 92 text

Mixins ☹ 44 Sunday, April 25, 2010 Since mixins are better than MI they get a smaller sad face

Slide 93

Slide 93 text

Roles 45 Sunday, April 25, 2010 Roles, which are also called traits, are similar to mixins. A role is a module, so it is a collection of methods and other stuff. You can't instantiate roles, they have no "new" method. And the way roles are different from mixins are that they use a new kind of "composition" instead of inheritance.

Slide 94

Slide 94 text

Roles •Module 45 Sunday, April 25, 2010 Roles, which are also called traits, are similar to mixins. A role is a module, so it is a collection of methods and other stuff. You can't instantiate roles, they have no "new" method. And the way roles are different from mixins are that they use a new kind of "composition" instead of inheritance.

Slide 95

Slide 95 text

Roles •Module •No instantiation (no "new") 45 Sunday, April 25, 2010 Roles, which are also called traits, are similar to mixins. A role is a module, so it is a collection of methods and other stuff. You can't instantiate roles, they have no "new" method. And the way roles are different from mixins are that they use a new kind of "composition" instead of inheritance.

Slide 96

Slide 96 text

Roles •Module •No instantiation (no "new") •Composition not inheritance 45 Sunday, April 25, 2010 Roles, which are also called traits, are similar to mixins. A role is a module, so it is a collection of methods and other stuff. You can't instantiate roles, they have no "new" method. And the way roles are different from mixins are that they use a new kind of "composition" instead of inheritance.

Slide 97

Slide 97 text

Roles • Originally in Smalltalk • in 2002 46 Sunday, April 25, 2010 Many of you have probably never heard of roles. Roles (or traits) were designed in 2002 using Smalltalk. 2002 is a pretty long time ago.

Slide 98

Slide 98 text

47 Sunday, April 25, 2010 It's ancient history as far as the internet is concerned.

Slide 99

Slide 99 text

Lisp • if-then-else • recursive functions • garbage collection • first-class functions • closures • dynamic typing • interactive programming 48 Sunday, April 25, 2010 But 2002 is still cutting edge in terms of language design. Lisp stole all the good ideas in the 60s and 70s. These are all things we take for granted nowadays, but most of these took a long time to get into the mainstream. Only in the last decade or two have these ideas took hold.

Slide 100

Slide 100 text

Mixins Profiled WithLexicals WithLexicals::AndProfile Devel::StackTrace 49 Sunday, April 25, 2010 So this is what mixins look like. They use inheritance which is vertical.

Slide 101

Slide 101 text

Roles Profiled WithLexicals WithLexicals::AndProfile Devel::StackTrace 50 Sunday, April 25, 2010 Roles are horizontal instead. When a class consumes a role, it does not inherit from it, but we say the class "consumes" the role. It's kind of like copying and pasting the code from the role into the class. We call that "flattening" since it's not using inheritance, it puts the code directly into the class.

Slide 102

Slide 102 text

Roles Profiled WithLexicals WithLexicals::AndProfile Devel::StackTrace 51 Sunday, April 25, 2010 So this part is interesting. When a class consumes multiple roles, they are first combined into a single role. Again this is like copying and pasting, but with some protection.

Slide 103

Slide 103 text

Roles 52 Sunday, April 25, 2010 So we have a role. It has a method modifier on the frame capture method. Which calls its own _record_extra_data method.

Slide 104

Slide 104 text

Roles role WithLexicals 52 Sunday, April 25, 2010 So we have a role. It has a method modifier on the frame capture method. Which calls its own _record_extra_data method.

Slide 105

Slide 105 text

Roles role WithLexicals after _record_caller_data { $self->_record_extra_data } 52 Sunday, April 25, 2010 So we have a role. It has a method modifier on the frame capture method. Which calls its own _record_extra_data method.

Slide 106

Slide 106 text

Roles role WithLexicals after _record_caller_data { $self->_record_extra_data } method _record_extra_data { # extract lexicals } 52 Sunday, April 25, 2010 So we have a role. It has a method modifier on the frame capture method. Which calls its own _record_extra_data method.

Slide 107

Slide 107 text

Roles role Profiled after _record_caller_data { $self->_record_extra_data } method _record_extra_data { # profiling } 53 Sunday, April 25, 2010 And again we have a Profiled role, same deal. And we have a method name collision on _record_extra_data.

Slide 108

Slide 108 text

Roles Profiled WithLexicals WithLexicals::AndProfile Devel::StackTrace 54 Sunday, April 25, 2010 When we combine these two roles, there is an ERROR.

Slide 109

Slide 109 text

Roles Profiled WithLexicals WithLexicals::AndProfile Devel::StackTrace ERROR 54 Sunday, April 25, 2010 When we combine these two roles, there is an ERROR.

Slide 110

Slide 110 text

Roles Due to a method name conflict in roles 'Profiled' and 'WithLexicals', the method '_record_extra_data' must be implemented or excluded by 'WithLexicals::AndProfile' 55 Sunday, April 25, 2010 The role system generates a method name conflict. Both of the two roles defined a method with the same name, so roles tell you about that problem. At compile time.

Slide 111

Slide 111 text

Mixins $self->_record_extra_data($frame); Profiled WithLexicals 56 Sunday, April 25, 2010 Remember, this is what happens in a mixin. The compile-time error roles give you is so much nicer than a bug at runtime which may not even make itself obvious. You might never notice that WithLexicals's method is not being called until after you ship to production.

Slide 112

Slide 112 text

Roles $self->_record_caller_data($frame); Profiled WithLexicals Devel::StackTrace 57 Sunday, April 25, 2010 The original diamond problem is also not present for roles because of the flattening.

Slide 113

Slide 113 text

Polymorphism • subclass polymorphism • duck typing • Go interfaces • Java interfaces • roles 58 Sunday, April 25, 2010 Like I said earlier, polymorphism lets an object act in place of another as long as it is sufficiently similar. I'll talk about all these methods to enable polymorphism.

Slide 114

Slide 114 text

Subclass Polymorphism • Liskov substitutition principle 59 Sunday, April 25, 2010 Subclass polymorphism is familiar to all object-oriented programmers. The formal name for it is the Liskov substitution principle. It means that any code that operates on a particular class will handle any subclasses of that class.

Slide 115

Slide 115 text

Subclass Polymorphism my $trace = Devel::StackTrace->new; print trace_to_html($trace); 60 Sunday, April 25, 2010 Say we create a Devel::StackTrace object and pass it to a trace_to_html function which renders it nicely. trace_to_html knows how to handle Devel::StackTrace so everything is fine.

Slide 116

Slide 116 text

Subclass Polymorphism my $trace = Devel::StackTrace::Profiled->new; print trace_to_html($trace); 61 Sunday, April 25, 2010 Now we're passing a subclass of Devel::StackTrace but it should still just work. Devel::StackTrace::Profiled fulfills Devel::StackTrace's API completely, it just provides more methods for inspecting the timings of each frame.

Slide 117

Slide 117 text

Subclass Polymorphism my $trace = Devel::Traceback->new; print trace_to_html($trace); 62 Sunday, April 25, 2010 Say someone else implements a completely different module Devel::Traceback module. It does not use Devel::StackTrace, perhaps because it's written in XS, or the code is cleaner, whatever the reason.

Slide 118

Slide 118 text

Subclass Polymorphism my $trace = Devel::Traceback->new; print trace_to_html($trace); Devel::StackTrace 63 Sunday, April 25, 2010 This won't work though because trace_to_html only accepts Devel::StackTrace objects, not Devel::Traceback objects. And for whatever reason - and there are potentially very many - we don't want Devel::Traceback to inherit from Devel::StackTrace.

Slide 119

Slide 119 text

Subclass Polymorphism 64 Sunday, April 25, 2010 Inheritance for polymorphism is a *lot* to demand of an API. Turns out, again, that inheritance is a lose. A subclass must play nicely with the superclass's state. So they share the object's data structure. This means that, for example, you can't use the same attribute names as any of your superclasses. Your subclass inherits all of the methods that its superclasses has, even if it doesn't want them. Your subclass must provide the same API or it will break in confusing ways. Inheritance itself is not very conducive for encapsulation. Subclasses are affected by a refactoring of a superclass even if the superclass's public API stays the same. If a superclass adds a method then you must ensure that none of the subclasses already have that method, or if they do that it makes sense to override it.

Slide 120

Slide 120 text

Subclass Polymorphism • state 64 Sunday, April 25, 2010 Inheritance for polymorphism is a *lot* to demand of an API. Turns out, again, that inheritance is a lose. A subclass must play nicely with the superclass's state. So they share the object's data structure. This means that, for example, you can't use the same attribute names as any of your superclasses. Your subclass inherits all of the methods that its superclasses has, even if it doesn't want them. Your subclass must provide the same API or it will break in confusing ways. Inheritance itself is not very conducive for encapsulation. Subclasses are affected by a refactoring of a superclass even if the superclass's public API stays the same. If a superclass adds a method then you must ensure that none of the subclasses already have that method, or if they do that it makes sense to override it.

Slide 121

Slide 121 text

Subclass Polymorphism • state • methods 64 Sunday, April 25, 2010 Inheritance for polymorphism is a *lot* to demand of an API. Turns out, again, that inheritance is a lose. A subclass must play nicely with the superclass's state. So they share the object's data structure. This means that, for example, you can't use the same attribute names as any of your superclasses. Your subclass inherits all of the methods that its superclasses has, even if it doesn't want them. Your subclass must provide the same API or it will break in confusing ways. Inheritance itself is not very conducive for encapsulation. Subclasses are affected by a refactoring of a superclass even if the superclass's public API stays the same. If a superclass adds a method then you must ensure that none of the subclasses already have that method, or if they do that it makes sense to override it.

Slide 122

Slide 122 text

Subclass Polymorphism • state • methods • same API 64 Sunday, April 25, 2010 Inheritance for polymorphism is a *lot* to demand of an API. Turns out, again, that inheritance is a lose. A subclass must play nicely with the superclass's state. So they share the object's data structure. This means that, for example, you can't use the same attribute names as any of your superclasses. Your subclass inherits all of the methods that its superclasses has, even if it doesn't want them. Your subclass must provide the same API or it will break in confusing ways. Inheritance itself is not very conducive for encapsulation. Subclasses are affected by a refactoring of a superclass even if the superclass's public API stays the same. If a superclass adds a method then you must ensure that none of the subclasses already have that method, or if they do that it makes sense to override it.

Slide 123

Slide 123 text

Subclass Polymorphism • state • methods • same API • breaks encapsulation 64 Sunday, April 25, 2010 Inheritance for polymorphism is a *lot* to demand of an API. Turns out, again, that inheritance is a lose. A subclass must play nicely with the superclass's state. So they share the object's data structure. This means that, for example, you can't use the same attribute names as any of your superclasses. Your subclass inherits all of the methods that its superclasses has, even if it doesn't want them. Your subclass must provide the same API or it will break in confusing ways. Inheritance itself is not very conducive for encapsulation. Subclasses are affected by a refactoring of a superclass even if the superclass's public API stays the same. If a superclass adds a method then you must ensure that none of the subclasses already have that method, or if they do that it makes sense to override it.

Slide 124

Slide 124 text

Subclass Polymorphism • state • methods • same API • breaks encapsulation • increases coupling 64 Sunday, April 25, 2010 Inheritance for polymorphism is a *lot* to demand of an API. Turns out, again, that inheritance is a lose. A subclass must play nicely with the superclass's state. So they share the object's data structure. This means that, for example, you can't use the same attribute names as any of your superclasses. Your subclass inherits all of the methods that its superclasses has, even if it doesn't want them. Your subclass must provide the same API or it will break in confusing ways. Inheritance itself is not very conducive for encapsulation. Subclasses are affected by a refactoring of a superclass even if the superclass's public API stays the same. If a superclass adds a method then you must ensure that none of the subclasses already have that method, or if they do that it makes sense to override it.

Slide 125

Slide 125 text

Duck Typing "when I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck." -- James Whitcomb Riley 65 Sunday, April 25, 2010 Duck typing is pretty popular in modern dynamic languages like Python, Ruby, and Perl. This kind of quote, which is apparently a common quote in the American South.

Slide 126

Slide 126 text

Duck Typing when I see an object that has a walk method, a swim method, and a quack method, I call that object a duck. 66 Sunday, April 25, 2010 Here it is recontextualized to describe duck typing.

Slide 127

Slide 127 text

Duck Typing if $object->can('walk') && $object->can('swim') && $object->can('quack') { feed($object, 'bread'); } 67 Sunday, April 25, 2010 So what this code does is it checks that the object has walk, swim and duck methods before treating it like a duck. It doesn't have to have yellow feathers or an orange bill, but it's close enough to a duck. $object doesn't have to inherit from the Duck class.

Slide 128

Slide 128 text

Duck Typing sub trace_to_html { unless $trace->can('frame_function') && $trace->can('frame_file') && $trace->can('frame_line') { die "Not stack tracey enough" } ... } 68 Sunday, April 25, 2010 In our example of stack traces, we want to define a common enough API that all stack trace classes can implement. As long as your stack trace defines the three methods we need, then we can use it to generate HTML.

Slide 129

Slide 129 text

Duck Typing my $trace = Devel::StackTrace->new; print trace_to_html($trace); ☺ 69 Sunday, April 25, 2010 So this works.

Slide 130

Slide 130 text

Duck Typing my $trace = Devel::StackTrace::Profiled->new; print trace_to_html($trace); ☺ 70 Sunday, April 25, 2010 Using a subclass works too of course.

Slide 131

Slide 131 text

Duck Typing my $trace = Devel::Traceback->new; print trace_to_html($trace); ☺ 71 Sunday, April 25, 2010 And using an entirely different module works. All that matters is that they provide the same three methods.

Slide 132

Slide 132 text

Duck Typing 72 Sunday, April 25, 2010 So the problems with duck typing are that it only checks method names. It can't check whether the method takes certain kinds of arguments, or what its return value will be. Duck typing can't check that the method will do anything useful or expected. I'll talk more about this later. Also duck typing is very ad hoc. It's not actually a language-level feature. The only language-level feature needed is being able to ask an object whether it has a certain method. Everything else is built on top in a non-introspectable way. It's also kind of hard to maintain. If you want to add a new method to the duck type list you have to update every place you perform that duck type.

Slide 133

Slide 133 text

Duck Typing • Method names 72 Sunday, April 25, 2010 So the problems with duck typing are that it only checks method names. It can't check whether the method takes certain kinds of arguments, or what its return value will be. Duck typing can't check that the method will do anything useful or expected. I'll talk more about this later. Also duck typing is very ad hoc. It's not actually a language-level feature. The only language-level feature needed is being able to ask an object whether it has a certain method. Everything else is built on top in a non-introspectable way. It's also kind of hard to maintain. If you want to add a new method to the duck type list you have to update every place you perform that duck type.

Slide 134

Slide 134 text

Duck Typing • Method names • Very ad-hoc 72 Sunday, April 25, 2010 So the problems with duck typing are that it only checks method names. It can't check whether the method takes certain kinds of arguments, or what its return value will be. Duck typing can't check that the method will do anything useful or expected. I'll talk more about this later. Also duck typing is very ad hoc. It's not actually a language-level feature. The only language-level feature needed is being able to ask an object whether it has a certain method. Everything else is built on top in a non-introspectable way. It's also kind of hard to maintain. If you want to add a new method to the duck type list you have to update every place you perform that duck type.

Slide 135

Slide 135 text

Duck Typing • Method names • Very ad-hoc • Maintenance burden 72 Sunday, April 25, 2010 So the problems with duck typing are that it only checks method names. It can't check whether the method takes certain kinds of arguments, or what its return value will be. Duck typing can't check that the method will do anything useful or expected. I'll talk more about this later. Also duck typing is very ad hoc. It's not actually a language-level feature. The only language-level feature needed is being able to ask an object whether it has a certain method. Everything else is built on top in a non-introspectable way. It's also kind of hard to maintain. If you want to add a new method to the duck type list you have to update every place you perform that duck type.

Slide 136

Slide 136 text

Duck Typing sub trace_to_html { unless $trace->can('frame_function') && $trace->can('frame_file') && $trace->can('frame_line') { die "Not stack tracey enough" } ... } 73 Sunday, April 25, 2010 So here we want to add a new method.

Slide 137

Slide 137 text

Duck Typing sub trace_to_html { unless $trace->can('frame_function') && $trace->can('frame_file') && $trace->can('frame_line') && $trace->can('frame_count') { die "Not stack tracey enough" } ... } 74 Sunday, April 25, 2010 Every time we check whether something is a stack trace, we have to add this additional check.

Slide 138

Slide 138 text

Duck Typing sub trace_to_html { unless $trace->can('frame_function') && $trace->can('frame_file') && $trace->can('frame_line') && $trace->can('frame_count') { die "Not stack tracey enough" } ... } 75 Sunday, April 25, 2010 Also this is not really introspectable for something like Eclipse. It's just a random check in the middle of a method. An IDE wouldn't want to inspect this because it could easily get too complicated to determine except at runtime. So we want more structure than duck typing provides.

Slide 139

Slide 139 text

Go Interfaces 76 Sunday, April 25, 2010 Google Go's interfaces are like duck typing but better. An interface is a named collection of method signatures, so it's an actual entity in your programs instead of the design pattern of duck typing. But it's very similar to duck typing. There are two key differences. One is that interfaces have names. A duck type is just a list of method names. Also, interfaces can also check arguments and return values. Duck types generally check only that methods of the given names exist.

Slide 140

Slide 140 text

Go Interfaces • named 76 Sunday, April 25, 2010 Google Go's interfaces are like duck typing but better. An interface is a named collection of method signatures, so it's an actual entity in your programs instead of the design pattern of duck typing. But it's very similar to duck typing. There are two key differences. One is that interfaces have names. A duck type is just a list of method names. Also, interfaces can also check arguments and return values. Duck types generally check only that methods of the given names exist.

Slide 141

Slide 141 text

Go Interfaces • named • method signature 76 Sunday, April 25, 2010 Google Go's interfaces are like duck typing but better. An interface is a named collection of method signatures, so it's an actual entity in your programs instead of the design pattern of duck typing. But it's very similar to duck typing. There are two key differences. One is that interfaces have names. A duck type is just a list of method names. Also, interfaces can also check arguments and return values. Duck types generally check only that methods of the given names exist.

Slide 142

Slide 142 text

Go Interfaces if !$trace->does('StackTrace') { die } 77 Sunday, April 25, 2010 Because interfaces are named, you can check a single thing - does the object implement the interface - rather than checking every single method. Now when we want to add that frame_count method to this duck type, we only have to do it in a single place, which is in the StackTrace interface. I like it when I don't have to repeat myself.

Slide 143

Slide 143 text

Go Interfaces 78 Sunday, April 25, 2010 Another thing interfaces do is check the entire method signature. Not only the method's name, but we can enforce the types of the arguments and return values. This is more than I've seen from most duck typing. So now we can confirm that, say, frame_count returns an integer. The more of the API we can check, the better the type check is because there will be fewer false positives. Which is kind of the whole point of type checking right?

Slide 144

Slide 144 text

Go Interfaces • Name 78 Sunday, April 25, 2010 Another thing interfaces do is check the entire method signature. Not only the method's name, but we can enforce the types of the arguments and return values. This is more than I've seen from most duck typing. So now we can confirm that, say, frame_count returns an integer. The more of the API we can check, the better the type check is because there will be fewer false positives. Which is kind of the whole point of type checking right?

Slide 145

Slide 145 text

Go Interfaces • Name • Return value 78 Sunday, April 25, 2010 Another thing interfaces do is check the entire method signature. Not only the method's name, but we can enforce the types of the arguments and return values. This is more than I've seen from most duck typing. So now we can confirm that, say, frame_count returns an integer. The more of the API we can check, the better the type check is because there will be fewer false positives. Which is kind of the whole point of type checking right?

Slide 146

Slide 146 text

Go Interfaces • Name • Return value • Arguments 78 Sunday, April 25, 2010 Another thing interfaces do is check the entire method signature. Not only the method's name, but we can enforce the types of the arguments and return values. This is more than I've seen from most duck typing. So now we can confirm that, say, frame_count returns an integer. The more of the API we can check, the better the type check is because there will be fewer false positives. Which is kind of the whole point of type checking right?

Slide 147

Slide 147 text

Go Interfaces 79 Sunday, April 25, 2010 A surprising thing about Go interfaces is that a class that fulfills an interface automatically "does" that interface. The class does not have to declare that it does that interface. This is nice because, like duck typing, it improves decoupling between the interface and the class. This is handy when the class is written without knowledge of the interface, but someone else wants to use the class with functions that require that interface. But it's also a source of problems because it means interfaces cannot declare semantics. This is kind of a subtle point but I will try to explain it.

Slide 148

Slide 148 text

Go Interfaces • not declared -- automatic 79 Sunday, April 25, 2010 A surprising thing about Go interfaces is that a class that fulfills an interface automatically "does" that interface. The class does not have to declare that it does that interface. This is nice because, like duck typing, it improves decoupling between the interface and the class. This is handy when the class is written without knowledge of the interface, but someone else wants to use the class with functions that require that interface. But it's also a source of problems because it means interfaces cannot declare semantics. This is kind of a subtle point but I will try to explain it.

Slide 149

Slide 149 text

Go Interfaces • not declared -- automatic • decoupling 79 Sunday, April 25, 2010 A surprising thing about Go interfaces is that a class that fulfills an interface automatically "does" that interface. The class does not have to declare that it does that interface. This is nice because, like duck typing, it improves decoupling between the interface and the class. This is handy when the class is written without knowledge of the interface, but someone else wants to use the class with functions that require that interface. But it's also a source of problems because it means interfaces cannot declare semantics. This is kind of a subtle point but I will try to explain it.

Slide 150

Slide 150 text

Go Interfaces • not declared -- automatic • decoupling • declaring semantics 79 Sunday, April 25, 2010 A surprising thing about Go interfaces is that a class that fulfills an interface automatically "does" that interface. The class does not have to declare that it does that interface. This is nice because, like duck typing, it improves decoupling between the interface and the class. This is handy when the class is written without knowledge of the interface, but someone else wants to use the class with functions that require that interface. But it's also a source of problems because it means interfaces cannot declare semantics. This is kind of a subtle point but I will try to explain it.

Slide 151

Slide 151 text

Go Interfaces interface NonblockingReader { string read(); } 80 Sunday, April 25, 2010 Say we want an interface for classes that implement a nonblocking read. Something that reads data but does not wait for it if there is no data yet, returning the empty string or null or whatever. So classes which fulfill this interface must have a method named "read" which takes no arguments and returns a string.

Slide 152

Slide 152 text

Go Interfaces class Filesystem { string read(string file) { ... } } 81 Sunday, April 25, 2010 We have a filesystem class. It has a read method, but it takes an argument so it does not fulfill the NonblockingReader interface. A simple duck type for the "read" method would not have caught this, so we're already ahead of the game.

Slide 153

Slide 153 text

Go Interfaces class Filesystem { string read(string file) { ... } } NonblockingReader 81 Sunday, April 25, 2010 We have a filesystem class. It has a read method, but it takes an argument so it does not fulfill the NonblockingReader interface. A simple duck type for the "read" method would not have caught this, so we're already ahead of the game.

Slide 154

Slide 154 text

Go Interfaces class NonblockingSocket { string read() { ... } } 82 Sunday, April 25, 2010 We have a nonblocking socket class. It fulfills the interface entirely. It has a method named read that takes no arguments and returns a string. Great! So this class does the NonblockingReader interface and it didn't even need to declare that.

Slide 155

Slide 155 text

Go Interfaces class NonblockingSocket { string read() { ... } } NonblockingReader 82 Sunday, April 25, 2010 We have a nonblocking socket class. It fulfills the interface entirely. It has a method named read that takes no arguments and returns a string. Great! So this class does the NonblockingReader interface and it didn't even need to declare that.

Slide 156

Slide 156 text

Go Interfaces class BlockingSocket { string read() { ... } } 83 Sunday, April 25, 2010 Now we have a *blocking* socket class. It too fulfills the interface. It has a read method that takes no arguments and returns a string. But it will block so it does not *really* fulfill the interface. But according to the system, it DOES do the interface, because it has that read method! Oh no!

Slide 157

Slide 157 text

Go Interfaces class BlockingSocket { string read() { ... } } NonblockingReader 83 Sunday, April 25, 2010 Now we have a *blocking* socket class. It too fulfills the interface. It has a read method that takes no arguments and returns a string. But it will block so it does not *really* fulfill the interface. But according to the system, it DOES do the interface, because it has that read method! Oh no!

Slide 158

Slide 158 text

Go Interfaces 84 Sunday, April 25, 2010 So because interfaces are implicit, they can be a little dangerous. They may lie about whether an object fulfills an interface or not. But they're also cool! It's an interesting new idea. It may show up in other languages if it turns out to work particularly well in Go. And from what I hear it does work well. It's like duck typing's younger but more refined brother.

Slide 159

Slide 159 text

Go Interfaces • dangerous 84 Sunday, April 25, 2010 So because interfaces are implicit, they can be a little dangerous. They may lie about whether an object fulfills an interface or not. But they're also cool! It's an interesting new idea. It may show up in other languages if it turns out to work particularly well in Go. And from what I hear it does work well. It's like duck typing's younger but more refined brother.

Slide 160

Slide 160 text

Go Interfaces • dangerous • but cool! 84 Sunday, April 25, 2010 So because interfaces are implicit, they can be a little dangerous. They may lie about whether an object fulfills an interface or not. But they're also cool! It's an interesting new idea. It may show up in other languages if it turns out to work particularly well in Go. And from what I hear it does work well. It's like duck typing's younger but more refined brother.

Slide 161

Slide 161 text

Go Interfaces • dangerous • but cool! • duck typing codified 84 Sunday, April 25, 2010 So because interfaces are implicit, they can be a little dangerous. They may lie about whether an object fulfills an interface or not. But they're also cool! It's an interesting new idea. It may show up in other languages if it turns out to work particularly well in Go. And from what I hear it does work well. It's like duck typing's younger but more refined brother.

Slide 162

Slide 162 text

Java Interfaces 85 Sunday, April 25, 2010 Java interfaces are like Go interfaces. They're much older though. Each interface has a name. Each interface checks the full method signature of each method, not just the method's name. And each interface must be explicitly declared. This is better because it avoids the problem of declaring semantics, the blocking reader versus nonblocking reader. This is worse because it requires that the class author knows every single interface that the class implements, even interfaces that are written after the class is published!

Slide 163

Slide 163 text

Java Interfaces • named 85 Sunday, April 25, 2010 Java interfaces are like Go interfaces. They're much older though. Each interface has a name. Each interface checks the full method signature of each method, not just the method's name. And each interface must be explicitly declared. This is better because it avoids the problem of declaring semantics, the blocking reader versus nonblocking reader. This is worse because it requires that the class author knows every single interface that the class implements, even interfaces that are written after the class is published!

Slide 164

Slide 164 text

Java Interfaces • named • method signature 85 Sunday, April 25, 2010 Java interfaces are like Go interfaces. They're much older though. Each interface has a name. Each interface checks the full method signature of each method, not just the method's name. And each interface must be explicitly declared. This is better because it avoids the problem of declaring semantics, the blocking reader versus nonblocking reader. This is worse because it requires that the class author knows every single interface that the class implements, even interfaces that are written after the class is published!

Slide 165

Slide 165 text

Java Interfaces • named • method signature • explicitly declared 85 Sunday, April 25, 2010 Java interfaces are like Go interfaces. They're much older though. Each interface has a name. Each interface checks the full method signature of each method, not just the method's name. And each interface must be explicitly declared. This is better because it avoids the problem of declaring semantics, the blocking reader versus nonblocking reader. This is worse because it requires that the class author knows every single interface that the class implements, even interfaces that are written after the class is published!

Slide 166

Slide 166 text

Java Interfaces • named • method signature • explicitly declared • omniscience a plus 85 Sunday, April 25, 2010 Java interfaces are like Go interfaces. They're much older though. Each interface has a name. Each interface checks the full method signature of each method, not just the method's name. And each interface must be explicitly declared. This is better because it avoids the problem of declaring semantics, the blocking reader versus nonblocking reader. This is worse because it requires that the class author knows every single interface that the class implements, even interfaces that are written after the class is published!

Slide 167

Slide 167 text

Java Interfaces class BlockingSocket implements NonblockingReader { string read() { ... } } 86 Sunday, April 25, 2010 Now this is obviously a lie. If the programmer lies then nothing is safe. But you could certainly yell at him when you discover this during a code review.

Slide 168

Slide 168 text

Roles 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 169

Slide 169 text

Roles • named 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 170

Slide 170 text

Roles • named • method names 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 171

Slide 171 text

Roles • named • method names • extension for method signatures and more 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 172

Slide 172 text

Roles • named • method names • extension for method signatures and more ww 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 173

Slide 173 text

Roles • named • method names • extension for method signatures and more • default implementation ww 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 174

Slide 174 text

Roles • named • method names • extension for method signatures and more • default implementation • explicitly declared ww 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 175

Slide 175 text

Roles • named • method names • extension for method signatures and more • default implementation • explicitly declared • composable ww 87 Sunday, April 25, 2010 Roles are like interfaces too. Each role has a name, so you can ask whether a class performs a role rather than a list of method names. By default roles can only require methods by name. But if you use the MooseX::Role::Parameterized extension, you can require anything that you can write code for. For example that the class provides some method with two "w"s in the name. The big advantage to roles is that they can provide a default implementation for methods. That's one huge problem with Java interfaces. Everyone who wants to fulfill a Java interface has to actually write the code in their class. There's no code reuse with interfaces. But with roles, where you get that default implementation, it's all about reuse.

Slide 176

Slide 176 text

Roles role WithLexicals after _record_caller_data { $self->_record_extra_data } method _record_extra_data { # extract lexicals } 88 Sunday, April 25, 2010 Providing default implementation is not actually new. We saw this earlier when I was showing off role conflict detection. This role is adding a new method - with a full implementation - to the classes that consume it.

Slide 177

Slide 177 text

Roles role WithLexicals after _record_caller_data { $self->_record_extra_data } method _record_extra_data { # extract lexicals } 89 Sunday, April 25, 2010 You can also see that roles can override methods from the consuming class, which may or may not be inherited.

Slide 178

Slide 178 text

Roles if !$trace->does('StackTrace') { die } 90 Sunday, April 25, 2010 And of course because roles are named you can ask an object if it fulfills a particular role. So roles can definitely be used like interfaces to make polymorphism work well. And they can also be used like mixins to enable code reuse.

Slide 179

Slide 179 text

Roles 91 Sunday, April 25, 2010 Or you could do both at the same time. Like here we are declaring an Equality role. It requires that each consumer have a "compare" method. And we give each consumer an "equals" method. It calls the compare method that we required. If a particular consumer wants to optimize this equals method to not require the compare, then that class can define its own equals method with its own logic. It will still perform the Equality role.

Slide 180

Slide 180 text

Roles role Equality 91 Sunday, April 25, 2010 Or you could do both at the same time. Like here we are declaring an Equality role. It requires that each consumer have a "compare" method. And we give each consumer an "equals" method. It calls the compare method that we required. If a particular consumer wants to optimize this equals method to not require the compare, then that class can define its own equals method with its own logic. It will still perform the Equality role.

Slide 181

Slide 181 text

Roles role Equality requires 'compare'; 91 Sunday, April 25, 2010 Or you could do both at the same time. Like here we are declaring an Equality role. It requires that each consumer have a "compare" method. And we give each consumer an "equals" method. It calls the compare method that we required. If a particular consumer wants to optimize this equals method to not require the compare, then that class can define its own equals method with its own logic. It will still perform the Equality role.

Slide 182

Slide 182 text

Roles role Equality requires 'compare'; sub equals { $self->compare($other) == 0 } 91 Sunday, April 25, 2010 Or you could do both at the same time. Like here we are declaring an Equality role. It requires that each consumer have a "compare" method. And we give each consumer an "equals" method. It calls the compare method that we required. If a particular consumer wants to optimize this equals method to not require the compare, then that class can define its own equals method with its own logic. It will still perform the Equality role.

Slide 183

Slide 183 text

Learn More 92 Sunday, April 25, 2010 There are a lot of role features I didn't talk about. None of them are really present in other systems. Aliasing methods lets you rename methods when you consume a role. Excluding methods lets you consume only some methods from a role. Conflict resolution in roles. That's where I started with two roles providing two methods with the same name. Turns out you can resolve such conflicts quite nicely using aliasing and excluding. You don't need to rewrite one of the roles. You can apply a role directly to an object, not just a class. That way only a single object does that role, not the entire class. Maybe that makes it pass more type checks, or maybe that gives it extra methods. Up to you. I think you can also apply mixins directly to an object. There's parameterized roles which let you configure a role differently based on options that the

Slide 184

Slide 184 text

Learn More • aliasing methods 92 Sunday, April 25, 2010 There are a lot of role features I didn't talk about. None of them are really present in other systems. Aliasing methods lets you rename methods when you consume a role. Excluding methods lets you consume only some methods from a role. Conflict resolution in roles. That's where I started with two roles providing two methods with the same name. Turns out you can resolve such conflicts quite nicely using aliasing and excluding. You don't need to rewrite one of the roles. You can apply a role directly to an object, not just a class. That way only a single object does that role, not the entire class. Maybe that makes it pass more type checks, or maybe that gives it extra methods. Up to you. I think you can also apply mixins directly to an object. There's parameterized roles which let you configure a role differently based on options that the

Slide 185

Slide 185 text

Learn More • aliasing methods • excluding methods 92 Sunday, April 25, 2010 There are a lot of role features I didn't talk about. None of them are really present in other systems. Aliasing methods lets you rename methods when you consume a role. Excluding methods lets you consume only some methods from a role. Conflict resolution in roles. That's where I started with two roles providing two methods with the same name. Turns out you can resolve such conflicts quite nicely using aliasing and excluding. You don't need to rewrite one of the roles. You can apply a role directly to an object, not just a class. That way only a single object does that role, not the entire class. Maybe that makes it pass more type checks, or maybe that gives it extra methods. Up to you. I think you can also apply mixins directly to an object. There's parameterized roles which let you configure a role differently based on options that the

Slide 186

Slide 186 text

Learn More • aliasing methods • excluding methods • resolving conflicts 92 Sunday, April 25, 2010 There are a lot of role features I didn't talk about. None of them are really present in other systems. Aliasing methods lets you rename methods when you consume a role. Excluding methods lets you consume only some methods from a role. Conflict resolution in roles. That's where I started with two roles providing two methods with the same name. Turns out you can resolve such conflicts quite nicely using aliasing and excluding. You don't need to rewrite one of the roles. You can apply a role directly to an object, not just a class. That way only a single object does that role, not the entire class. Maybe that makes it pass more type checks, or maybe that gives it extra methods. Up to you. I think you can also apply mixins directly to an object. There's parameterized roles which let you configure a role differently based on options that the

Slide 187

Slide 187 text

Learn More • aliasing methods • excluding methods • resolving conflicts • applying to an object 92 Sunday, April 25, 2010 There are a lot of role features I didn't talk about. None of them are really present in other systems. Aliasing methods lets you rename methods when you consume a role. Excluding methods lets you consume only some methods from a role. Conflict resolution in roles. That's where I started with two roles providing two methods with the same name. Turns out you can resolve such conflicts quite nicely using aliasing and excluding. You don't need to rewrite one of the roles. You can apply a role directly to an object, not just a class. That way only a single object does that role, not the entire class. Maybe that makes it pass more type checks, or maybe that gives it extra methods. Up to you. I think you can also apply mixins directly to an object. There's parameterized roles which let you configure a role differently based on options that the

Slide 188

Slide 188 text

Learn More • aliasing methods • excluding methods • resolving conflicts • applying to an object • parameterized roles 92 Sunday, April 25, 2010 There are a lot of role features I didn't talk about. None of them are really present in other systems. Aliasing methods lets you rename methods when you consume a role. Excluding methods lets you consume only some methods from a role. Conflict resolution in roles. That's where I started with two roles providing two methods with the same name. Turns out you can resolve such conflicts quite nicely using aliasing and excluding. You don't need to rewrite one of the roles. You can apply a role directly to an object, not just a class. That way only a single object does that role, not the entire class. Maybe that makes it pass more type checks, or maybe that gives it extra methods. Up to you. I think you can also apply mixins directly to an object. There's parameterized roles which let you configure a role differently based on options that the

Slide 189

Slide 189 text

Learn More • aliasing methods • excluding methods • resolving conflicts • applying to an object • parameterized roles • new design patterns 92 Sunday, April 25, 2010 There are a lot of role features I didn't talk about. None of them are really present in other systems. Aliasing methods lets you rename methods when you consume a role. Excluding methods lets you consume only some methods from a role. Conflict resolution in roles. That's where I started with two roles providing two methods with the same name. Turns out you can resolve such conflicts quite nicely using aliasing and excluding. You don't need to rewrite one of the roles. You can apply a role directly to an object, not just a class. That way only a single object does that role, not the entire class. Maybe that makes it pass more type checks, or maybe that gives it extra methods. Up to you. I think you can also apply mixins directly to an object. There's parameterized roles which let you configure a role differently based on options that the

Slide 190

Slide 190 text

Learn More http://scg.unibe.ch/research/traits http://tinyurl.com/traits-papers http://search.cpan.org/perldoc?Moose::Manual::Roles http://tinyurl.com/roles-manual http://sartak.org/talks/osdc.tw-2010/nonhierarchical-oop/ http://tinyurl.com/nh-oop-talk 93 Sunday, April 25, 2010 If you want to learn more about the origins of roles, their initial implementation and design using Smalltalk, and their formal specification, check out the first link. It's worth noting that roles depart from these original traits in that they are allowed to have attributes. That's kind of a long story, but it turns out it's a really useful feature to have, even if it makes some things harder. If you want to learn more about the current best implementation of roles, which is in Perl's Moose object system, check out the second link. The second link is more for human being users of roles, whereas the first link is for super hackers who are building roles into a language. The third link is of course these slides.

Slide 191

Slide 191 text

Thank you! 94 Sunday, April 25, 2010

Slide 192

Slide 192 text

Thank you! • Thank you 94 Sunday, April 25, 2010

Slide 193

Slide 193 text

Thank you! • Thank you • ँँ 94 Sunday, April 25, 2010

Slide 194

Slide 194 text

Thank you! • Thank you • ँँ • ༗Γ೉͏͍͟͝·ͨ͠ 94 Sunday, April 25, 2010