Slide 1

Slide 1 text

Парадигми в езиците за програмиране Стефан Кънев http://skanev.com/ @skanev OpenFest 3 ноември 2012 София

Slide 2

Slide 2 text

Стефан

Slide 3

Slide 3 text

twitter: @skanev github: skanev blog: http://skanev.com/

Slide 4

Slide 4 text

⽃⽄ Ruby, Ruby, Ruby ̆̇㽈

Slide 5

Slide 5 text

Ruby & Python

Slide 6

Slide 6 text

Всеки път

Slide 7

Slide 7 text

“Разчупен лед”

Slide 8

Slide 8 text

Днес нямам време за това!

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Aspect-Oriented Programming Object-Oriented Programming Functional Programming Imperative Programming Structured Programming Logical Programming Language-Oriented Programming

Slide 14

Slide 14 text

ще гледаме нещата отгоре-отгоре

Slide 15

Slide 15 text

размисли на които ме навеждат

Slide 16

Slide 16 text

Wikipedia дефинира “програмна парадигма” като фундаментален стил за програмиране (или “парадигмален стил за програмиране”)

Slide 17

Slide 17 text

семантика организация възможности runtime

Slide 18

Slide 18 text

семантика кое какво значи

Slide 19

Slide 19 text

организация как и на какво разделяме програмата

Slide 20

Slide 20 text

възможности какво е разрешено и какво е забранено

Slide 21

Slide 21 text

runtime код, работещ заедно с програмата ни

Slide 22

Slide 22 text

няколко неща за парадигмите

Slide 23

Slide 23 text

Един език може да е едновременно функционален и обектно-ориентиран

Slide 24

Slide 24 text

Няма нито “чисто обектно-ориентирани” езици, нито “чисто функционални” езици.

Slide 25

Slide 25 text

Парадигмите нямат еднозначна дефиниция. Няма конкретно свойство, което да прави езика функционален или нефункционален.

Slide 26

Slide 26 text

No silver-bullet-oriented programming

Slide 27

Slide 27 text

Aspect-Oriented Programming

Slide 28

Slide 28 text

AspectJ

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

[ˈzɛrɒks,]

Slide 31

Slide 31 text

Искаме да преведем пари от една сметка в друга...

Slide 32

Slide 32 text

void transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger) throws Exception { Transaction = new Transaction(); try { transaction.begin(); logger.info("Transferring money..."); if (!checkUserPermission(user)) { logger.info("User has no permission."); throw new UnauthorizedUserException(); } if (fromAcc.getBalance() < amount) { logger.info("Insufficient funds, sorry."); throw new InsufficientFundsException(); } fromAcc.withdraw(amount); toAcc.deposit(amount); transaction.commit(); logger.info("Successful transaction."); } catch(Exception e) { transaction.rollback(); throw e; } }

Slide 33

Slide 33 text

void transfer(Account fromAcc, Account toAcc, int amount) throws Exception { if (fromAcc.getBalance() < amount) { logger.info("Insufficient funds, sorry."); throw new InsufficientFundsException(); } fromAcc.withdraw(amount); toAcc.deposit(amount); }

Slide 34

Slide 34 text

Трансфер Заем Погасяване Logging Transactions Authorization Cross-cutting concerns

Slide 35

Slide 35 text

aspect TransactionLogging { before(): target(Account) && call(void withdraw(int)) { Logger.getLogger().info("Transferring money..."); } } COMEFROM

Slide 36

Slide 36 text

Разделя кода на малки, независими и тестваеми парчета.

Slide 37

Slide 37 text

@transactions @logging @authenticate def transfer(sender, receiver, amount): if sender.balance() < amount: raise "Insufficient funds" sender.withdraw(amount) receiver.deposit(amount) Подобно, но не AOP

Slide 38

Slide 38 text

Object-Oriented Programming

Slide 39

Slide 39 text

...или грешните неща, на които ни учиха в училище.

Slide 40

Slide 40 text

Данни + Функци = Обекти

Slide 41

Slide 41 text

Alan Kay

Slide 42

Slide 42 text

Разделяме програмата на малки, независими компоненти, които си общуват с изпращане на съобщения.

Slide 43

Slide 43 text

Алан Кей твърди, че обмяната на съобщения между обектите е по- важна от самите обекти. http://lists.squeakfoundation.org/pipermail/squeak-dev/1998-October/017019.html

Slide 44

Slide 44 text

Добрия обектно-ориентиран дизайн има много на брой, малки на размер, прости класове. Същината му е в комуникацията между тях.

Slide 45

Slide 45 text

Основната ценност е улесняване на поддръжката и разширяемостта на системата.

Slide 46

Slide 46 text

много прост пример

Slide 47

Slide 47 text

collection = MusicCollection.new extract_songs(input).each do |song| collection.songs << song end Лош обектно-ориентиран код

Slide 48

Slide 48 text

collection = MusicCollection.new extract_songs(input).each do |song| collection.add_song(song) end Добър обектно-ориентиран код

Slide 49

Slide 49 text

още по-прост пример

Slide 50

Slide 50 text

public static float area(Circle circle) { return PI * circle.radius * circle.radius; } Лош обектно-ориентиран код

Slide 51

Slide 51 text

class Circle { public float area() { return PI * radius * radius; } } Добър обектно-ориентиран код

Slide 52

Slide 52 text

Наследяване

Slide 53

Slide 53 text

Наследяването се използва по-рядко, отколкото учебниците ни карат да си мислим.

Slide 54

Slide 54 text

Причина №1 наследяването да е неразбрано

Slide 55

Slide 55 text

Slide 56

Slide 56 text

Основната теза на книгата е “предпочитайте композиция пред наследяване”. За нещастие, остава неразбрана.

Slide 57

Slide 57 text

Наследяването има две предназначения в повечето езици за програмиране.

Slide 58

Slide 58 text

Преизползване на код Моделиране на релация IS (подтип) OK Бърз път към ада

Slide 59

Slide 59 text

Liskov Substitution Principle

Slide 60

Slide 60 text

Liskov Substitution Principle

Slide 61

Slide 61 text

Клас Child може да наследява клас Parent, само ако на всички места, на които програмата приема Parent може да подадем Child. class Child extends Parent

Slide 62

Slide 62 text

Functional Programming

Slide 63

Slide 63 text

Три неща функции от по-висок ред намаляване/премахване на странични ефекти мощна типова система

Slide 64

Slide 64 text

Haskell, Erlang, LISP, OCaml, F#

Slide 65

Slide 65 text

map & filter (функции от по-висок ред)

Slide 66

Slide 66 text

emails = [] for user in users if user.active? emails << user.email end end notify(emails)

Slide 67

Slide 67 text

emails = users.select { |u| u.active? }.map { |u| u.email } notify(emails)

Slide 68

Slide 68 text

Въпросът е: кое от двете е по-ясно?

Slide 69

Slide 69 text

Често когато покажа това на някого, той ще каже, че първия вариант е по-ясен. Но за мен втория вариант е по-ясен. Защо?

Slide 70

Slide 70 text

Експеримент: кое от следващите две изречения е по-ясно?

Slide 71

Slide 71 text

ϧϏΛ࢖ͬͯخ͍͠։ൃऀʹͳΔɻ ϧϏΛ࢖ͬͯخ͍͠ιϑτ΢ΣΞΛ࡞ΔਓʹͳΔɻ

Slide 72

Slide 72 text

map и filter са част от “азбуката”

Slide 73

Slide 73 text

В момента за мен map и filter са по- четими. Първия път като ги видях не бе така.

Slide 74

Slide 74 text

accidental vs. essential complexity

Slide 75

Slide 75 text

странични ефекти (още състояние/state)

Slide 76

Slide 76 text

Писането без странични ефекти е като здравословния начин на живот – всеки го подценява докато не го пробва.

Slide 77

Slide 77 text

Липсата на странични ефекти прави кода декларативен. Така той е по-лесно четим.

Slide 78

Slide 78 text

Наличието на странични ефекти превръща кода в императивен. Това го прави по- трудно разбираем.

Slide 79

Slide 79 text

83% от всички бъгове са породени от код със странични ефекти Lorenzo van Matterhorn учен

Slide 80

Slide 80 text

Конкурентност

Slide 81

Slide 81 text

Липсата на странични ефекти сериозно опростява паралелизацията на приложението.

Slide 82

Slide 82 text

типова система

Slide 83

Slide 83 text

Типовата система ни гарантира по време на компилация, че цял клас от грешки няма как да възникнат.

Slide 84

Slide 84 text

Типовата система на един функционален език е далеч по-развита от тази на (например) Java.

Slide 85

Slide 85 text

Type Inference

Slide 86

Slide 86 text

Типовата система е feature на езика, подобно на наследяване. Може да я карате да върши работа вместо вас.

Slide 87

Slide 87 text

The Expression Problem

Slide 88

Slide 88 text

Нека разгледаме система, в която имаме типове (кръг, квадрат) и операции (обиколка, лице).

Slide 89

Slide 89 text

class Circle def initialize(center, radius) @center, @radius = center, radius end def area Math::PI * @radius * @radius end end class Square def initialize(top_left, side) @top_left, @side = top_left, side end def area @side * @side end end ООП

Slide 90

Slide 90 text

ФП Circle = Struct.new(:center, :radius) Square = Struct.new(:top_left, :side) module Geometry extend self def area(shape) case shape when Circle then Math::PI * shape.radius * shape.radius when Square then shape.side * shape.side end end end

Slide 91

Slide 91 text

Ще разгледаме какво се случва когато искаме да добавим нов тип или нова операция.

Slide 92

Slide 92 text

class Circle def initialize(center, radius) ... def area ... def circumference 2 * Math::PI * @radius end end class Square def initialize(top_left, side) ... def area ... def circumference 4 * @side end end Операция в ООП ☢

Slide 93

Slide 93 text

module Geometry def area(shape) case shape when Circle then Math::PI * shape.radius * shape.radius when Square then shape.side * shape.side end end def circumference(shape) case shape when Circle then 2 * Math::PI * shape.radius when Square then 4 * shape.side end end end Операция във ФП ✔

Slide 94

Slide 94 text

class Rectangle def initialize(top_left, width, height) @top_left, @width, @height = top_left, width, height end def area @width * @height def circumference 2 * @width + 2 * @height end end Тип в ООП ✔

Slide 95

Slide 95 text

module Geometry def area(shape) case shape when Circle then Math::PI * shape.radius * shape.radius when Square then shape.side * shape.side when Rectangle then shape.width * shape.height end end def circumference(shape) case shape when Circle then 2 * Math::PI * shape.radius when Square then 4 * shape.side when Rectangle then 2 * shape.width + 2 * shape.height end end end Тип във ФП ☢

Slide 96

Slide 96 text

ООП ФП Тип Операция Лесно Трудно Трудно Лесно The Expression Problem

Slide 97

Slide 97 text

Обърнете внимание, че функционалния подход ще изглежда грешно в Java.

Slide 98

Slide 98 text

извод

Slide 99

Slide 99 text

всеки език ни поставя рамки

Slide 100

Slide 100 text

Рамките създават структура, която е позната на повечето програмисти в дадената среда.

Slide 101

Slide 101 text

Рамките могат да бъдат и нож с две остриета. Какво става ако пишем на Java и ни трябва често да добавяме нови операции?

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

Труден въпрос: кога да стоим в рамките на един език и кога да излезем от тях?

Slide 106

Slide 106 text

Imperative Programming

Slide 107

Slide 107 text

фон Нойман езици

Slide 108

Slide 108 text

Давате ясни и точни инструкции на компютъра какво да направи.

Slide 109

Slide 109 text

emails = [] for user in users if user.active? emails << user.email end end notify(emails)

Slide 110

Slide 110 text

Кога императивното програмиране е подходящо?

Slide 111

Slide 111 text

Скорост

Slide 112

Slide 112 text

Някои алгоритми са естествено императивни. В този стил са много по-ясни.

Slide 113

Slide 113 text

Structured Programming

Slide 114

Slide 114 text

Едсгар Дийкстра

Slide 115

Slide 115 text

Едсгар Дейкстра е известен със спорната си фамилия и с това, че е открил блог поста.

Slide 116

Slide 116 text

Структурирано програмиране a.k.a. бунта на Дайкстра срещу GOTO

Slide 117

Slide 117 text

Не просто goto в C, а всякакви jump-ове (Assembler, BASIC)

Slide 118

Slide 118 text

Структурираното програмиране предлага набор от езикови абстракции, които да заменят GOTO

Slide 119

Slide 119 text

Структурирано Неструктурирано for, while goto функции goto блокове goto

Slide 120

Slide 120 text

class Structured extends Imperative * not sure about LSP

Slide 121

Slide 121 text

Böhm-Jacopini theorem

Slide 122

Slide 122 text

Всеки алгоритъм може да се изрази само с три вида конструкции.

Slide 123

Slide 123 text

sequence selection iteration

Slide 124

Slide 124 text

Няма да вземам отношение за GOTO, но...

Slide 125

Slide 125 text

...Кнут твърди, че определен код е по-четим с GOTO...

Slide 126

Slide 126 text

...Д[аеи]йсктра показва как употребите на GOTO могат да се премахнат...

Slide 127

Slide 127 text

...има теорема твърдяща, че може да напишете всичко без GOTO...

Slide 128

Slide 128 text

...не съм писал на език с GOTO отдавна.

Slide 129

Slide 129 text

Но пък от време на време пиша на език с COMEFROM!

Slide 130

Slide 130 text

Logical Programming

Slide 131

Slide 131 text

Не давате на компютъра решение, а проблем. Той намира решението вместо вас.

Slide 132

Slide 132 text

Подходящо за бързи/мързеливи сметки

Slide 133

Slide 133 text

Има ред специални приложения

Slide 134

Slide 134 text

Изисква особен runtime

Slide 135

Slide 135 text

No content

Slide 136

Slide 136 text

1. The Brit lives in a red house. 2. The Swede keeps dogs as pets. 3. The Dane drinks tea. 4. The green house is next to, and on the left of the white house. 5. The owner of the green house drinks coffee. 6. The person who smokes Pall Mall rears birds. 7. The owner of the yellow house smokes Dunhill. 8. The man living in the centre house drinks milk. 9. The Norwegian lives in the first house. 10. The man who smokes Blends lives next to the one who keeps cats. 11. The man who keeps horses lives next to the man who smokes Dunhill. 12. The man who smokes Blue Master drinks beer. 13. The German smokes Prince. 14. The Norwegian lives next to the blue house. 15. The man who smokes Blends has a neighbor who drinks water. Who has the fish? Einstein’s Riddle

Slide 137

Slide 137 text

BEWARE! HERE BE DRAGONS!

Slide 138

Slide 138 text

solution(People) :- People = [_, _, _, _, _], same(brit, red, People), same(swede, dogs, People), same(dane, tea, People), left_of(green, white, People), same(green, coffee, People), same(birds, pall_mall, People), same(yellow, dunhill, People), center_house(milk, People), first_house(norwegian, People), neighbors(blends, cats, People), neighbors(horses, dunhill, People), same(beer, blue_master, People), same(german, prince, People), neighbors(norwegian, blue, People), neighbors(blends, water, People), maplist(person, People), flatten(People, Items), is_set(Items).

Slide 139

Slide 139 text

has(Thing, Person) :- nationality(Thing), Person = [Thing, _, _, _, _]. has(Thing, Person) :- color(Thing), Person = [_, Thing, _, _, _]. has(Thing, Person) :- pet(Thing), Person = [_, _, Thing, _, _]. has(Thing, Person) :- beverage(Thing), Person = [_, _, _, Thing, _]. has(Thing, Person) :- cigars(Thing), Person = [_, _, _, _, Thing]. same(A, B, People) :- has(A, Person), has(B, Person), member(Person, People). first_house(A, People) :- has(A, Person), People = [Person, _, _, _, _]. center_house(A, People) :- has(A, Person), People = [_, _, Person, _, _]. left_of(A, B, People) :- has(A, PersonA), has(B, PersonB), nextto(PersonA, PersonB, People). neighbors(A, B, People) :- left_of(A, B, People); left_of(B, A, People).

Slide 140

Slide 140 text

has_fish(Nationality) :- solution(Solution), member([Nationality, _, fish, _, _], Solution).

Slide 141

Slide 141 text

?-

Slide 142

Slide 142 text

?- has_fish(Answer).

Slide 143

Slide 143 text

?- has_fish(Answer). Answer = german.

Slide 144

Slide 144 text

Language-Oriented Programming

Slide 145

Slide 145 text

Развиваме собствени езици, които описват проблема по-добре.

Slide 146

Slide 146 text

Embedded DSL

Slide 147

Slide 147 text

Огъваме езика да ни даде по-добро API

Slide 148

Slide 148 text

class Comment < ActiveRecord::Base validates_presence_of :body belongs_to :user belongs_to :revision attr_protected :user_id, :solution_id delegate :solution, to: :revision delegate :task, :task_name, to: :solution def editable_by?(user) self.user == user or user.try(:admin?) end def user_name user.name end end

Slide 149

Slide 149 text

Macros

Slide 150

Slide 150 text

Разширяваме синтаксиса

Slide 151

Slide 151 text

(define-syntax unless (syntax-rules () ((_ condition body) (if (not condition) body (void)))))

Slide 152

Slide 152 text

(unless (belly-full?) (begin (eat) (drink)))

Slide 153

Slide 153 text

DSL

Slide 154

Slide 154 text

Правим какъвто си искаме език (заедно с парсер и интерпретатор)

Slide 155

Slide 155 text

Scenario: Purchasing goods with coupons Given a product "MacBook Air" that costs 2000$ And a discount coupon "CUCUMBER" for 10% When I add "MacBook Air" to my bag And I apply the coupon "CUCUMBER" Then I should have to pay 1800$ Cucumber

Slide 156

Slide 156 text

In Closing

Slide 157

Slide 157 text

аспектно-ориентирано AspectJ in Action

Slide 158

Slide 158 text

обектно-ориентирано SmallTalk Best Practice Patterns Implementation Patterns Design Patterns Refactoring Refactoring to Patterns MIT 6.170 записки

Slide 159

Slide 159 text

c2.com

Slide 160

Slide 160 text

функционално програмирнане Haskell (която и да е книга, сериозно) Structure and Interpretation of Computer Programs A Little Java, A Few Patterns

Slide 161

Slide 161 text

две наблюдения един възглед

Slide 162

Slide 162 text

Езика ни дава рамки, които структурират програмата ни. Това я прави по-разбираема за всички останали.

Slide 163

Slide 163 text

Рамките понякога ни водят към лоши решения и трябва да знаем кога да излизаме от тях.

Slide 164

Slide 164 text

Разбирането на теоритична материя прави кода ни по-добър.

Slide 165

Slide 165 text

Благодаря ви!