﻿1
00:00:00,720 --> 00:00:06,000
Hi everyone, in this video
we'll talk about the Anti-IF Campaign.

2
00:00:06,480 --> 00:00:09,480
In particular,
we'll explain the reasons why

3
00:00:09,920 --> 00:00:13,720
the Return Nil and Null Check
functions are not great.

4
00:00:13,920 --> 00:00:18,520
Here's an example of a code,
which is not an object.

5
00:00:19,040 --> 00:00:21,680
Its method parameter is an animal.

6
00:00:21,880 --> 00:00:24,680
Its actions vary
according to the animal.

7
00:00:24,880 --> 00:00:30,560
For example, we can ask a dog
to wag its tail or a duck to quack.

8
00:00:31,000 --> 00:00:33,440
For a cat, we request other actions.

9
00:00:34,040 --> 00:00:38,080
So, why is it problematic
to use If statements?

10
00:00:39,120 --> 00:00:43,800
Particularly when they're used
to check the type of receiver.

11
00:00:45,080 --> 00:00:49,200
For example, if we want to add
a new animal here,

12
00:00:49,360 --> 00:00:53,400
we would need to check
the entire project code

13
00:00:53,680 --> 00:00:56,880
to search for If statements
that may apply.

14
00:00:57,040 --> 00:01:01,280
We would have to modify
numerous codes throughout the project.

15
00:01:01,640 --> 00:01:06,560
Additionally, adding cases to methods
makes them cumbersome,

16
00:01:06,840 --> 00:01:10,440
and they become lost
in too many details.

17
00:01:10,720 --> 00:01:13,760
Adding animals
makes this method very long,

18
00:01:13,920 --> 00:01:17,160
and each animal type
can have many details.

19
00:01:17,320 --> 00:01:21,760
Even for a simple feature,
such as not all dogs having tails,

20
00:01:21,920 --> 00:01:25,920
we would have to create
separate cases for each option.

21
00:01:26,120 --> 00:01:31,640
The code would become
complicated and harder to understand.

22
00:01:32,240 --> 00:01:35,760
So, to replace these actions,
we send messages.

23
00:01:36,080 --> 00:01:38,480
This is a point we keep reiterating.

24
00:01:38,640 --> 00:01:42,240
The key point to remember
is the sending of messages.

25
00:01:42,880 --> 00:01:46,280
We can replace
the previous code with this one.

26
00:01:47,040 --> 00:01:51,160
It applies the showHappiness method
in each relevant class.

27
00:01:51,320 --> 00:01:56,480
Each class will decide how each animal
will show its "happiness."

28
00:01:56,760 --> 00:02:02,720
For each animal, all we need to do
is send the message

29
00:02:05,560 --> 00:02:07,560
showHappiness to the animal,

30
00:02:08,600 --> 00:02:11,360
and one of its methods will be executed.

31
00:02:11,520 --> 00:02:15,040
We see here that Pharo
is pursuing the If function.

32
00:02:15,200 --> 00:02:19,960
Pharo decides which method to apply
to a particular type of animal.

33
00:02:20,120 --> 00:02:22,920
This is executed automatically.

34
00:02:23,120 --> 00:02:27,480
There's no need for us
to specify Ifs for object types.

35
00:02:28,040 --> 00:02:31,200
It only makes codes
less coherent and dynamic.

36
00:02:32,560 --> 00:02:36,040
Now we'll discuss
the specific case of Nil.

37
00:02:36,440 --> 00:02:39,160
If a method returns nil,

38
00:02:39,320 --> 00:02:43,120
you'll oblige your clients
to use If statements.

39
00:02:43,280 --> 00:02:46,200
Whereas, using If is rarely recommended.

40
00:02:47,520 --> 00:02:50,520
Here we use an example of a code

41
00:02:50,760 --> 00:02:55,440
based on a parameter and an inferencer.

42
00:02:55,600 --> 00:02:57,880
The type of code is not important.

43
00:02:58,160 --> 00:03:01,440
Here we see that in some cases,
nil is returned.

44
00:03:01,840 --> 00:03:04,480
This means that when we use this code,

45
00:03:04,760 --> 00:03:08,600
we need to test
the message rulesForFact.

46
00:03:08,800 --> 00:03:11,480
Did rulesForFact return nil?

47
00:03:11,680 --> 00:03:14,560
We act differently
depending on the reply.

48
00:03:14,720 --> 00:03:17,280
We see that in this case,

49
00:03:17,880 --> 00:03:20,280
since we're using a plural term,

50
00:03:20,440 --> 00:03:23,960
the method will probably
return a collection.

51
00:03:24,200 --> 00:03:26,880
An effective solution for avoiding nil

52
00:03:27,080 --> 00:03:31,000
in this situation
is to return an empty collection.

53
00:03:31,200 --> 00:03:33,080
This works in many cases.

54
00:03:33,400 --> 00:03:38,520
Returning an empty collection
instead of nil simplifies the code.

55
00:03:38,880 --> 00:03:42,400
Because clients can simply
iterate the collection,

56
00:03:42,560 --> 00:03:45,360
and if it's empty, nothing will happen.

57
00:03:46,480 --> 00:03:48,400
For exceptional cases,

58
00:03:48,840 --> 00:03:52,360
such as when you have a file stream

59
00:03:52,520 --> 00:03:56,320
that has not been opened for writing
and shows an error,

60
00:03:56,560 --> 00:04:01,640
instead of returning nil, we inform
the system by raising an exception.

61
00:04:01,920 --> 00:04:05,600
In Pharo,
we call this filing an exception.

62
00:04:05,760 --> 00:04:09,560
We create an instance
of the Exception class or subclass

63
00:04:09,720 --> 00:04:11,960
and send the message, or signal.

64
00:04:13,680 --> 00:04:19,640
This avoids obliging
the client of the method nextPutAll

65
00:04:19,800 --> 00:04:23,960
to test if it is nil,
when a problem has likely occurred.

66
00:04:24,200 --> 00:04:26,800
Either the client handles the exception

67
00:04:26,960 --> 00:04:31,680
or it's handled
by the client of the client, and so on.

68
00:04:31,880 --> 00:04:37,840
We can focus on one specific level
to capture the exception.

69
00:04:38,560 --> 00:04:40,240
It avoids overuse of Ifs.

70
00:04:40,880 --> 00:04:45,720
Another case where we find checks
for the nil value

71
00:04:45,880 --> 00:04:49,280
is in instance variables
that are not initialized.

72
00:04:49,600 --> 00:04:54,800
If a code says that if the variable
is still nil, it must react a certain way,

73
00:04:54,960 --> 00:04:59,200
it's better to initialize the variable
straightaway,

74
00:04:59,360 --> 00:05:01,960
with a value that works for all cases.

75
00:05:02,120 --> 00:05:03,120
So, here,

76
00:05:03,600 --> 00:05:06,680
for "members,"
which contains a collection,

77
00:05:06,840 --> 00:05:10,600
we initialize an empty collection
instead of using nil.

78
00:05:10,920 --> 00:05:13,520
Once again, this often works well.

79
00:05:13,960 --> 00:05:18,000
If you want to give a value
to a variable,

80
00:05:18,400 --> 00:05:22,680
and if it's costly
to calculate its value,

81
00:05:22,840 --> 00:05:26,560
you can wait until the last moment
to calculate it.

82
00:05:26,720 --> 00:05:30,520
It may never be calculated,
so it saves execution time.

83
00:05:31,320 --> 00:05:35,040
In such cases,
we use lazy initialization.

84
00:05:35,200 --> 00:05:38,280
This is used when a value is required.

85
00:05:38,680 --> 00:05:42,400
If the value is still nil,
we assign it a value.

86
00:05:42,560 --> 00:05:47,240
If it's no longer nil,
we return its value immediately.

87
00:05:48,000 --> 00:05:52,600
Here we have an If associated with nil,
but we have only one.

88
00:05:53,160 --> 00:05:57,920
All other users of the variable
utilize the descent method,

89
00:05:58,520 --> 00:06:00,720
and have not tested if it is nil.

90
00:06:01,320 --> 00:06:03,960
Sometimes we come across cases

91
00:06:04,520 --> 00:06:09,840
in which it's necessary to check
whether or not we need to respond.

92
00:06:10,320 --> 00:06:12,160
As we see in this example.

93
00:06:12,800 --> 00:06:15,840
Here we have a ToolPalette.

94
00:06:16,120 --> 00:06:19,440
If a tool is selected, we can respond,

95
00:06:19,600 --> 00:06:22,960
but if none is selected,
we prefer not to act.

96
00:06:23,640 --> 00:06:26,480
Look at the selectedTool function.

97
00:06:26,720 --> 00:06:31,600
If it returns nil, no tools are selected,
so no action is required.

98
00:06:31,800 --> 00:06:35,760
If selectedTool returns something,

99
00:06:36,000 --> 00:06:40,080
we will ask it to perform an action.

100
00:06:41,040 --> 00:06:42,920
A good way of replacing this

101
00:06:43,360 --> 00:06:45,720
is to use the NullObject pattern.

102
00:06:45,880 --> 00:06:50,400
Instead of having two cases,
one with tools and one without,

103
00:06:50,600 --> 00:06:54,440
we have one case
in which one of our tools does nothing.

104
00:06:54,600 --> 00:06:57,120
This tool will be selected by default.

105
00:06:57,360 --> 00:07:01,840
We create a tool that does nothing
when asked to perform actions.

106
00:07:03,120 --> 00:07:09,000
Instead of not selecting anything,
we enable a tool that does nothing.

107
00:07:10,360 --> 00:07:14,800
To find out more about NullObject,
see these references.

108
00:07:15,680 --> 00:07:16,840
In conclusion,

109
00:07:17,000 --> 00:07:19,640
messages are more effective than Ifs.

110
00:07:19,840 --> 00:07:22,520
You will utilize Ifs in certain cases,

111
00:07:22,680 --> 00:07:27,680
but you can often avoid using them
and send messages instead.

112
00:07:28,840 --> 00:07:34,160
Avoid returning nil because
it obliges you to insert If checks

113
00:07:34,360 --> 00:07:38,280
to find out whether or not
the value is nil.

114
00:07:39,440 --> 00:07:44,720
Initialize variables either on creation
or using lazy initialization.

115
00:07:45,680 --> 00:07:50,760
Create objects representing default
behavior or an absence of behavior.

116
00:07:50,960 --> 00:07:54,960
This applies not only to Pharo
but to all object languages.

117
00:07:55,200 --> 00:08:00,840
It's important to remember these points
whichever language you use.