Skip to content

Instantly share code, notes, and snippets.

@jaysudodeveloper
Forked from santisbon/Good taste.md
Created December 27, 2016 06:26
Show Gist options
  • Save jaysudodeveloper/2ae49041a7d688ef06865f22d6403815 to your computer and use it in GitHub Desktop.
Save jaysudodeveloper/2ae49041a7d688ef06865f22d6403815 to your computer and use it in GitHub Desktop.

Revisions

  1. asantisbon revised this gist Nov 23, 2016. 1 changed file with 13 additions and 8 deletions.
    21 changes: 13 additions & 8 deletions Good taste.md
    Original file line number Diff line number Diff line change
    @@ -42,21 +42,24 @@ int main() {

    /*
    Add some entries.
    When we start out with an empty list the function that adds an entry (which we'll talk about later) needs to
    modify the head pointer itself so instead of passing it a copy of the pointer we send a reference to it.
    When we start out with an empty list the function that adds an entry
    (which we'll talk about later) needs to modify the head pointer itself
    so instead of passing it a copy of the pointer we send a reference to it.
    */
    add_entry(&head, 3);
    add_entry(&head, 10);
    add_entry(&head, 2);
    add_entry(&head, 7);

    // Get a pointer to the entry we want to delete, in this example the node containing a "3" in it.
    // Get a pointer to the entry we want to delete,
    // in this example the node containing a "3" in it.
    node *entry = find_entry(head, 3);

    // Create a pointer to the pointer that points to the head of the list
    node **indirect = &head;

    // As long as what is referenced by our double pointer doesn't point to the same place as our entry pointer
    // As long as what is referenced by our double pointer doesn't point
    // to the same place as our entry pointer
    while((*indirect) != entry) {
    // Advance our double pointer by making it point to the "next" pointer.
    indirect = &(*indirect)->next;
    @@ -144,7 +147,8 @@ The following is a way to do it without having to worry about whether the list a
    ##### Within the main() function
    ```c
    int main() {
    // We start with an empty list but it could also be an existing list with elements.
    // We start with an empty list but it could also be an existing list
    // with elements.
    node *head = NULL;
    // A reference to the last pointer. Starts out pointing to the head.
    node **indirect = &head;
    @@ -159,8 +163,8 @@ int main() {
    indirect = &(*indirect)->next;
    }

    // indirect now points to the last pointer in the list whether it was empty or not
    // so we just add the new node there.
    // indirect now points to the last pointer in the list whether it was
    // empty or not so we just add the new node there.
    *indirect = new_node;

    return 0;
    @@ -187,7 +191,8 @@ void add_entry(node **head, int new_value) {
    *indirect = &(**indirect)->next;
    }

    // indirect now points to the last pointer in the list whether it was empty or not
    // indirect now points to the last pointer in the list
    // whether it was empty or not
    **indirect = new_node;
    }
    ```
  2. asantisbon revised this gist Nov 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # On Good Taste

    Linus Torvalds in an [interview](http://www.ted.com/talks/linus_torvalds_the_mind_behind_linux/transcript?language=en) talked about the idea of good taste in code or what I like to call elegance. As one might expect from two slides meant to make a point during a talk, he omits a lot of details to keep it short and simple. This post digs into the specifics of his example and adds another example including working code.
    Linus Torvalds in an [interview](http://www.ted.com/talks/linus_torvalds_the_mind_behind_linux/transcript?language=en) talked about the idea of good taste in code or what I like to call elegance. As one might expect from two slides meant to make a point during a talk, he omits a lot of details to keep it short and simple. This post digs into the specifics of his example (deleting an element from a list) and adds another example (inserting an element in a list) including working code.

    ## Example from Linus

  3. asantisbon revised this gist Nov 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,7 @@ typedef struct node_t {

    #### Good taste

    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. I'll skip the poor taste version because you can easily implement that once you know the better one. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & operators have right-to-left associativity.
    Now the fun part: The implementation of the *good taste* example keeping the same outline from Torvalds's slide. I'll skip the less elegant version because you can easily implement that once you know the better one. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & operators have right-to-left associativity.

    ##### As part of the main() function
    ```c
  4. asantisbon revised this gist Nov 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -192,6 +192,6 @@ void add_entry(node **head, int new_value) {
    }
    ```
    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and you need to evaluate the costs and benefits of each approach.
    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and you need to evaluate the costs and benefits of each approach including both efficiency and maintainability.
    Below you'll find the file taste.c with full working examples of these concepts.
  5. asantisbon revised this gist Nov 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # On Good Taste

    Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torvalds_the_mind_behind_linux/transcript?language=en) and video available at the 14:17 marker) talked about the idea of good taste in code or what I like to call elegance. As one might expect from two slides meant to make a point during a talk, he omits a lot of details to keep it short and simple. This post digs into the specifics of his example and adds another example including working code.
    Linus Torvalds in an [interview](http://www.ted.com/talks/linus_torvalds_the_mind_behind_linux/transcript?language=en) talked about the idea of good taste in code or what I like to call elegance. As one might expect from two slides meant to make a point during a talk, he omits a lot of details to keep it short and simple. This post digs into the specifics of his example and adds another example including working code.

    ## Example from Linus

  6. asantisbon revised this gist Nov 23, 2016. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions Good taste.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # On Good Taste

    Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torvalds_the_mind_behind_linux/transcript?language=en) and video available at the 14:17 marker) talked about the idea of good taste in code or what I like to call elegance. As one might expect from two slides meant to make a point during a talk, he omits a lot of details to keep it short and simple. This post digs into the specifics of his example, including working code.
    Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torvalds_the_mind_behind_linux/transcript?language=en) and video available at the 14:17 marker) talked about the idea of good taste in code or what I like to call elegance. As one might expect from two slides meant to make a point during a talk, he omits a lot of details to keep it short and simple. This post digs into the specifics of his example and adds another example including working code.

    ## Example from Linus

    @@ -192,4 +192,6 @@ void add_entry(node **head, int new_value) {
    }
    ```
    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and you need to evaluate the costs and benefits of each approach.
    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and you need to evaluate the costs and benefits of each approach.
    Below you'll find the file taste.c with full working examples of these concepts.
  7. asantisbon revised this gist Nov 23, 2016. 1 changed file with 14 additions and 3 deletions.
    17 changes: 14 additions & 3 deletions Good taste.md
    Original file line number Diff line number Diff line change
    @@ -30,7 +30,11 @@ typedef struct node_t {

    ### Delete entry

    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & operators have right-to-left associativity.
    #### Good taste

    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. I'll skip the poor taste version because you can easily implement that once you know the better one. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & operators have right-to-left associativity.

    ##### As part of the main() function
    ```c
    int main() {
    // Create an empty list
    @@ -74,6 +78,7 @@ int main() {

    If we want to create a separate function to do the deletion, we'll need to change the pointer itself, not a copy of it. In C++ you can just declare the pointer parameter as a reference argument (&) and the compiler will take care of the details. In C we need to handle it ourselves so we add one more level of indirection for any parameters that need to be updated including pointers.

    ##### As a separate function
    ```c
    /*
    The head pointer may need to be modified so we need a double pointer.
    @@ -108,6 +113,8 @@ void remove_entry(node **head, node **entry) {
    Now let's look at the add_entry function we used. As it turns out, this one is also a good example of something we can do in a pretty straightforward way but also in a very elegant, better way.
    When adding an entry, we need to know if we're working with an empty list and therefore need to change the head pointer or if the list already contains elements, in which case we don't change the head but add the new node after the last one.
    #### Poor taste
    ```c
    /*
    When the list is empty adding an element requires modifying the head
    @@ -131,8 +138,10 @@ void add_entry(node **head, int new_value) {
    }
    }
    ```

    #### Good taste
    The following is a way to do it without having to worry about whether the list already has elements. It's more elegant. Let's start with the case where we're doing it from within our main() function.

    ##### Within the main() function
    ```c
    int main() {
    // We start with an empty list but it could also be an existing list with elements.
    @@ -159,6 +168,8 @@ int main() {
    ```

    And now let's see how we would do the same but in a separate function. This adds another level of indirection just as it did for the delete function.

    ##### As a separate function
    ```c
    /*
    We'll have to update the head pointer when the list is empty
    @@ -181,4 +192,4 @@ void add_entry(node **head, int new_value) {
    }
    ```
    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and at some point you need to evaluate the costs and benefits of each approach.
    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and you need to evaluate the costs and benefits of each approach.
  8. asantisbon revised this gist Nov 23, 2016. 1 changed file with 11 additions and 1 deletion.
    12 changes: 11 additions & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,9 @@
    # On Good Taste

    Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torvalds_the_mind_behind_linux/transcript?language=en) and video available at the 14:17 marker) talked about the idea of good taste in code or what I like to call elegance. As one might expect from two slides meant to make a point during a talk, he omits a lot of details to keep it short and simple. This post digs into the specifics of his example, including working code.

    ## Example from Linus

    This is an example of removing an element from a [singly-linked list](https://en.wikipedia.org/wiki/Linked_list). It's one of the first data structures you learn about when you start learning about computer science and programming. The reason it doesn't show particularly good taste is because we have that condition at the end where we take a different action depending on whether the element we want to remove is at the beginning of the list or somewhere in the middle.

    ![Bad taste](http://i.imgur.com/KVrR8Jt.jpg)
    @@ -12,6 +16,8 @@ Some things to keep in mind:
    * This example shows how we could do it when we're deleting the item from within the same function where our list was defined, meaning where our head pointer is defined. In a moment we'll look at the case where we use a separate function to manipulate the list. For now let's stick to the case where we're deleting it from within our main() function.
    * It assumes we already have a pointer to the element we want to delete.

    ## Implementation

    I'll use C because we don't need any C++ features to illustrate this point.

    First we'll define our node type.
    @@ -22,6 +28,8 @@ typedef struct node_t {
    } node;
    ```

    ### Delete entry

    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & operators have right-to-left associativity.
    ```c
    int main() {
    @@ -95,6 +103,8 @@ void remove_entry(node **head, node **entry) {
    }
    ```
    ### Add entry
    Now let's look at the add_entry function we used. As it turns out, this one is also a good example of something we can do in a pretty straightforward way but also in a very elegant, better way.
    When adding an entry, we need to know if we're working with an empty list and therefore need to change the head pointer or if the list already contains elements, in which case we don't change the head but add the new node after the last one.
    @@ -148,7 +158,7 @@ int main() {
    }
    ```

    And now let's see how we would do the same but in a separate function.
    And now let's see how we would do the same but in a separate function. This adds another level of indirection just as it did for the delete function.
    ```c
    /*
    We'll have to update the head pointer when the list is empty
  9. asantisbon revised this gist Nov 23, 2016. 1 changed file with 22 additions and 19 deletions.
    41 changes: 22 additions & 19 deletions taste.c
    Original file line number Diff line number Diff line change
    @@ -10,27 +10,23 @@ typedef struct node_t {
    } node;

    /*
    When the list is empty adding an element requires modifying the head
    pointer itself so the add function needs the address of the pointer,
    that is, a pointer to a pointer.
    We'll have to update the head pointer when the list is empty
    so we get a reference to it, not a copy.
    */
    void add_entry(node **head, int new_value) {
    node *current = *head;
    // A reference to the last pointer. Starts out pointing to the head.
    node ***indirect = &head;

    if(*head == NULL) {
    *head = malloc(sizeof(node));
    (*head)->value = new_value;
    (*head)->next = NULL;
    }
    else {
    while(current->next != NULL) {
    current = current->next;
    }

    current->next = malloc(sizeof(node));
    current->next->value = new_value;
    current->next->next = NULL;
    node *new_node = malloc(sizeof(node));
    new_node->value = new_value;
    new_node->next = NULL;

    while(**indirect != NULL) {
    *indirect = &(**indirect)->next;
    }

    // indirect now points to the last pointer in the list whether it was empty or not
    **indirect = new_node;
    }

    /*
    @@ -53,7 +49,7 @@ node *find_entry(node *head, int value) {
    */
    void remove_entry(node **head, node **entry) {
    /*
    The indirect pointer points to the pointer that we'll update
    The indirect pointer point to the pointer that we'll update
    */
    node ***indirect = &head;

    @@ -87,16 +83,23 @@ void print_list(node *head) {
    int main(int argc, char const *argv[]) {
    node *head = NULL;

    print_list(head);

    add_entry(&head, 4);
    add_entry(&head, 3);
    add_entry(&head, 10);
    add_entry(&head, 2);
    add_entry(&head, 7);

    print_list(head);

    node *entry = find_entry(head, 3);
    node *entry = find_entry(head, 2);
    remove_entry(&head, &entry);

    entry = find_entry(head, 4);
    remove_entry(&head, &entry);

    print_list(head);

    return 0;
    }
  10. asantisbon revised this gist Nov 23, 2016. 1 changed file with 23 additions and 0 deletions.
    23 changes: 23 additions & 0 deletions Good taste.md
    Original file line number Diff line number Diff line change
    @@ -148,4 +148,27 @@ int main() {
    }
    ```

    And now let's see how we would do the same but in a separate function.
    ```c
    /*
    We'll have to update the head pointer when the list is empty
    so we get a reference to it, not a copy.
    */
    void add_entry(node **head, int new_value) {
    // A reference to the last pointer. Starts out pointing to the head.
    node ***indirect = &head;

    node *new_node = malloc(sizeof(node));
    new_node->value = new_value;
    new_node->next = NULL;

    while(**indirect != NULL) {
    *indirect = &(**indirect)->next;
    }

    // indirect now points to the last pointer in the list whether it was empty or not
    **indirect = new_node;
    }
    ```
    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and at some point you need to evaluate the costs and benefits of each approach.
  11. asantisbon revised this gist Nov 23, 2016. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -125,14 +125,17 @@ void add_entry(node **head, int new_value) {
    The following is a way to do it without having to worry about whether the list already has elements. It's more elegant. Let's start with the case where we're doing it from within our main() function.
    ```c
    int main() {
    // We start with an empty list but it could also be an existing list with elements.
    node *head = NULL;
    // A reference to the last pointer. Starts out pointing to the head.
    node **indirect = &head;

    // We'll add a node with the value "4" in it
    node *new_node = malloc(sizeof(node));
    new_node->value = 4;
    new_node->value = 4;
    new_node->next = NULL;

    // Walk the list until indirect points to the last pointer of the list
    while(*indirect != NULL) {
    indirect = &(*indirect)->next;
    }
  12. asantisbon revised this gist Nov 23, 2016. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -126,6 +126,7 @@ The following is a way to do it without having to worry about whether the list a
    ```c
    int main() {
    node *head = NULL;
    // A reference to the last pointer. Starts out pointing to the head.
    node **indirect = &head;

    node *new_node = malloc(sizeof(node));
    @@ -137,7 +138,7 @@ int main() {
    }

    // indirect now points to the last pointer in the list whether it was empty or not
    // so we just add the new node.
    // so we just add the new node there.
    *indirect = new_node;

    return 0;
  13. asantisbon revised this gist Nov 23, 2016. 1 changed file with 22 additions and 3 deletions.
    25 changes: 22 additions & 3 deletions Good taste.md
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,7 @@ typedef struct node_t {

    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & operators have right-to-left associativity.
    ```c
    int main(int argc, char const *argv[]) {
    int main() {
    // Create an empty list
    node *head = NULL;

    @@ -59,6 +59,8 @@ int main(int argc, char const *argv[]) {

    // Free up the allocated memory
    free(entry);

    return 0;
    }
    ```

    @@ -120,9 +122,26 @@ void add_entry(node **head, int new_value) {
    }
    ```

    And this is a way to do it without having to worry about whether the list already has elements. It's more elegant.
    The following is a way to do it without having to worry about whether the list already has elements. It's more elegant. Let's start with the case where we're doing it from within our main() function.
    ```c
    // Tricky implementation of add_entry
    int main() {
    node *head = NULL;
    node **indirect = &head;

    node *new_node = malloc(sizeof(node));
    new_node->value = 4;
    new_node->next = NULL;

    while(*indirect != NULL) {
    indirect = &(*indirect)->next;
    }

    // indirect now points to the last pointer in the list whether it was empty or not
    // so we just add the new node.
    *indirect = new_node;

    return 0;
    }
    ```

    One final note: There's nothing wrong with the less elegant versions. They work just as well and are easy to implement. Coming up with clean, elegant solutions to problems is harder and at some point you need to evaluate the costs and benefits of each approach.
  14. asantisbon revised this gist Nov 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ typedef struct node_t {
    } node;
    ```

    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & opearators have right-to-left associativity.
    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & operators have right-to-left associativity.
    ```c
    int main(int argc, char const *argv[]) {
    // Create an empty list
  15. asantisbon revised this gist Nov 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ typedef struct node_t {
    } node;
    ```

    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and addres-of (&) operators. Also, the \* and & opearators have right-to-left associativity.
    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and address-of (&) operators. Also, the \* and & opearators have right-to-left associativity.
    ```c
    int main(int argc, char const *argv[]) {
    // Create an empty list
  16. asantisbon revised this gist Nov 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ typedef struct node_t {
    } node;
    ```

    Now the fun part: The implementation of the good taste example keeping the same structure from Torvalds's slide.
    Now the fun part: The implementation of the *good taste* example keeping the same structure from Torvalds's slide. As a reminder, the member access through pointer (->) operator has precedence over both the dereference (\*) and addres-of (&) operators. Also, the \* and & opearators have right-to-left associativity.
    ```c
    int main(int argc, char const *argv[]) {
    // Create an empty list
  17. asantisbon revised this gist Nov 22, 2016. 1 changed file with 21 additions and 1 deletion.
    22 changes: 21 additions & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -97,7 +97,27 @@ Now let's look at the add_entry function we used. As it turns out, this one is a

    When adding an entry, we need to know if we're working with an empty list and therefore need to change the head pointer or if the list already contains elements, in which case we don't change the head but add the new node after the last one.
    ```c
    // Naive implementation of add_entry
    /*
    When the list is empty adding an element requires modifying the head
    pointer itself so the add function needs the address of the pointer,
    that is, a pointer to a pointer.
    */
    void add_entry(node **head, int new_value) {
    node *current = *head;
    node *new_node = malloc(sizeof(node));
    new_node->value = new_value;
    new_node->next = NULL;

    if(*head == NULL) {
    *head = new_node;
    }
    else {
    while(current->next != NULL) {
    current = current->next;
    }
    current->next = new_node;
    }
    }
    ```
    And this is a way to do it without having to worry about whether the list already has elements. It's more elegant.
  18. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@ Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torv

    This is an example of removing an element from a [singly-linked list](https://en.wikipedia.org/wiki/Linked_list). It's one of the first data structures you learn about when you start learning about computer science and programming. The reason it doesn't show particularly good taste is because we have that condition at the end where we take a different action depending on whether the element we want to remove is at the beginning of the list or somewhere in the middle.

    ![Bad taste](http://i.imgur.com/KVrR8Jt.jpg)![Good taste](http://i.imgur.com/LgKhtO9.jpg)
    ![Bad taste](http://i.imgur.com/KVrR8Jt.jpg)

    The following is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

  19. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@ Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torv

    This is an example of removing an element from a [singly-linked list](https://en.wikipedia.org/wiki/Linked_list). It's one of the first data structures you learn about when you start learning about computer science and programming. The reason it doesn't show particularly good taste is because we have that condition at the end where we take a different action depending on whether the element we want to remove is at the beginning of the list or somewhere in the middle.

    ![Bad taste](http://i.imgur.com/KVrR8Jt.jpg)
    ![Bad taste](http://i.imgur.com/KVrR8Jt.jpg)![Good taste](http://i.imgur.com/LgKhtO9.jpg)

    The following is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

  20. asantisbon revised this gist Nov 22, 2016. 2 changed files with 2 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -71,7 +71,7 @@ If we want to create a separate function to do the deletion, we'll need to chang
    */
    void remove_entry(node **head, node **entry) {
    /*
    The indirect pointer point to the pointer that we'll update
    The indirect pointer points to the pointer that we'll update
    */
    node ***indirect = &head;
    2 changes: 1 addition & 1 deletion taste.c
    Original file line number Diff line number Diff line change
    @@ -53,7 +53,7 @@ node *find_entry(node *head, int value) {
    */
    void remove_entry(node **head, node **entry) {
    /*
    The indirect pointer point to the pointer that we'll update
    The indirect pointer points to the pointer that we'll update
    */
    node ***indirect = &head;

  21. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ This is an example of removing an element from a [singly-linked list](https://en

    ![Bad taste](http://i.imgur.com/KVrR8Jt.jpg)

    This one is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.
    The following is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

    ![Good taste](http://i.imgur.com/LgKhtO9.jpg)

  22. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ This is an example of removing an element from a [singly-linked list](https://en

    This one is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

    ![Good taste](http://imgur.com/a/XUuiM)
    ![Good taste](http://i.imgur.com/LgKhtO9.jpg)

    Some things to keep in mind:
    * This example shows how we could do it when we're deleting the item from within the same function where our list was defined, meaning where our head pointer is defined. In a moment we'll look at the case where we use a separate function to manipulate the list. For now let's stick to the case where we're deleting it from within our main() function.
  23. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@ Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torv

    This is an example of removing an element from a [singly-linked list](https://en.wikipedia.org/wiki/Linked_list). It's one of the first data structures you learn about when you start learning about computer science and programming. The reason it doesn't show particularly good taste is because we have that condition at the end where we take a different action depending on whether the element we want to remove is at the beginning of the list or somewhere in the middle.

    [Imgur](http://i.imgur.com/KVrR8Jt.jpg)
    ![Bad taste](http://i.imgur.com/KVrR8Jt.jpg)

    This one is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

  24. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@ Linus Torvalds in an interview ([transcript](http://www.ted.com/talks/linus_torv

    This is an example of removing an element from a [singly-linked list](https://en.wikipedia.org/wiki/Linked_list). It's one of the first data structures you learn about when you start learning about computer science and programming. The reason it doesn't show particularly good taste is because we have that condition at the end where we take a different action depending on whether the element we want to remove is at the beginning of the list or somewhere in the middle.

    ![Bad taste](http://imgur.com/a/8ZhJs)
    [Imgur](http://i.imgur.com/KVrR8Jt.jpg)

    This one is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

  25. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ This is an example of removing an element from a [singly-linked list](https://en

    This one is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

    ![Good taste](http://imgur.com/LgKhtO9)
    ![Good taste](http://imgur.com/a/XUuiM)

    Some things to keep in mind:
    * This example shows how we could do it when we're deleting the item from within the same function where our list was defined, meaning where our head pointer is defined. In a moment we'll look at the case where we use a separate function to manipulate the list. For now let's stick to the case where we're deleting it from within our main() function.
  26. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ This is an example of removing an element from a [singly-linked list](https://en

    This one is better. More elegant. It doesn't matter which element we are trying to remove, we always take the same action and it works for both cases.

    ![Good taste]()
    ![Good taste](http://imgur.com/LgKhtO9)

    Some things to keep in mind:
    * This example shows how we could do it when we're deleting the item from within the same function where our list was defined, meaning where our head pointer is defined. In a moment we'll look at the case where we use a separate function to manipulate the list. For now let's stick to the case where we're deleting it from within our main() function.
  27. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -62,7 +62,7 @@ int main(int argc, char const *argv[]) {
    }
    ```
    If we want to create a separate function to do the deletion, we'll need to add one more level of indirection for any parameters that need to be updated such as pointers themselves rather than copies of the pointers.
    If we want to create a separate function to do the deletion, we'll need to change the pointer itself, not a copy of it. In C++ you can just declare the pointer parameter as a reference argument (&) and the compiler will take care of the details. In C we need to handle it ourselves so we add one more level of indirection for any parameters that need to be updated including pointers.
    ```c
    /*
  28. asantisbon revised this gist Nov 22, 2016. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions Good taste.md
    Original file line number Diff line number Diff line change
    @@ -93,14 +93,14 @@ void remove_entry(node **head, node **entry) {
    }
    ```

    Now let's look at the add_entry function we used. As it turns out, this one is also a good example of something we can do in a pretty straighforward way but also in a very elegant, better way.
    Now let's look at the add_entry function we used. As it turns out, this one is also a good example of something we can do in a pretty straightforward way but also in a very elegant, better way.

    When adding an entry, we need to know if we're working with an empty list and therefore need to change the head pointer or if the list already contains elements, in which cae we don't change the head but add the new node after the last one.
    When adding an entry, we need to know if we're working with an empty list and therefore need to change the head pointer or if the list already contains elements, in which case we don't change the head but add the new node after the last one.
    ```c
    // Naive implementation of add_entry
    ```

    And this is a way to do it without having to worry about whther the list already has elements. It's more elegant.
    And this is a way to do it without having to worry about whether the list already has elements. It's more elegant.
    ```c
    // Tricky implementation of add_entry
    ```
  29. asantisbon revised this gist Nov 22, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -62,7 +62,7 @@ int main(int argc, char const *argv[]) {
    }
    ```
    If we want to create a function to do the deletion, we'll need to add one more level of indirection for any paramaters that need to be updated such as pointers themselves rather than copies of the pointers.
    If we want to create a separate function to do the deletion, we'll need to add one more level of indirection for any parameters that need to be updated such as pointers themselves rather than copies of the pointers.
    ```c
    /*
  30. asantisbon revised this gist Nov 22, 2016. 1 changed file with 32 additions and 1 deletion.
    33 changes: 32 additions & 1 deletion Good taste.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ typedef struct node_t {
    } node;
    ```

    Now the fun part: The implementation of the good taste example.
    Now the fun part: The implementation of the good taste example keeping the same structure from Torvalds's slide.
    ```c
    int main(int argc, char const *argv[]) {
    // Create an empty list
    @@ -62,6 +62,37 @@ int main(int argc, char const *argv[]) {
    }
    ```
    If we want to create a function to do the deletion, we'll need to add one more level of indirection for any paramaters that need to be updated such as pointers themselves rather than copies of the pointers.
    ```c
    /*
    The head pointer may need to be modified so we need a double pointer.
    The entry pointer is also passed by reference as we'll free that memory.
    */
    void remove_entry(node **head, node **entry) {
    /*
    The indirect pointer point to the pointer that we'll update
    */
    node ***indirect = &head;
    /*
    Walk the list as long as we haven't found the pointer we're looking for
    */
    while((**indirect) != *entry) {
    *indirect = &(**indirect)->next;
    }
    /*
    We remove it.
    indirect, which now points to either null or to the pointer that points to
    the entry we want to delete, is set to whatever comes after that entry.
    */
    **indirect = (*entry)->next;
    free(*entry);
    }
    ```

    Now let's look at the add_entry function we used. As it turns out, this one is also a good example of something we can do in a pretty straighforward way but also in a very elegant, better way.

    When adding an entry, we need to know if we're working with an empty list and therefore need to change the head pointer or if the list already contains elements, in which cae we don't change the head but add the new node after the last one.