5
\$\begingroup\$

Recently I made an basic port of the JavaScript Promise construct to Python. Here's the basic code:

class Promise:
    def __init__(self, fn):
        self.value = None
        self.errors = []
        self._state = "unfullfilled"

        def resolve(val): 
            if self._state == "settled":
                return
            self.value = val
            self._state = "settled"
        def reject(err):
            if self._state == "settled":
               return
            self.errors.append(err)
            self._state = "settled"
        fn(resolve, reject)

    def catch(self, fn):
        if self.errors:
            for i in self.errors:
                fn(i)
                self.errors.remove(i)
        return self

    def then(self, fn):
        if not self.errors:
            fn(self.value)
        return self

    @staticmethod
    def resolve(val):
        def g(resolve, reject):
            resolve(val)
        return Promise(g)

    @staticmethod
    def reject(val):
        def g(resolve, reject):
            reject(val)
        return Promise(g)

What could I improve in this code? Besides that, are there any bugs in this code?

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to codereview. Have you checked promise module? \$\endgroup\$ – Grajdeanu Alex. Mar 5 '18 at 9:13
  • \$\begingroup\$ This code is for personal use. I was just checking if it is okay to write code in this manner. \$\endgroup\$ – Vikram Durai Mar 5 '18 at 13:06
1
\$\begingroup\$

Thank you for showing your code. You really should show us how to use it, by including unit tests, a reference URL, or with comments. At a minimum the class needs a docstring.

self._state = "unfullfilled"

Typo. Consider using enum.Enum instead of str.

self.value = None

This appears to be just wrong. (Hard to tell, since no docstring describes what valid callers may do.) A fn could choose to return None, yes? The usual approach for such a sentinel is to invoke object() to create a private object, essentially an allocated memory location that other code doesn't know about. Then test equality against that. If, on the other hand, you want your API to prohibit passing None, then you'll want to add some checks for that.

self.errors.remove(i)

That's an odd way to phrase it. The usual idiom for the loop you wrote would be to .pop() the initial element. Consider switching from list to deque if lots of errors might accumulate.

|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.