DEV Community

Cover image for [Rewrite]Link: Bidirectional Aliasing in Python
Nutchanon Ninyawee
Nutchanon Ninyawee

Posted on • Edited on

[Rewrite]Link: Bidirectional Aliasing in Python

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, a place to propose an idea before almost all 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 and the thread.

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

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.

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

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

Free Memory after unlinks

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

"    Hi dude.      ".trim() // "Hi dude."
"COVID-19 symptoms are Fever, Cough, and Shortness of breath".includes("Fever") // true
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.

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.

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.

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

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.

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

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

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-Chris Angelico and Andrew Barnert
  2. alias_identifier and set behaviour-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

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

Credit: Cover Photo by Vincent van Zalinge on Unsplash

Top comments (0)