Interface Quirks in Golang

An interface defines a set of methods. A struct type implements these methods and qualifies the object type as an interface type.

However, how the struct implements the interface?

There are two ways:

  • As a pointer handler
  • As a value handler

Implementation with a struct value handler

package main

import (
	"fmt"
)

type Dummy interface {
  Add(int, int)int
}

type Adder struct {
  magic int
}

func (s Adder) Add(a, b int) int {
  fmt.Printf("magic:%d\n", s.magic)

  s.magic = a + b + s.magic
  return s.magic
}

func GenericAdder(object Dummy) {
    object.Add(2,3)
}

func main() {
  nums := Adder{magic: 43}
  nums.Add(2,3)
  GenericAdder(nums)
}

Output

magic:43
magic:43

Implementation with a pointer handler

package main

import (
	"fmt"
)

type Dummy interface {
  Add(int, int)int
}

type Adder struct {
  magic int
}

func (s *Adder) Add(a, b int) int {
  fmt.Printf("magic:%d\n", s.magic)

  s.magic = a + b + s.magic
  return s.magic
}

func GenericAdder(object Dummy) {
    object.Add(2,3)
}

func main() {
  nums := &Adder{magic: 43}
  nums.Add(2,3)
  GenericAdder(nums)
}

Output

magic:43
magic:48

Conclusion

  • A pointer handler is useful if the struct variable is updated by multiple handlers and the variable state needs to persist.
  • When the method is called with a value of struct, Go uses a copy of the struct variable.
  • The golang function signature stays the same for interface argument. It does not care for the passed argument type (pointer to struct or value of struct)

References

Written with StackEdit.



Python datetime strptime: unconverted data remains

Problem

    timeobj = datetime.datetime.strptime(my_time, '%Y-%m-%d %H:%M:%S').isoformat()
  File "/usr/lib/python2.7/_strptime.py", line 335, in _strptime
    data_string[found.end():])
ValueError: unconverted data remains:

Solution

The error was an elusive one. The solution was to make sure that the input time string is exactly as the format expected.
The missing piece was an extra space after the string which was causing format mismatch.
So the solution was to call strip() on the string before passing it to strptime().

Useful Tips

  • Read the format strip syntax of strptime().
  • datetime objects are very handy and general operations such as comparison are inbuilt.

References


Database Trigger Procedure in Postgres

Introduction

A trigger is an easy way to enforce a check or constraint, log mutations on a table. It is available for each row or a statement modification.
You can ask the DB to run a function triggered on an action (row append, update, delete) and a clause and timeframe (before/ after the operation).

Ingredients

  • Watch the Youtube video on Postgres trigger for 10 minutes (link)
  • Postgres psql client
  • Any text editor

Writing a Trigger Procedure is different than a Query

  • Find out Postgres datatypes
  • Typecasts using CAST() method
  • Learn Trigger Procedure Syntax

Sample Trigger Procedure

CREATE OR REPLACE FUNCTION time_range_check() RETURNS trigger AS
'
DECLARE
    acceptedTime timestamp;
    newTime timestamp;
    defaultTime timestamp;
  BEGIN
    acceptedTime = LOCALTIMESTAMP(0);
    defaultTime = to_timestamp(1577800000);
    newTime = to_timestamp(CAST(NEW.value as bigint));
	
    IF  newTime < defaultTime  THEN
		 raise EXCEPTION ''invalid past timestamp passed'';
         return NULL;
	END IF;
	IF  newTime > acceptedTime  THEN
		 raise EXCEPTION ''invalid future timestamp passed'';
         return NULL;
	END IF;
	RETURN NEW;
  END;
'LANGUAGE 'plpgsql';

Trigger Code

create trigger my_range_check 
before insert on my_table 
for each row 
when (NEW.item_id = 1)
execute procedure time_range_check();

How to Execute

After composing the trigger procedure and trigger, just paste the text on the psql command line.

How to Debug and Develop

You will get a hint of an error on pasting the trigger code on psql CLI. Every time the procedure code changes, we need to drop the trigger.

# drop trigger my_range_check on my_table;

List Triggers

# \d table_name

Reference


go-kit: Sample Code for Function to Log

go-kit: Sample Code for Function to Log

func getLogger() log.Logger {
    var logger log.Logger
    logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
    logger = log.With(logger, "instance_id", 123)
    return logger
}

The above function is easily usable in a go-kit project to log JSON style data.

func myfun() {
    mylogger := getLogger()
    mylogger.Log("a key", "a value")
}

Reference

Written with StackEdit.


etcd: A Reliable Distributed KV Store

  • Pronounced et-cee-dee
  • Persistent KV store
  • Uses Raft protocol to maintain data consistency
  • Developed in Go
  • Popular Use case: Kubernetes, Consul

Installation (OSX)

  • Step 1
    $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null
    
  • Step 2
    $ brew install etcd
    
  • Step 3
    $ which etcd
    /usr/local/bin/etcd
    

Start Server and Make Requests

  • Step 4
    $ /usr/local/bin/etcd
    [WARNING] Deprecated '--logger=capnslog' flag is set; use '--logger=zap' flag instead
    2020-03-23 01:11:59.084231 I | etcdmain: etcd Version: 3.4.4
    2020-03-23 01:11:59.084520 I | etcdmain: Git SHA: Not provided (use ./build instead of go build)
    2020-03-23 01:11:59.084527 I | etcdmain: Go Version: go1.13.8
    2020-03-23 01:11:59.084529 I | etcdmain: Go OS/Arch: darwin/amd64
    
  • Step 5
    $ etcdctl put mykey "this is a test"
    OK
    
    $ etcdctl get mykey 
    mykey
    this is a test
    

Reference

Written with StackEdit.


7 Rules of Git Commit Log

The seven commonly accepted rules on how to write a git commit message are:

  1. Limit the subject line to 50 characters.
  2. Capitalize only the first letter in the subject line.
  3. Don’t put a period at the end of the subject line.
  4. Put a blank line between the subject line and the body.
  5. Wrap the body at 72 characters.
  6. Use the imperative mood.
  7. Describe what was done and why, but not how.

Reference


Why Use Python Ordered Dictionary?

An ordered dictionary offers same time complexity as the standard dict.

The implementation is simple:

  • Keep two dictionaries and a doubly-linked list of keys.
  • The DLL maintains order.
  • One dict maps key => DLL node
  • Other dict maps key => value

Implementation details

https://github.com/python/cpython/blob/3.7/Lib/collections/init.py#L129

Example

Problem: Find the first non-repeating char in a string.

def firstUniqChar(self, s):
        """
        :type s: str
        :rtype: int
        """
        if len(s) == 0:
            return -1

        d = collections.OrderedDict()
        
        for index, c in enumerate(s):
            if c in d:
                d[c][0] += 1
            else:
                d[c] = [1, index]
        
        for k in d:
            if d[k][0] == 1:
                return d[k][1]
        
        return -1

Quicksort in C++

// cat quicksort.cc

#include <bits/stdc++.h>
#include <algorithm>    // std::swap

using namespace std;

int partition(int arr[], int low, int high);

void qsort(int arr[], int start, int end)
{
    int p;
    if (start < end)
    {
        p = partition(arr, start, end);
        qsort(arr, start, p - 1);
        qsort(arr, p + 1, end);
    }
}

int partition(int arr[], int low, int high)
{
    int pivot = arr[low];
    int i = low;
    int j = high + 1;

    do {
        do {
            i++;
        } while (arr[i] < pivot && i <= high);

        do {
            j--;
        } while(arr[j] > pivot);

        if (i < j)
            swap(arr[i], arr[j]);

    } while (i < j);
    swap(arr[low], arr[j]);
    return j;
}
int main()
{
    int arr[] = {11,2,100,1,2,31};

    size_t size = sizeof(arr)/sizeof(arr[0]);
    qsort(arr, 0, size - 1);

    for (int i = 0; i < size; i++)
        cout << arr[i] << endl;
}                                     

Reference


Basic HashMap in C++

Useful Points

  1. I use chaining for key collisions.
  2. The key is also stored with the payload.
  3. A GET operation searches the key in bucket’s linked-list and returns the value.
#include<bits/stdc++.h>

using namespace std;

class HashNode {
    private:
    string key;
    string value;
    HashNode *next;

    public:
    HashNode(string key, string value) {
        this->key = key;
        this->value = value;
        this->next = NULL;
    }

    string getValue() {
        return value;
    }
};

class HashKey {
    public:
    long hash(string key) {
        return 100 + key[0];
    }
};

class HashMap {
    private:
    size_t size;
    HashNode **table;
    HashKey hk;

    public:
    HashMap(size_t size) {
        table = new HashNode*[size];
    }

    ~HashMap() {
            delete [] table;
    }

    string get(string key) {
        long hash = hk.hash(key);
        HashNode *h = table[hash];
        return h->getValue();
    }

    void put(string key, string value)
    {
        long hash = hk.hash(key);
        table[hash] = new HashNode(key, value);
    }
};

int main()
{
    HashMap *hm = new HashMap(1024);
    hm->put("mykey", "avalue");
    cout << hm->get("mykey") << endl;

    return 0; 
}

Execution

$ g++ ./hashmap.cc
$ ./a.out
avalue