Skip to main content

14 posts tagged with "SOC"

View All Tags

ยท 4 min read

Thoughtsโ€‹

This is a retrospective of the second semester of my second year at NUS. It was a relatively relaxed semester, with me taking 5 modules that resulted in a very manageable workload. In some sense, I would also say that perhaps I got used to what needed to be done.

Module Reviewโ€‹

CS3281 Thematic Systems Project I (aka Open Source Mod)โ€‹

This was my highlight-of-the-semester module, and I truly enjoyed it ๐Ÿ˜„ (Kudos to Prof Damith for keeping the module alive by volunteering his time to deliver this module!) It taught me a lot about open-source development. Even though the project that I worked on is by no means a large-scale, well-established one, in some way that provided autonomy and a whole range of tasks to tackle. As someone who has taken CS3216 (aka Go build software projects mod), I would say the learning outcome is different, but this module is equally worth doing. Summarizing some of my thoughts on the module:

  • You get to work on an open-source project!
  • You get to participate in the routine tasks of an open-source project, such as raising (and triaging) issues, fixing bugs, reviewing PRs, improving documentation, proposing new features, and discussing implementation details etc.
  • The projects are generally well documented; or have rich context from the git history and public discussion in issues and PRs.
  • The project mentors will be very helpful and you will get to learn from them through PR reviews and discussions.
  • When you spot the not-so-good parts of the projects, you have the chance to improve them.
  • Working on school-based projects also lends you the opportunity to work with other students, as well as external contributors and even on external projects (especially upstream dependencies).

I spent a fairly consistent amount of time working on MarkBind, as you can see in the contribution graph: [graph]

You can find out about what I have done (my progress and knowledge-learned log) here.

One thing I learned about OSS: if you want to be a contributor, first become a user. That leads to so many opportunities to contribute, and new perspectives to look at the project.

CS3230 Design and Analysis of Algorithmsโ€‹

This module is what you would expect in an advanced data structure and algorithms class. While the concepts may be difficult, they turned out to be pretty interesting to know. I enjoyed learning and analyzing the algorithms, which were all quite fundamental. There's some stress from the weekly graded assignments, but in general, it was manageable.

CS3240 Interaction Designโ€‹

This module provides a good introduction to the field of interaction design. It covers topics such as user-centered design, usability, and accessibility. It's a good survey of the field, and it was a more design-oriented module than the other CS modules I have taken. Workload wise if you don't like working on wireframes, and prototypes on tools like Figma, it can be a bit of a drag. I personally had many occasions where I opened Figma and just can't get myself to work on the assignment. But I did enjoy the module and my output, which you can find in the write-up here.

ES2660 Communicating In The Information Ageโ€‹

This required module focuses on the theories, techniques, and skills related to effective communication in the context of Information Technology. It covers topics such as critical thinking, public speaking, and writing, and provides opportunities to practice these skills through tutorial activities and assignments. The workload is manageable, and the classroom atmosphere is relaxed.

One thing that I remember most about this module: the challenge of speaking impromptu on a given topic (Not that easy if you want to do it well).

(bonus: here's the guideline I used for impromptu speaking)

  • Essence of the prompt (Context, audience, purpose)
  • Stand (Agree, Disagree)
  • Key terms
  • Reasons for my stand
  • Evidence/Examples/Implications/applications/ramifications
  • Delve deeper(Consider alternative, consequences)
  • Conclusion

LSM1303 Animal Behaviourโ€‹

Pretty chill and fun module with an awesome prof (The Otterman!). It was a great gateway to learning more about animals, and even got to observe them out in the wild.

animal1 animal2 animal3 animal4

ยท 5 min read

Motivationโ€‹

This article is inspired by a question I received in a programming methodology class. In this class, in which we write Java code to solve programming exercises, we have the constraint that every attribute of a class should be private and final. It means there is no access to the field outside of the class, and no modification is allowed once this field is initialized. This strict requirement is put in place to enforce immutability when constructing a class object in Java.

Sooner or later, when the exercises get more complex, we tend to move on to an OOP solution whereby multiple classes are constructed and organized with the help of inheritance. The problem then arises when there is a need to access this private final field in the parent class from a subclass. What should we do then?

To give a concrete example, let's say we have the following classes:

class Parent {
private final int value;

Parent(int value) {
this.value = value;
}
}

class Child extends Parent {
Child(int value) {
super(value);
}

int add(int another) {
return super.value + another; // UNABLE TO ACCESS!
}
}

What should we do if the child class wants to access value from the parent?

Solutionsโ€‹

Change modifierโ€‹

The simplest way to deal with that is to change the access modifier from private to something else - perhaps public or protected. This solution can be legitimate depending on the context. In some cases, perhaps it is perfectly normal to expose this value to other classes.

Add a getter methodโ€‹

From the Oracle's Java tutorial on inheritance

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

So, another possible solution is to have a getter method in the parent class and make that method public. This way child classes (and technically other classes) will have access via the getter. So a quick example will be:

class Parent {
private final int value;

Parent(int value) {
this.value = value;
}

public int getValue() {
return this.value;
}
}

class Child extends Parent {
Child(int value) {
super(value);
}

int add(int another) {
return super.getValue() + another; // CAN ACCESS!
}
}

Having a getter method can be beneficial in the sense that even though now a "private" field is exposed, you still have one layer of abstraction over it. The users of the getter method do not need to know how that value is generated, which can be manipulated (if needed) by some complex preprocessing steps in the getter method. Also, the underlying private field could change drastically and yet the users of the getter method are unaware.

Rethink code designโ€‹

Lastly, this problem may be a signal to rethink if there is a legitimate need to access a private final field. Given a parent-child relationship, sometimes it's difficult to be clear about which field/method should reside in which classes.

  • Would it be better to have the field in the child class instead?
  • Can we shift what the child class wanted to do with value into the parent class as a general method that the child class can inherit and possibly override?

A better code design might suggest that the private final field can stay as is, maintaining an abstraction barrier between the parent and the child class. One example solution is then:

class Parent {
private final int value;

Parent(int value) {
this.value = value;
}

int add(int another) {
return this.value + another;
}
}

class Child extends Parent {
Child(int value) {
super(value);
}

int add(int another) { // will work if this method is omitted as well,
return super.add(another); // as it will be inherited
}
}

Anti patternโ€‹

A problematic walkaround that some might come up with is to redeclare the same field in the child class.

class Parent {
private final int value;

Parent(int value) {
this.value = value;
}
}

class Child extends Parent {
private final int value;

Child(int value) {
super(value);
this.value = value;
}

int add(int another) {
return this.value + another; // will work but not recommended
}
}

This works but is arguably a bad design because it does not make use of inheritance to reduce any duplicates between shared properties. It also could result in the values (that meant to represent the same thing) going out of sync, especially if these fields were not declared as final.

Conclusionโ€‹

When I was asked the motivating question, my immediate response was: "make a public getter method". To which I was then asked a follow-up question:

  • Why do we resort to using a public getter method, when we want to keep the field private?

Which got me thinking:

  • Why can't private fields be inherited?

This article is a reminder for me to ask the "why" questions more often, and explore the reasons for the answers.

ยท 3 min read

P.S. My proof attempt/rewrite based on the solution discussed, uploaded mainly for my own reference. (warning: possibly erroneous)

Claim: The problem of determining whether a graph is connected is evasiveโ€‹

  • evasive as in it requires n C 2 queries i.e checking all the edges
  • Prove by making an adversary argument
  1. Suppose M is an algorithm that makes m < (n C 2) queries to decide whether the graph is connected
  2. The adversary responds to each query as follows:
    • suppose it receives the x th query for 1 <= x <= m
    • it considers the graph x defined by taking
      • all the responses before this query (those that have reply of 1 => those edges that exist)
      • all unqueried edges are set to 1 and hence considered as exist
      • the current queried edge is set to 0 and hence not included
    • if this graph is still connected without the current edge, then the adversary replies 0, else replies 1
      • it's like if the graph does not need the current edge to be fully connected, then return 0
  3. After all m queries, there are
    • responses for previously queried edges, which can be 1 or 0
    • one unqueried edge that is unknown
  4. The adversary makes two graphs using the above information:
    • G0: take all edges that are connected according to the responses + set the unqueried edge to 0 (ignore the unknown edge)
    • G1: take all edges that are connected according to the responses + set the unqueried edge to 1 (include the unknown edge)
  5. M cannot distinguish between G0 and G1 because both are consistent with its queries.
  6. The argument is that G0 is disconnected while G1 is connected, and hence since M can only decide whether the graph is connected or not, M must be wrong for one of the above inputs.
  7. G1 is connected trivially because it is consistent with the adversary's response strategy.
    • If you set the unqueried edges to 1, then the graph must be connected (together with those edges that exist, i.e. previously answered 1)
  8. G0 is disconnected by contradiction:
    • Suppose G0 is connected for purpose of contradiction
    • Then let (i, j) = the last unqueried pair of nodes be connected, i.e there is a path between i and j
    • Given the adversary strategy, it must replied 1 to all edges on this path, because they exist
    • let (i', j') be the edge on this path that was queried last. Then the adversary should have answered 0 as i and j will be set as connected since they are unqueried at that point.
    • So a contradiction arises and the assumption is incorrect.

Concrete Exampleโ€‹

  • n = 3 example

  • Since the algorithm is going to decide whether the graph is connected or not, the adversary simply takes the input that is not consistent with the algorithm.