[Rewrite]Link: Bidirectional Aliasing in Python
Tags: python, ideas
Published: 2019-09-25 18:56:41

---
title: [Rewrite]Link: Bidirectional Aliasing in Python
published: true
description: Constructive Experience in the Discussion at Python-Ideas and last thought about "Link", Bidirectional Aliasing in Python
tags: #python #ideas 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/u2p4su7kjuxsisdc45s8.jpg
---
Hihi~ Devs,

First of all, I would like to communicate that Python-Ideas is a very open place for your ideas and contributions.

Dear People in the discussion 
> This was my first time being here among Python Core Developers, [Python-Ideas](https://mail.python.org/archives/list/python-ideas@python.org/), a place to propose an idea before almost all [PEPs](https://www.python.org/dev/peps/) starts here. It was a very constructive (and technical, of course) dialogue. Considering that I totally newbies to the development of the core language, I was impressed by those responses. I learned a lot of technical aspects of the language throughout the 3-day of conversation. And I know that there is still a lot to learn more!

The discussion(thread) at its 4-day becomes inactive now and will get abandoned soon. I would like to leave this idea to guys in any programming languages not limited to python. Here is my reconstructed proposal as a summary. The original proposal is [here](https://dev.to/circleoncircles/python-ideas-link-bidirectional-aliasing-in-python-3f20) and the [thread](https://mail.python.org/archives/list/python-ideas@python.org/thread/NS5YFU3NLMZ63F3YWAHFKNXIWKHHKHRQ/).


**Link** is a language feature that allows multiple variable names to always refer to the same underlying object define in a namespace.


## Notation of Link
The notation of **Link** and even how to call it are open for changes.
For now, if the variable a link with b. I will denote as `a >< b` or `link a, b`. To unlink all, `unlinks a`. To unlink a variable, `unlink a`. **Link** can be inspected via `links()` like `globals()` and `locals()` To `del` and `unlinks`, use `del_and_unlinks a`. `@link(a,b)` as decorator for function linked parameter. To inspect the link of a variable, use `aka(a)`. 

### Link can be chained.
`a >< b >< c` is same as 
```
a >< b
b >< c
```




## Link Behaviors

The behavior can be simplified as 
```python
a >< b
a = 1
print(b) # 1
b = 2
print(a) # 2

del a
print(b) # will raise NamedError, both were un-binded.

a = ['Cat', None]
assert a is b # True, both were rebinded.

```
More complex scenarios

### Link after have assigned
When a set of names is link or chained link. Only one variable(or name) is allowed to have been assigned before. Otherwise, the link will be unsuccessful and raise a `TooManyAssignError`. Thus, **Link** doesn’t care the order of variables.

```python
x = 5
x >< y # or `y >< x` would be ok

a = 1
b = 'foo'
a >< b # raise TooManyAssignError
```

### Free Memory after unlinks
```python
a >< b >< c
a = HighMemObject()

del a # free memory at once

b = HighMemObject()

unlinks b # unlink all but, all will keep referring to the `HighMemObject`.

del a # b, c still refer to the `HighMemObject`
del b # c still refer to the `HighMemObject`
del c # free memory
```



> **link** is more-or-less like entanglement property in quantum physics.

## Rationale

### Language Smooth Shift [Newly Added 11/03/2020]
Suppose you are coming from another language like js. You can archive the faster transition with 'link'. I will provide some examples in `String` - `str`

```javascript
"    Hi dude.      ".trim() // "Hi dude."
"COVID-19 symptoms are Fever, Cough, and Shortness of breath".includes("Fever") // true
```

```python
str.trim >< str.strip
"    Hi dude.      ".trim() # "Hi dude."

str.includes >< str.contains
"COVID-19 symptoms are Fever, Cough, and Shortness of breath".includes("Fever") // True
```

### Alter the variable name throughout a complex process
Easier to wrap your head around. If we can add another meaningful name. Less cognitive load for coder and reader. We rely on fewer comments to keep track of things.
> I code what I mean, mean what I code.
```python
students = School.list_students(year=4)
School.gruaduate(students)
students_graduated >< to_be_sentCertificates >< students

...

School.sendCertificates(students_graduated)
```

> Allow snippet/partial read, without a need to track upper variable changes.

this also may favor a guy who codes on interactive environments like `jupyter` , **del once and free mem. everywhere** no need to keep track of variables to the same object.

```python
import pandas as pd

df2train = pd.read_csv('train.csv') # VERY Large DataFrame
df >< df2train 

...

df >< df_didEDA

...

df2train >< df_preprocessed

...

df >< df_trained
...

aka(df) # df, df2train, df_didEDA, df_preprocessed, df_trained

del df # del once and free mem. everywhere! >//<
```

### Simplify aliasing
Instead of using `@property` and `@foo.setter` decoration and define in `__init__` like this.

```python
class PackageManager:
    packages = ['requests', 'loguru']

    @property
    def installed(self):
        return self.packages

    @installed.setter
    def installed(self, value):
        self.packages = value

    def remove(self):
        ...
        
    def __init__(self, ...)
        ...
        self.uninstall = self.remove

# monkey patching
PackageManager.uninstall = lambda x: print('uninstalled')
PackageManager.remove = lambda x: print('uninstalled')

```
We can just

```python
class PackageManager:
    uninstall >< remove
    installed >< packages
    packages = ['requests', 'loguru']

    def remove(): 
        ...

# Plus >//<, one-stop service monkey patching
PackageManager.uninstall = lambda x: print('uninstalled')

```

### Change unintuitive/non-pythonic naming to a better name
Everyone has a different set of vocabulary. Code users may have a hard time to wrap their heads around certain unfamiliar vocabulary created by coders. Linked variables allow them to change to a new name while keeping full compatibility.

```python
from selenium import webdriver

driver = webdriver.Firefox()
webdriver.find_element_by_name >< webdriver.get_element_by_name

elem = driver.get_element_by_name("q")
```

### Multilingual Code
```python
class Human:
    
    love >< 爱 >< любовь >< รัก >< 💞

    @link(you, вы, คุณ, 您)
    def love(self, you: 'Human'):
        self.soulmate = soulmate

    def code(self):
        return "import json"

    # link function name of similar term
    program >< code


# link class name of different languages
link Human, มนุษย์, 人的, человек, 👤

me = человек()
assert me.program() == me.code() # True


# monkey patch all at once!
人的.program = lambda x: "import this"
assert มนุษย์().program() == me.code() # True
```

## [ProbablyTooAmbitiousException]Allow unnested naming on part of a specified object
I am not sure that this should be part of ***Link*** or not. Since not all objects able to assign back etc… The sample would be
```python
house = {'resident': {'count': 12}}
house['resident']['number'] >< n_resident
n_resident = 3
print(house['resident']['number']) # print 3

del_and_unlink house

```


## Implementation Idea
There are several discussions about it. I can’t grasp the mechanism in details. Here is the list

1. [namespaces stuff](https://mail.python.org/archives/list/python-ideas@python.org/message/JXSY5SJM4LROV5D2Y7DTGCKBPTPVRRX7/)-Chris Angelico and Andrew Barnert
2. [_alias_identifier_ and set behaviour](https://mail.python.org/archives/list/python-ideas@python.org/message/RQNPJZXOIGXQTM6CBSMS2MKBWA3QI6NH/)-Richard Musil



In conclusion, it not as easy as it seems to me lol 😂. Not yet talking about performance, there is no solid implementation of this.

# Similar Existing
0. C++ pointers to the same address `auto & a = b`
1. C preprocessor directive (`#define`) used to define macros.
2. Python Assignment/Chained Assignment: the same object in a snap moment.

Credit: Cover Photo by Vincent van Zalinge on Unsplash