Saturday, 31 May 2025

Resolvable Promise

We know that JavaScript promises do not have a resolve or a reject method. A Promise constructor receives an executor function that represents the code to be run and that eventually will resolve or reject that Promise. For that, this executor function receives a resolve and reject function. So it's as if the Promise could only be resolved/rejected "from inside", by the code that "materializes" that Promise. Well, as I did in this old post, from inside the executor we can assign the resolve/reject function to some outer variable or field, and use that to resolve/reject the Promise "from outside".

With that in mind, I was thinking about having a resolvable (and rejectable) Promise that inherits from Promise and has a resolve and reject method (that just make use of the resolve/reject functions that were passed to the executor). Let's see how that can be implemented:


class ResolvablePromise extends Promise {
    constructor(executor) {
        let _resolve, _reject;
        let executorWrapper = (res, rej) => {
            _resolve = res;
            _reject = rej;
            executor(res, rej);
        };      
        super(executorWrapper);
        // now "this" is available
        this.resolve = _resolve;
        this.reject = _reject;  
    }
}

My initial implementation (see below) was failing (it was not throwing an exception as the error was captured by the Promise constructor itself), but I could see it with the debugger: Must call super constructor in derived class before accessing 'this' or returning from derived constructor"


class WRONGResolvablePromise extends Promise {
    // this does not work because "this" is not available yet in executorWrapper  
    // I see an "internal error": "Must call super constructor in derived class before accessing 'this' or returning from derived constructor"
    constructor(executor) {
        let executorWrapper = (res, rej) => {
            // here "this" (that the arrow function should find in the constructor through the Scope chain) is undefined
            this.resolve = res;
            this.reject = rej;
            executor(res, rej);
        };      
        super(executorWrapper);
    }

That's because in the constructor of a child class "this" is not available until super has been called. I was expecting that the arrow function that I use as executorWrapper would reach the lexical "this" in the ResolvablePromise.constructor through the Scope chain, but as I've said it's undefined there until super has finished

Now that we can freely resolve/reject a Promise, what happens if we try to resolve or reject again a promise that is no longer in pending state (it has already been resolved/rejected)? Nothing, the Promise state does not change and we don't get any error. This is different from Python asyncio, where invoking set_result or set_exception on a Future that is already done will cause an InvalidStateError exception.


let pr1 = new ResolvablePromise((resolve, reject) => {    
    setTimeout(() => {
        resolve('resolved');
    }, 2000);
});

pr1.resolve('manually resolved');
try {
    let res = await pr1;
    console.log(res);
} catch (err) {
    console.log(err);
}

let pr2 = pr1.then(res => {        
    console.log(res); //manually resolved
    return res;
});
console.log(pr2.constructor.name); // ResolvablePromise!!! rather than Promise

// I can resolve it again, it won't crash, it will just continue to be resolved to the same value
pr1.resolve('manually resolved again');
try {
    let res = await pr1;
    console.log(res); //manually resolved
} catch (err) {
    console.log(err);
}

// rejecting a resolved promise won't have any effect either
pr1.reject('manually rejected');
try {
    let res = await pr1;
    console.log(res); //manually resolved
} catch (err) {
    console.log(err);
}

/*
manually resolved
ResolvablePromise
manually resolved
manually resolved
manually resolved
*/


I thought that it would be important that the different methods in a ResolvablePromise (then, catch, finally) also returned a ResolvablePromise, rather than a standard Promise, so that we can apply the resolve/reject methods to the promises produced during chaining. I did an implementation and came across an odd problem, caused by the fact that in recent JavaScript versions that's no longer necessary. When subclassing a Promise the then-catch-finally methods of parent Promise already return an instance of the Child class! (see my "ResolvablePromise!!! rather than Promise" comment in the above code). This is an interesting topic that I'll explain in more detail in a separate post.

Friday, 23 May 2025

Try-Expression 2

Time ago I wrote about how nice Kotlin try expressions feel to me, and about emulating them in JavaScript using a function. Obviously we can also emulate them in Python, though the lack of statement lambdas restrict the cases where they can be used in an elegant way (without having to declare a separate function before). Let's see a simple implementation (a more complex one would include a finally function and different handlers for different exception types):


def do_try(action: Callable, exceptions: BaseException | list[BaseException] | None = Exception, on_except: Any | None = None) -> Any:
    """
    simulate 'try expressions'
    on_except can be a value or a Callable (that receives the Exception)
    """
    try:
        return action()
    except exceptions as ex:
        return on_except(ex) if (on_except and callable(on_except)) else on_except

There's a rejected PEP that proposed a pretty nice syntax:
cond = (args[1] except IndexError: None)
but we know how anti-functional programming some Python deciders are...

Kotlin try expressions are obviously more powerful as we can have multiple statements, not just expressions, in its try-catch-finally blocks, but at the same time for simple cases (like the above proposal) are more verbose (because of the brackets).

There are two cases where the simple do_try function (with its defaults) that I showed above really shines, for "try and forget" cases and for "default if it fails" cases.



# try and forget
do_try(lambda: os.unlink(aux_file1))

# default if it fails
v = do_try(lambda: int(txt), on_except=-1)


It's interesting that python provides a context manager for "try and forget" cases:



from contextlib import suppress

with suppress(Exception):
    os.unlink(aux_file1)
    

That context manager really shines when combined with a contextlib.nullcontext, so that we can easily decide to ignore or not to ignore exceptions:



def myfunction(arg, ignore_exceptions=False):
   # nullcontext has no effect, so it won't ignore exceptions
   cm = contextlib.suppress(Exception) if ignore_exceptions else contextlib.nullcontext()
   with cm:
        # Do something
        

In Kotlin, apart from the expressive try-catch expressions we have the runCatching function. This function can be used instead of try-catch, providing an alternative, more functional way of dealing with errors. That's a complex beast that I have not properly explored yet (and even less more purely functional approaches like Arrow), so what interests me about runCatching is using it just for "try and forget" situations and for "default if it fails" situations. I copy-paste 2 samples from this nice article.


// try and forget
fun fireAndForget() {
    try {
        riskyFunction()
    } catch (t: Throwable) {
        // Ignore
    }
}

fun fireAndForget() {
    runCatching { riskyFunction() }
}


// default if it fails:
fun parseNumberWithDefault(input: String): Int {
    return try {
        input.toInt()
    } catch (t: Throwable) {
        0 // Default value for invalid numbers
    }
}

// it's cleaner using runCatching:
fun parseNumberWithDefault(input: String): Int {
    return runCatching { input.toInt() }.getOrElse { 0 }
}



Monday, 12 May 2025

Novembre (Film)

I've already watched a couple of times Novembre the film that follows the chase of the Islamist terrorists after the November 13th Islamist attacks in Paris. The film touches me on personal level. I remember that day of 2015. It was a Friday and I was living in Toulouse. After dinner I was working for 2 hours, almost the last task for a project that made me rather nervous and uncomfortable, so when finished I felt pretty relieved. Before opening some film on the laptop I decided to check the news and they came as a storm. I was quite shocked, and I was terrified. But I was not terrified because of the idea that some day that could happen to me, but because at that time I still thought that the problem with Islamism (and all what goes along with a big part of the "Muslim community in France", like anti-white and anti-Asian racism, the hatred for France, the "parallel societies, the criminality...) was not so big, and that the French society still worked fine. And I was terrified before the prospect of the French people overreacting to this attack with a wave of violence against all Muslims (and even just foreigners). Of course that did not happen. Hopefully, those few moderate Muslims that are well integrated (even assimilated) in French society have not faced any sort of retaliation (well, indeed the only discrimination and attacks that they suffer come from non-moderate, non-integrated Muslims and the far-left that see them as traitors to "their community"). But unfortunately, those non-integrated, strict or radical Muslims that hate us so much have not seen any sort of retaliation either...

OK, enough with my "old-white-straight-privileged man disconnected from progress" speech, let's talk about the film. The film is rather intense, it portrays well the tension and efforts of the French counter-terrorism to neutralize those blood thirsty beasts. I like a lot how it represents an arrested Islamist (that was not involved in this attack) as someone totally crazy with hatred for all infidels, and I also quite enjoyed the confrontation with a neo-nazi bastard in prison that is suspected of having sold weapons to the terrorists. That's purely fictional, as far as it's known the criminal networks from which the terrorists got their weapons did not involve neo-nazis, and indeed, regardless of how mentally sick neo-nazis can be (and regardless of the very good relations between "the original" nazis in the 30's-40's and Muslim groups) it's very, very forced to envision a French neo-nazi (that by the way, we are talking about a micro-minority of maybe 100-200 scumbags) selling weapons to an Islamist. That said, this idiot says something I could not agree more:

Those deaths were not caused by my weapons, but by 50 years of shitty policies. On Friday, the army should have taken action, dropping Napalm over the banlieus.

Regarding the fictional elements in the film:

Director Cédric Jimenez has taken creative liberties to dramatize certain aspects of the story. Reviews indicate that Novembre is not a strict documentary but rather a dramatization that incorporates fictionalized characters and scenarios to enhance the narrative.

The most interesting character in these events (and I mean not just in the film, but in the real events) is a young woman of Maghrebian origin (known in the film as Samia Khelouf, and in real life under the pseudonym Sonia) that had been hosting in her flat for some months another young woman (a bitch named Hasna) that happened to be the cousin of the main brain after the attacks (Abaaoud) and had helped him to find a hide-out in Saint Denis. Sonia contacted the police to explain the situation and utterly helped them to find the terrorists. The film shows how the police treated her with a lot of distrust and disdain and was about to abandon her after all her help (obviously this woman needs a new identity to avoid retaliation from other Terrorists or just from other Muslims that will see her as a "traitor"). Hopefully, eventually she has received some support from the French authorities, that have treated her a bit better than de Gaulle treated Harkis (those Algerians that fought on the French side during the Algeria war and that de Gaulle abandoned in an incomprehensible display of dishonor and inhumanity). And now, the film director decided to spit on her face, by depicting her in the film (as Samia) wearing an Islamic veil, that is something that she had never done in her life and that she is up against! Of course, for our progressist world showing us a devote Muslim (because that's what a veiled woman is) that is willing to collaborate with "the French" denouncing the terrorists is very, very cool, but the problem is that it's very, very unrealistic... I've asked Claude.ai some information about this heroic woman.

Who Is "Sonia"?

Sonia was a 40-year-old mother of two living in a Paris suburb. Known for her compassion, she often offered shelter to women in distress. One such woman was Hasna Aït Boulahcen, who turned out to be Abaaoud's cousin. Unbeknownst to Sonia, Hasna was aiding Abaaoud in finding a hideout after the attacks. On November 15, 2015, Sonia accompanied Hasna to meet someone in Aubervilliers. There, she met Abaaoud, who openly admitted his involvement in the attacks and his plans for further violence. Recognizing the gravity of the situation, Sonia alerted the authorities, providing crucial information that led to the police raid in Saint-Denis on November 18, where Abaaoud and his accomplices were killed.

Following her brave actions, Sonia entered a witness protection program, adopting a new identity and relocating to ensure her safety. Despite her heroism, she faced significant challenges, including feelings of abandonment by the state and difficulties in securing employment due to her concealed identity. Her story was later co-authored with journalist Claire Andrieux in the book Témoin ("Witness"), shedding light on her experiences and the broader implications of the attacks.

Portrayal in Novembre and Legal Action
In Novembre, Sonia's character is renamed Samia Khelouf and depicted wearing an Islamic veil, which Sonia does not wear in real life. Feeling misrepresented, she pursued legal action against the filmmakers. The dispute was amicably resolved, resulting in a disclaimer added to the film clarifying that the character is a fictionalized portrayal.

Sonia's story is a testament to individual courage and the profound impact one person can have in the face of terror.

At the end of the film we can read this text:

Le port du voile islamique par le personnage de Samia Khelouf répond à un choix de fiction qui ne reflète pas ses convictions personnelles

And now let me stress some of the information provided by Claude.ai: she faced significant challenges, including feelings of abandonment by the state and difficulties in securing employment due to her concealed identity.

In France there are several millions of people living on all sort of social aids, quite a few of them not having worked a single day in their lives, many of them professing a profound hatred for the French Nation and the French People, and many of them having perpetrated different kinds of crimes (from petty crimes to murder, rape, etc). Also, there are many thousands of Algerians (or Algerians with a French passport) that were entitled to a French retirement payment and that having been dead for years (or decades), their families in Algeria (that have "forgotten" to inform the Government about the decease) continue to receive that payment. And with such a generous welfare system, the French state thinks that a woman that has risked her life for France and the French People does not deserve to be granted a decent for-life payment that will make her new life a bit easier!!!

Monday, 5 May 2025

Pipe Operator part 2

Last year I found out about the existence of a pipe operator in several languages (other than bash) and wrote a post about some ways (Pipe21, coconut, a decorator that transpiles the function...) to bring that into Python. I've recently come across a very interesting post about pipes in different languages

The article mentions several decisions to take when adding pipes to a language:

  • Piping functions which accept multiple parameters. Should the piped value be the first parameter or the last (pipe first, pipe last)? Well, of course you can circumvent that by adding an extra wrapper function that just takes the piped value and invokes the real function with the value in the right position, or you can use Partial function application. I like the "pipe everywhere" approach and using a keyword to refer to the piped value.
  • What do we pipe (what do we put on the right side of the pipe operator), expressions or unary functions? I mean we pass the value to an expression or to an unary function (F# style)

The different answers to the 2 above questions have been the reason for having 2 different proposals for adding pipes to JavaScript, though there's now a single contender that is still going through the endless approval process. That proposal is a really interesting read, as it also explains how it differs from the rival proposal. To summarize:

Main proposal: We put an expression on the right side of the pipe operator and we refer to the piped value using a keyword.

Discarded proposal (F# like pipes): We put an expression that evaluates to an unary function on the right side of the pipe operator. If we are piping to a function that receives multiple parameters (or want to invoke a method in the piped value), we have to use an unary arrow function that will invoke the real function/method.

I have to say that I really like a lot this pipe operator, and revisiting my thoughts on how to emulate it in Python, I've come to the conclusion that just using a pipe() function (and combining it with functools.partial) is almost as elegant as the Pipe21 approach that I mentioned last year. It feels like a verbose, function based, version of the F# like approach. Let's see.


import functools
from functools import partial as pl

def pipe(val: Any, *fns: list[Callable]) -> Any:
    """
    pipes function calls over an initial value
    """
    def _call(val, fn):
        return fn(val)
    return functools.reduce(_call, fns, val)


cities = ["Paris", "Berlin", "Xixon", "Porto", "Prague", "Turin"]

pipe(cities, 
pipe(cities, 
    pl(filter, lambda x: x.startswith("P")), # bind the first argument to filter
    pl(map, lambda x: x.upper()), # bind the first argument to map
    pl(sorted, key=lambda x: len(x)), # use keyword arguments to bind the second argument to sorted
    print,
)

# ['PARIS', 'PORTO', 'PRAGUE']

# if we had a pipe operator like the one proposed for javascript we could write this:
# https://github.com/tc39/proposal-pipeline-operator?tab=readme-ov-file
# (cities
#     |> filter(lambda x: x.startswith("P"), $$)
#     |> map(lambda x: x.upper(), $$),
#     |> sorted($$, key=lambda x: len(x)),
#     |> print($$),
# )

Languages like C# or Kotlin come with extension methods, which facilitate method chaining and can seem like an alternative to having a pipe operator. I still prefer the pipe operator. We should use extension methods for a class/interface if really they fit in it (and we had missed to put them directly in the class/interface when it was designed), but we should not arbitrarily add extension methods to an object just to enable method chaining. All this relates to the discussion of whether something should be a method of a class or a separate function. If our normal design logic tells us that something should be a function and not a method, the lack of a pipe operator should not push us to turn the function into an extension method.