Reputation:
I am learning the methods of list (difference between pop and remove)
and be aware of the Command–query separation
It states that every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, Asking a question should not change the answer.[1] More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.
I’m unable to interpret “Asking a question should not change the answer”,
I read the ppt
wikipedia linked which takes an example of ‘light’ sign inside and outside of channel.
It did not illustrate the relationship between a question and an answer.
In my perception, It should be “Answering a question should not change the question”
that is reasonable to say
In theoretical terms, this establishes a measure of sanity, whereby one can reason about a program's state without simultaneously modifying that state.
Does my deduction reasonable?
Upvotes: 3
Views: 1448
Reputation: 22324
The class below obeys to the CQS principle. Each of its method is either a query or a command. The method get
provides information on the state and allows no side effects. The method set
has side effects and thus returns None
.
class IntValue:
def __init__(self, x):
self.x = int(x)
def get(self):
return self.x
def set(self, x):
self.x = int(x)
In particular, the following will always be true.
v = IntValue(1)
v.get() == v.get() # Always True
Never will you have asked the value through the get
method and changed it at the same time. Here, the CQS principle assures you that you can ask for the value multiple times in a row and still get the same answer.
The reason this is important is because a lot of undesired complexity in programs arises from side effects.
Now consider a similar class that encapsulates a list.
class ListValue:
def __init__(self, x):
self.x = list(x)
def get(self):
return self.x
def set(self, x):
self.x = list(x)
The problem with the above is that asking a question may lead the answer to change.
v = ListValue([1, 2, 3])
lst = v.get() # [1, 2, 3]
lst.append(4)
v.get() # [1, 2, 3, 4]
When developping large softwares, this is often a source of hard-to-track bugs. These can be avoided by making sure that you cannot access state from a ListValue
, but only a view on that state.
class ListValue:
def __init__(self, x):
self.x = list(x)
def get(self):
return deepcopy(self.x) # Here we return a copy of the list
def set(self, x):
self.x = list(x)
Upvotes: 2
Reputation: 95760
I’m unable to interpret “Asking a question should not change the answer”, I read the ppt wikipedia linked which takes an example of ‘light’ sign inside and outside of channel. It did not illustrate the relationship between a question and an answer.
Light?
essentially asks "Is the light on?" It returns True or False.
The wrong thing for Light?
to do is to turn the light on if it's off, or to turn the light off if it's on. In the absence of any other confounding code, executing Light?
three times in a row should return the same value three times. Asking a question should not change the answer. But if asking the question Light?
changed the answer, you'd get "True, False, True" or "False, True, False".
In my perception, It should be “Answering a question should not change the question”
No, because answers (return values) can't change questions (method calls). But questions can change answers (if you code your methods that way).
Upvotes: 0
Reputation: 13498
You've got the gist of it. In computer science terms it pretty much means that getting information should not in any way modify the information
What they mean in
More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.
Has more to do with communication between your software and a client. This takes the above a bit further in saying that any information returned must be a copy of the actual stored value, and cannot be used to trace back to that value in any way.
Take this list for example:
a = [1, 2, 3, 4, 5]
This is a very important list in my system, and clients pay me to give the access to my secret list. I'm going to make up a method here and say that the send()
method will send this list to my clients.
If I send(a)
to my clients, this breaks the tenet that is above. Because now my client can use the reference to a in a number of nasty says:
for i in range(len(a)):
a[i] = None
Now when I try to access a, all I get is [None, None, None, None, None]
. They were overwrite a because I sent them the reference and not the value. Instead, I should have send(a[:])
, or a copy of a. Now regardless of what my client does with the list I sent him, it has no impact on what goes on inside my system.
Upvotes: 1