Thursday, 25 September 2025

Kotlin Unit

When I wrote this post and mentioned the Kotlin use function for Automatic Resource Management I had some doubts about the signature. It's a generic function that returns R:


inline fun  T.use(block: (T) -> R): R

which fits so nice in the more functional style code I was discussing in that post, but what if we want to do something on that closable resource without returning any value? Well, the thing is that the function signature is also valid for that case, as in Kotlin what I mean by "not returning anything" (I'll be careful not to say "returning nothing" as in Kotlin Nothing has a particular meaning) means indeed returning Unit, a singleton object/class descending from Any, so that perfectly fits with the T generic type.

Having said this, it feels interesting to me to review how this "not retuning anything" works in different languages and compare it to the Kotlin approach and its advanced type system.

In Java and C# functions that do not return anything are marked as returning void. void is indeed a keyword representing "no return value" - it's not part of the normal type hierarchy.

In Python a function that does not have an explicit return statement or just does "return" without providing a value is indeed returning None (that is the single instance of the NoneType singleton class). If using type hints, mypy will consider correct that a function defined as returning Any returns None (as None is just a normal objec). In JavaScript the lack of an explicit return statement (or a simple "return;") will return the undefined value (JavaScript has this messy distinction between undefined and null that feels more accidental than intentional). For dynamic languages where type checking has come as an after thought (either directly in Python via typing or indirectly in JavaScript via its TypeScript "friend") this seems OK, but static languages things have to be more strict.

Kotlin elegantly establishes a subtle difference between functions that can return a value or the absence of that value, and functions that never return anything useful. For the former we use as return a nullable type. A getUser(id) function returns User? cause it returns a User if the id exists or null if that's not the case. On the other hand a writeLog() function returns Unit because it never returns anything useful. In Python we don't have that subtle difference, both write_log and get_user for missing id return None. With this, we can say that:

  • Kotlin uses Unit for "no meaningful value" and null for "the absence of an expected value"
  • Python lacks the semantic distinction between "no meaningful value" vs "absent value"

As I said at the start of this post I've been saying "does not return anything" (I should better say "does not return anything useful") rather than "returns nothing" because as I mention in this post Nothing has a special meaning in Kotlin. It's a bottom type, used for expressing that a function does not return (throws an exception, it's an infinite loop...). There's a good discussion here. I think Nothing is a confusing name, I prefer the naming used in Python typing for the same concept Never and NoReturn (both types are equivalent).

I was wondering, what if we want to declare a Kotlin function that always returns null? Well, probably that does not make much sense and we should just declare it as returning Unit. Googling around I've found this discussion where they propose returning Nothing?. They support the idea by copy-pasting a fragment of the documentation that does no longer seem to exist in the current documentation, so maybe the Kotlin designers just discarded that notion.

As a conclusion, in languages like Kotlin, Python or JavaScript we should not think about functions that do not return anything (save for functions that crash). All functions that finish naturally return something, but that something can be a not usable value (Unit) or an absent value(null, None, undefined).

Sunday, 14 September 2025

Python Currying

Last year I wrote a post about function currying in JavaScript, it corrected the (absolutely) wrong implementation that I had written some years ago. That last implementation did not feel particularly easy to understand to me. I was using three functions: curry, one for saving args and the curried function itself... I've recently implemented currying in Python, without looking into the JavaScript version, and it's interesting how thinking more in Python terms has made me better think about a JavaScript implementation

Currying a function means ending up with an invokable/callable object that references the original function and stores the provided parameters until all of them have been provided. In each "incomplete invokation" it has to return another invokable object trapping the expanded list of parameters. In Python an "invokable/callable object with state" is either a closure or an instance of a callable class (well, indeed normal functions are also instances of callables). And the creator of that invokable object is either a closure factory or a callable class. For my implementation I've used a Callable rather than a closure, somehow this time it felt more intutive:


class Curried:
    def __init__(self, fn, args: list[Any] | None = None):
        # in the initial call to create the initial curried function args is None
        self.fn = fn
        self.saved_args = args or []
        self.expected_args_len = len(inspect.signature(self.fn).parameters)
        # notice how for class based decorators we have to use update_wrapper here, rather than wraps
        functools.update_wrapper(self, fn)

    def __call__(self, *args):
        current_args = [*self.saved_args, *args]
        if len(current_args) > self.expected_args_len:
            raise Exception("too many arguments!!!")
        if len(current_args) == self.expected_args_len:
            return self.fn(*current_args)
        else:
            return Curried(self.fn, current_args)

# alias for better semantics when used as decorator        
curry = Curried


def test_curried(): 
    def format_city(planet: str, continent: str, country: str, region: str, city: str) -> str:
        """I'm the format_city docstring"""       
        return f"{planet}.{continent}.{country}.{region}_{city}"

    curried_format_city = Curried(format_city)
    
    # or if used as decorator:
    # @curry
    # def format_city(planet: str, continent: str, country: str, region: str, city: str) -> str:
    #     """I'm the format_city docstring"""       
    #     return f"{planet}.{continent}.{country}.{region}_{city}"

    print(curried_format_city("Earth")("Europe", "Spain")("Asturies", "Xixon"))

    format1 = curried_format_city("Earth", "Europe")
    format2 = curried_format_city("Earth", "Asia")
    # update_wrapper works nicely
    print(f"{format1.__name__=}, {format1.__doc__=}, ")

    print(format1("Spain")("Asturies", "Xixon"))
    print(format1("France")("Ile de France", "Paris"))

    print(format2("China")("Beijing", "Beijing"))
    print(format2("China")("Guandong", "Shenzen"))
    format3 = format2("Russia")("Northwestern")
    print(f"{format3.__name__=}, {format3.__doc__=}, ")
    print(format3("Saint Petersburg"))
    
# Earth.Europe.Spain.Asturies_Xixon
# format1.__name__='format_city', format1.__doc__="I'm the format_city docstring", 
# Earth.Europe.Spain.Asturies_Xixon
# Earth.Europe.France.Ile de France_Paris
# Earth.Asia.China.Beijing_Beijing
# Earth.Asia.China.Guandong_Shenzen
# format3.__name__='format_city', format3.__doc__="I'm the format_city docstring", 
# Earth.Asia.Russia.Northwestern_Saint Petersburg

As you see, a curried function is a callable object, an instance of the Curried class (that has a __call__ method). As I said, the curried function is equivalent to a closure, and the Curried class is equivalent to a closure factory. Notice that as I'm creating a callable object rather than a standard function I'm using functools.update_wrapper (rather than functools.wraps) to set the original __name__, __doc__, etc in the curried callable. I can invoke it directly (Curried(fn)) or use it as a decorator at function definition time.

In my previous JavaScript implementation I had 3 elements: a curry function, a saveArgs function and the closure itself. That's why it felt a bit strange to me, following the Python implementation, I only need 2 elements, the closure factory and the closure. So here it goes my new JavaScript implementation:


let curry = function createCurriedFn(fn, args) {
    // createCurriedFn is a closure factory, creates a closure that traps original fn and parameters
    let savedArgs = args ?? [];
    // return the curriedFn/closure
    return (...args) => {
        const curArgs = [...savedArgs, ...args];
        return curArgs.length >= fn.length 
            ? fn(...curArgs)
            : createCurriedFn(fn, curArgs);
    };
}

curriedFormat = curry(formatMessages);
curriedFormat("a")("b")("c");
curriedFormat("d")("e")("f");
curriedFormat("g", "h")("i");
curriedFormat("j", "k", "l");

// a-b-c
// d-e-f
// g-h-i
// j-k-l

As we know Python features named parameters (contrary to JavaScript), so we should contemplate that in our curry function. This is the improved version that does just that:


class Curried:
    def __init__(self, fn, args: list[Any] | None = None, kwargs: dict[str, Any] | None = None):
        # in the initial call to create the initial curried function args is None
        self.fn = fn
        self.saved_args = args or []
        self.saved_kwargs = kwargs or {}
        self.expected_args_len = len(inspect.signature(self.fn).parameters)
        # notice how for class based decorators we have to use update_wrapper here, rather than wraps
        functools.update_wrapper(self, fn)

    def __call__(self, *args, **kwargs):
        current_args = [*self.saved_args, *args]
        current_kwargs = {**self.saved_kwargs, **kwargs}
        
        if (cur_len := (len(current_args) + len(current_kwargs))) > self.expected_args_len:
            raise Exception("too many arguments!!!")
        if cur_len == self.expected_args_len:
            return self.fn(*current_args, **current_kwargs)
        else:
            #return wraps(self.fn)(Curried(self.fn, cur_arguments))
            return Curried(self.fn, current_args, current_kwargs)

# alias for better semantics when used as decorator        
curry = Curried


def test_curried(): 
    def format_city(planet: str, continent: str, country: str, region: str, city: str) -> str:
        """I'm the format_city docstring"""       
        return f"{planet}.{continent}.{country}.{region}_{city}"

    curried_format_city = Curried(format_city)
    #print(curried_format_city.__name__)
    print(curried_format_city("Earth")("Europe", "Spain")("Asturies", "Xixon"))

    format1 = curried_format_city("Earth", "Europe")
    format2 = curried_format_city("Earth", "Asia")
    # update_wrapper works nicely
    print(f"{format1.__name__=}, {format1.__doc__=}, ")

    print(format1("Spain")(region="Asturies", city="Xixon"))
    print(format1("France")("Ile de France", city="Paris"))

    print(format2(country="Chinaaa")(country="China")(city="Guangzhou", region="Guangdong"))
    print(format2("China")("Guandong", "Shenzen"))

    print(format2("China")("Guangdong", "Guangzhou"))
    print(format2("China")("Guandong", city="Shenzen"))
    format3 = format2("Russia")("Northwestern")
    print(f"{format3.__name__=}, {format3.__doc__=}, ")
    print(format3("Saint Petersburg"))


test_curried()
print("----------------------")

# Earth.Europe.Spain.Asturies_Xixon
# format1.__name__='format_city', format1.__doc__="I'm the format_city docstring", 
# Earth.Europe.Spain.Asturies_Xixon
# Earth.Europe.France.Ile de France_Paris
# Earth.Asia.China.Guangdong_Guangzhou
# Earth.Asia.China.Guandong_Shenzen
# Earth.Asia.China.Guangdong_Guangzhou
# Earth.Asia.China.Guandong_Shenzen
# format3.__name__='format_city', format3.__doc__="I'm the format_city docstring", 
# Earth.Asia.Russia.Northwestern_Saint Petersburg


Notice that contrary to what happens with standard functions, in the curried functions created by this implementation we can pass unnamed parameters after named ones, but the unnamed ones have to be provided in the same order as in the original function. Same as with functools.partial, we can provide the same named parameter multiple times, each new provided value overwrites the previous one.

Wednesday, 10 September 2025

Dans les Brumes de Capelans

I have to sadly admit that I'm not a great reader (I'm talking about literature, as for programming/technical stuff, political crap, history and so on I read tons of stuff). Just a few books per year (these last years a bit more, hopefully). Years ago (betwen 2009 and 2013 mainly) I was very much into Nordic Noir. I started with Stieg Larsson and continued with Asa Larsson (my favorite), Camilla Lackberg and Jo Nesbo. In Asa Larsson and Camilla Lackberg I terribly appreciated the "darkness" of many of the characters, that sadness, those difficoult existences... In recent years I've moved back into crime/thriller/police books, but this time into what I would call as "French blood noir", that is, crime-police-dark thriller novels where crimes are particularly bloody, violent, evil (involve torture, some sort of ritual, mutilations, BSDM...). It's what in Les Rivieres Pourpres (series) they call "crimes de sang". By the way, those series are really good, particularly Season 1 and 2 (season 3 and 4 felt a bit weaker to me, but have some excellent chapters also).

Since 2022 I've been reading the Sharko and Lucie Henebelle stories by Franck Thilliez. I can not recommend it enough. The crimes are horrible, bloody, sick, conducted by lonely psychopaths, organised elitist groups, pseudo-vampires... there are secret clubs that remind me of the 28 mms film, but above all I've come to love the main characters, particularly Sharko, and Nicolas Bellanger, whose nightmarish existence has become more and more important in the last books. They live a painful life, they fall, get up, fall again, overcome all sort of crap that leaves such deep scars... I should write several posts about them, but this one is not intended to that, but to a book from a different author, Dans les Brumes des Capelans by Olivier Norek.

I had previously read "Trilogy 93", that follows the misadventures of policeman Captain Victor Costa and his team tracking criminals in Seine-Saint-Denis. Pretty good, but it's more "standard crime-police literature" than the aforementiond "crimes de sang" stuff. In his real life Norek worked as a policeman in Seine-Saint-Denis, so one can imagine that there's much reality poured into those novels. "Dans les brumes de Capelans" is quite a different beast, much more of a dark thriller, of a "crimes de sang" story. Several years after the tragic end of the trilogy, Costa has managed to survive by running away from Paris and his previous life and living a lonely existence in such a secluded place as Saint Pierre et Miquelon, where works for the Witness Protection Service, managing a house by a cliff where he receives guests that have to remain hidden until they are provided with a new identity. We could say that Costa wants to remain as hidden as his guests.

This time he receives a young woman, Anna, that is the only survival of a maniac that has been seizing, torturing and murdering young girls for more than a decade, but that decided to keep her alive "for some reason". The girl is fucked up, Costa is fucked up, and strong bonds get woven between these 2 broken souls, 2 partners in pain and desolation. There are some very beautiful cathartic moments, there's the maniac killer that resurfaces, and there are many, many surprises. There's another interesting character, the policeman that dealt with Anna and the other girls disappearances and Anna's liberation. He appears only in the first and last chapters, playing an important role. Setting the story in this mysterious island adds darkness and loneliness to the story, a hard place for hard people.

I won't tell you more, go for the book and enjoy it.

Thursday, 4 September 2025

Automatic Resource Management as Expression

As a few weeks ago, going through the Python ideas forum has introduced me again to another interesting idea. As usual, someone proposes a syntax for a feature, and as it's clear that no syntax changes will be performed to provide that, people come up with interesting work arounds.

So someone proposed allowing to use with, the syntax for Automatic Resource Management with context managers, as an expression (so having a with expression along with the existing with statement. He was proposing something like this:
txt = do_something(json.load(f) with open('foo.json') as f)
That indeed reminds me of the syntax outlined in the rejected PEP for exception-catching expressions (aka try-expressions):
msg = (parse(txt) except ParsingError: None)

As I said, it's obvious that given how reluctant the Python leaders are to any syntax change, neither of those ideas will ever make it into the language. The good thing is that same as we can easily define a do_try function as the one we saw in this previous post, we can also define a using/with_do function, like this (taken from the discussion thread):


#def with_do(mgr, fn): 
def using(mgr, fn):
    with mgr as res:
        return fn(res)

# or maybe this is more semantic?
def do_with(fn, mgr):
    with mgr as res:
        return fn(res)

#config = tomllib.load(with open("file.toml", "rb") as f: f)
config = using(open("file.toml", "rb"), tomllib.load)
config = do_with(tomllib.load, open("file.toml", "rb"))

#data = with open("file.txt", "r") as f: f.read()
data = using(open("file.txt", "r"), lambda f: f.read())
data = do_with(lambda f: f.read(), open("file.txt", "r"), )

All the above examples are pretty contrived, as "with open() as" can be replaced by pathlib.Path.read_text, that takes care of managing any exception. I mean:


config = tomlib.loads(pathlib.Path('foo.json').read_text())

But there are other context manager use cases for which this kind of function would come handy.

The other Automatic Resource Management (ARM) mechanisms I'm familiar with are the C# using statement with IDisposables and Java Try-with-resources statement with Closables. So in Python, C# and Java ARM is provided via statements, not expressions, that's why I think I had never thought of using it as an expression. Given that in Kotlin almost everything is an expression, is easy to imagine that they have had this into account. Kotlin does not have a specific syntax construct for ARM, as given its rich and expressive syntax it can be nicely implemented with an extension function of the Closable interface, use. It Executes the given block function on this resource (a Closable object) and then closes it down correctly whether an exception is thrown or not:


inline fun  T.use(block: (T) -> R): R

As you can see in the signature, the block returns a value R, that in turn is returned by use, so what if we just want to execute a block that does not return anything? Well, that signature is also valid. In Kotlin a function that does not return anything does indeed return Unit (a singleton class), so when passing to use a block that does not return anything that generic type R becomes Unit, and everything is perfectly valid.