You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Design patterns: good practices and structured thinking
2
2
3
-
Design guiding principles:
3
+
Every software developer has a desire to write better code. A desire
4
+
to improve system performance. A desire to design software that is easy to maintain, easy to understand and explain.
5
+
6
+
Design patterns are recommendations and good practices accumulating knowledge of experienced programmers.
7
+
8
+
The highest level of experience contains the design guiding principles:
4
9
- SOLID: Single Responsibility, Open/Closed, Liskov Substitution, Interface
5
10
- Segregation, Dependency Inversion
6
11
- DRY: Don't Repeat Yourself
@@ -9,23 +14,49 @@ Design guiding principles:
9
14
- YAGNI: You Aren't Gonna Need It (overengineering)
10
15
- POLP: Principle of Least Privilege
11
16
12
-
These hig-level concepts are guiding principles for
17
+
While these high-level concepts are intuitive, they are too general to give specific answers.
18
+
19
+
More detailed patterns arise for programming paradigms (declarative, imperative) with specific instances of functional or object-oriented programming.
13
20
14
-
Julia does not fit into any methodological classes like *object-oriented*or*functional* programming. The key concept of julia are:
21
+
Julia is a multi-paradigm, taking features of both *object-oriented*and*functional* programming. The key concept of julia are:
15
22
-*type system* of data structures
16
23
-*multiple dispatch*, respecting the types,
17
24
- functional programming concepts such as *closures*
18
25
19
-
These simple concepts allows to construct design patters common in other languages.
20
-
- the language does not enforce many formalisms structures (can be limiting as well as advantageous).
21
-
- the compiler cannot check for correctness of "patterns"
26
+
How do I correctly use these tools to express what I want to achieve?
27
+
28
+
The concept of design patterns originates in the OOP paradigm. OOP defines a strict way how to write software:
29
+
- class
30
+
- interface
31
+
- virtual methods
32
+
It is often unclear how to use these concepts to solve a particular programming task.
33
+
34
+
A cookbook:
35
+
- Gamma, E., Johnson, R., Helm, R., Johnson, R. E., & Vlissides, J. (1995). Design patterns: elements of reusable object-oriented software. Pearson Deutschland GmbH.
36
+
37
+
Defining 23 design patterns in three categories. Became extremely popular.
38
+
39
+
Fundamental tradeoff: rules vs. freedom
40
+
- freedom: in the C language it is possible to access assembler instructions, use pointer aritmetics:
41
+
- it is possible to write extremely efficient code
42
+
- it is easy to segfault, leak memory, etc.
43
+
- rules: in strict languages (strict OOP, strict functional programing) you lose freedom for certain guarantees:
44
+
- e.g. strict functional programing guarantees that the program provably terminates
45
+
- operations that are simple e.g. in pointer arithmetics may become clumsy and inefficient in those strict rules.
46
+
- the compiler can validate the rules and complain if the code does not comply with them.
47
+
48
+
Julia is again a dance between freedom and strict rules. It is more inclined to freedom.
49
+
Provides few simple concepts that allow to construct design patterns common in other languages.
50
+
- the language does not enforce too many formalisms (via keywords (interfac, trait, etc.) but they can be
51
+
- the compiler cannot check for correctness of these "patterns"
22
52
- the user has a lot of freedom (and responsibility)
23
53
- lots of features can be added by Julia packages (with various level of comfort)
24
54
- macros
25
55
56
+
Read:
57
+
- Hands-On Design Patterns and Best Practices with Julia Proven solutions to common problems in software design for Julia 1.x Tom Kwong, CFA
26
58
27
-
28
-
## Closures
59
+
## Functional tools: Closures
29
60
30
61
!!! tip "Closure (lexical closure, function closure)"
31
62
A technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment.
@@ -41,7 +72,7 @@ function adder(x)
41
72
return y->x+y
42
73
end
43
74
```
44
-
creates a function that "closes" the argument ```x```.
75
+
creates a function that "closes" the argument ```x```. Try: ```f=adder(5); f(3)```.
45
76
46
77
```julia
47
78
x =30;
@@ -84,7 +115,7 @@ function adder(x)
84
115
end
85
116
```
86
117
87
-
Note that the structure ##1 is not directly accessible.
118
+
Note that the structure ##1 is not directly accessible. Try ```f.x``` and ```g.x```.
88
119
89
120
### Functor = Function-like structure
90
121
Each structure can have a method that is invoked when called as a function.
Is this confusing? What can ```cb()``` do and what it can not?
115
146
116
147
Note that function ```train!``` does not have many local variables. The important ones are arguments, i.e. exist in the scope from which the function was invoked.
117
148
@@ -135,12 +166,14 @@ Usage of closures:
135
166
136
167
## Design Patterns of OOP from the Julia viewpoint
137
168
169
+
OOP is currently very popular concept (C++, Java, Python). It has strenghts and weaknesses. The Julia authors tried to keep the strength and overcome weaknesses.
170
+
138
171
Key features of OOP:
139
172
- Encapsulation
140
173
- Inheritance
141
174
- Polymorphism
142
175
143
-
Classical OOP languages define classes that bind processing functions to the data.
176
+
Classical OOP languages define classes that bind processing functions to the data. Virtual methods are defined only for the attached methods of the classes.
144
177
145
178
!!! tip "Encapsulation"
146
179
Refers to bundling of data with the methods that operate on that data, or the restricting of direct access to some of an object's components. Encapsulation is used to hide the values or state of a structured data object inside a class, preventing direct access to them by clients in a way that could expose hidden implementation details or violate state invariance maintained by the methods.
@@ -159,6 +192,7 @@ What if I create Grass with larger size than ```max_size```?
159
192
```julia
160
193
grass =Grass(1,50,5)
161
194
```
195
+
Freedom over Rules. Maybe I would prefer to introduce some rules.
162
196
163
197
Some encapsulation may be handy keeping it consistent. Julia has ```innerconstructor```.
164
198
```julia
@@ -169,6 +203,7 @@ mutable struct Grass <: Plant
169
203
Grass(id,sz,msz) = sz > msz ?error("size can not be gerater that max_size") :new(id,sz,msz)
170
204
end
171
205
```
206
+
When defined, Julia does not provide the default outer constructor.
172
207
173
208
But fields are still accessible:
174
209
```julia
@@ -189,11 +224,12 @@ Julia has *partial encapsulation* via a mechanism for consistency checks.
189
224
190
225
191
226
### Encapsulation Disadvantage: the Expression Problem
192
-
Matrix of methods/types(data-structures)
227
+
228
+
Encapsulation limits the operations I can do with an object. Sometimes too much. Consider a matrix of methods/types(data-structures)
193
229
194
230
Consider an existing matrix of data and functions:
Polymorphism is the method in an object-oriented programming language that performs different things as per the object’s class, which calls it. With Polymorphism, a message is sent to multiple class objects, and every object responds appropriately according to the properties of the class.
235
271
236
-
Example animals of different classes make different sounds:
272
+
Example animals of different classes make different sounds. In Python:
237
273
```python
238
274
sheep.make_sound()
239
275
wolf.make_sound()
240
276
```
241
-
Will make distinct sounds (baa, bark).
277
+
Will make distinct sounds (baa, Howl).
242
278
243
279
Can we achieve this in Julia?
244
280
```
245
281
make_sound(s::Sheep)=println("Baa")
246
-
make_sound(w::Wolf)=println("Bark")
282
+
make_sound(w::Wolf)=println("Howl")
247
283
```
248
284
249
-
Multiple dispatch is an extension of classical polymorphism of OOP, which is only single dispatch.
285
+
Multiple dispatch is an *extension* of the classical polymorphism of OOP, which is only a single dispatch.
250
286
251
287
!!! tip "Implementation of virtual methods"
252
288
Virtual methods in OOP are typically implemented using Virtual Method Table, one for each class.
253
289

254
290
255
-
NotesDuck typing:
291
+
*Freedom* vs. Rules.
256
292
- julia does not check if```make_sound``` exists for all animals. May result in MethodError. Responsibility of a programmer.
257
293
- define ```make_sound(A::AbstractAnimal)```
258
294
- Duck typing is a type of polymorphism without static types
@@ -273,7 +309,6 @@ meet(w1::Sheep, w2::Sheep)=
273
309
274
310
275
311
276
-
277
312
## Inheritance
278
313
279
314
!!! tip "Inheritance"
@@ -326,21 +361,21 @@ The type hierarchy is only one way of subtyping. Julia allows many variations, e
0 commit comments