nus-cs2103-AY1819S1 / forum

A repo to hold the issue tracker for module discussions
1 stars 1 forks source link

Question on Law of Demeter #108

Open jeffkwoh opened 6 years ago

jeffkwoh commented 6 years ago

Hi all,

I have a few questions on the Law of Demeter.

Please find the formal definition for convenient reference: • The object O itself • Objects passed as parameters of m • Objects created/instantiated in m • Objects from the direct association of O

This was given as an example and g.doSomething() violates LoD.

void foo(Bar b) {
    Goo g = b.getGoo();
    g.doSomething();
}

As such, would this circumvent LoD ? I.e. calling g.doSomething() no longer violates LoD.

void foo(Bar b) {
    Goo g = b.getGoo();
    koo(g);
}

void koo(Gar g) {
    g.doSomething();
}

To extend on this, how does LoD apply to higher order functions?

In the code below model.updateFilteredTaskList(task -> originalTasks.contains(task));, specifically originalTasks.contains(task) is equivalent to model.getFilteredTaskList.contains(task), does this violate LoD?

/**
 * Generates a set of tasks that can be completed which also satisfies the supplied predicate.
 */
private Set<Task> generateSetOfCompletableTasks(Predicate<Task> pred, Model model) {
    // Preserve a shallow copy of original list of task to restore later on
    List<Task> originalTasks = new ArrayList<>(model.getFilteredTaskList());

    // Add all of the completable tasks to setOfTasks
    Set<Task> setOfTasks = new HashSet<>();
    model.updateFilteredTaskList(pred.and(task -> !task.isCompleted()));
    List<Task> filteredList = model.getFilteredTaskList();
    setOfTasks.addAll(filteredList);

    // Restore filteredTaskList to it's original view
    model.updateFilteredTaskList(task -> originalTasks.contains(task));

    return setOfTasks;
}

Do we have a general set of rules pertaining to how we evaluate Law of Demeter for higher order functions? Do we treat the anonymous lambda created, a Predicate as "Objects created/instantiated in m", then through passing final local variables into the anonymous lambda, are all of those local variables considered as "Objects created/instantiated in anonymous lambda" or "Objects passed as parameters of anonymous lambda".

A second question would be using a wrapper to circumvent LoD.

void foo(Bar b) {
    Goo g = b.getGoo();
    Goo x = koo(g);
    x.doSomething() //x is created in foo.
}

void koo(Gar g) {
   return g.deepCopy();
}

This is similar to

List<Task> originalTasks = new ArrayList<>(model.getFilteredTaskList());

Then calling methods on originalTasks.

Is LoD circumvented here?

Thank you!

damithc commented 6 years ago

As such, would this circumvent LoD ? I.e. calling g.doSomething() no longer violates LoD.

void foo(Bar b) {
    Goo g = b.getGoo();
    koo(g);
}

void koo(Gar g) {
    g.doSomething();
}

My take (there are slightly different interpretations of LoD): This is still a violation of LoD (in spirit) if one class ends up knowing the internal structure of another. In practice, use LoD as way to minimize coupling between classes rather than a law that needs to be followed to the letter.

jeffkwoh commented 5 years ago

I see, understand prof @damithc , in the context of exams, however, how should we approach ambiguous cases like this

damithc commented 5 years ago

I see, understand prof @damithc , in the context of exams, however, how should we approach ambiguous cases like this

  1. In the exam, if there is an ambiguity in the question, you can write it down in the exam paper (even for MCQ) and we'll take those into account when grading. Generally, we try to avoid ambiguities in exam questions.
  2. w.r.t. LoD, I plan to revisit the topic at the start of today's lecture to attempt to clear up the picture a bit more.
jeffkwoh commented 5 years ago

@damithc Sorry about the late reply, I missed it. Thank you for your response and clarification!