Saturday 31 December 2022

IIEF's

I've been fiddling with Kotlin these last weeks and it's an absolutely amazing language. Honestly I didn't expect it, as it's an static language and I've always considered dynamic languages more appealing to my "Freak inside", but the expressiviness of Kotlin is just incredible. Notice that this expressiviness comes with a price, as there's a learning curve to understand what that beautiful and expressive code is doing. I'm going to use a sample comparing Groovy, JavaScript and Python. Hey, I absolutely love JavaScript and Python, being dynamic languages they still have some rare features that are not possible in Kotlin, but my overall feeling is that at least for non-browser projects, probably I would favor Kotlin for any relatively big project due to its combination of a beautiful language with the amazingly performant JVM.

Same as JavaScript, Kotlin has IIFE's (Immediatelly Invokable Function Expressions). They come very handy when you need a closure, and you'll only have one instance of that closure. In this case, as you won't be invoking that "closure factory" function in several places with different arguments to obtain different instances, but just once, you can just define and invoke the "closure factory" in the place where you first need that instance. As I'm still learning the crazy kotlin syntax, writing the same "one shot" closure factory in Kotlin, JavaScript and Python seemed like a pretty nice exercise to me. Let's see:

This is the Kotlin's most compact code I've come up with. It's beautiful and idiomatic, but I would not say it's easy to read, particularly if you stop coding in Kotlin for some time.


val formatWithCounter = {
    var counter = 0
    { txt: String, wrapper: String -> "${++counter}.${wrapper}${txt}${wrapper}" }
}()


println(formatWithCounter("Paris", "|"))
println(formatWithCounter("Paris", "+"))
// 1.|Paris|
// 2.+Paris+

The JavaScript code is slightly more verbose, but I guess feels a bit clearer. I would say it's the winner for me.


const formatWithCounter = (() => {
    let counter = 0;
    return (txt, wrapper) => `${++counter}.${wrapper}${txt}${wrapper}`
})();


console.log(formatWithCounter("Paris", "|"))
console.log(formatWithCounter("Paris", "+"))
// 1.|Paris|
// 2.+Paris+

The Python code is much more verbose and less elegant. The only Function Expressions in Python are lambdas (that in Python can only contain an expression). We still lack (multi)statement lambdas, as Guido said in 2006 that they were "unpythonic"... which is a reasoning that upsets me quite a bit, and we can not use "def" as an expression. So we have to define the factory function first and invoke it in another line. The same goes for the function being created and returned from the factory, that can not be just a lambda cause in this function I need to add the "nonlocal" line so that the counter variable is trapped by the closure (otherwise, as the variable is being modified, the compiler would consider it as local rather than trap it from the surrounding scope).


def factory():
    counter = 0
    def _format_with_counter(txt, wrapper):
        nonlocal counter
        return f"{(counter:=counter+1)}.{wrapper}{txt}{wrapper}"
    return _format_with_counter   
format_with_counter = factory()


print(format_with_counter("Paris", "|"))
print(format_with_counter("Paris", "+"))
# 1.|Paris|
# 2.+Paris+

An additional note regarding the Python version. I've used the walrus (:=) operator (assignment expressions). These 2 codes are equivalent:


        return f"{(counter:=counter+1)}.{wrapper}{txt}{wrapper}"
        
        # is equivalent to:
        
	counter += 1
        return f"{counter}.{wrapper}{txt}{wrapper}"
        

Saturday 24 December 2022

Bolo de Arroz

I've recently been lucky enough to spend a few days in Lisbon. I already wrote a post 5 years ago about how lovely the city is. Lisbon is still booming, and that massive advantage over other gorgeous European cities that I mention in that post has not done but to increase, as France, Belgium, Germany... are each day more and more submerged by that kind of incompatible and hostile "culture" arrived from abroad and that hopefully is not ravaging Portugal yet. Also, the Left-wing and ecologist mindset in Portugal seems to be rather civilized (the way it was intended to be), far away from the ultra-violent Far-Left, Islamo-Left, Eco-Madness scum in France that propagate self-hatred, racialism and communitarism.
As for cities in Eastern Europe, the fact that they are more conservative is no longer something that bothers me particularly, but the pro-USA fanatism and servility to the fucking North American empire of countries like Poland, the Baltic ones and so on (and their senseless hatred for anything related to Russia) is something that now makes me have a really negative perception of them.

Unexpectedly, I'm not going to talk about architecture, about charming streets, beautiful view-points... but about something I think I rarely talk about in my blog, food!. I mentioned in that previous post that Portuguese sweets are pretty good, and coffee is absolutely delicious and cheap. That statement remains completely true. The most iconic Portuguese sweet, the Pastel de Belem/Pastel de Nata is really popular in I guess most of Europe (for example you have them in Lidl in France and Spain, and in Mercadona in Spain). Though the ones that you buy in a supermarket (the ones in a Portuguese supermarkets are basically the same than those in Lidl abroad) are years ahead from the ones that you can buy in Belem, right out of the oven, with a powdered sugar and a cinnamon sachet, they are still delicious. Portuguese people are very fond of their coffee and sweets, so there are cafetarias/pastelarias in every corner (they are so omnipresent as bars and cafes in Spain) and it's a very common tradition (respected also by the young generations) to go to them to have a coffee and a sweaet in the afternoons (and obviously for breakfast). From the beautiful assortment of sweets that you'll find in a "Pastelaria", there's one that I have rediscovered in this trip, the delicious Bolo de Arroz. Forget you English muffins, Bolo de Arroz plays in an upper level (the same level as French magdalenes). I used to eat them with breakfast in 2008 while working in Lisbon, but in later visits I seemed not to appreciate them so much, and now I think I know why. In those visits I had bought them in MiniPreco supermarkets (part of Spanish Dia chain). This trip I had a Pingo Doce supermarket very close to my hostel, and I bought them there (it has its own "patisserie", cooking stuff in place), the difference is huge, pretty huge, they are way better. I don't think there's any difference betwen these ones in Pingo Doce and those that you can buy in a street patisserie.

I can not talk about Lisbon without bringing up memories of that amazing vegan buffet that has become the icing on the cake in my visits to Lisbon, Jardim das Cerejas. Right in the center of Lisbon you find this small, cosy restaurant, with a neighbourhood feeling, where a buffet with a delicios veggie soup, salad and 4 main dishes along with 2 types of rice costs just 9.5 euros. Add it a freshly squeezed juice (you can mix apple, orange, carrot...) for just 2.5 euros. The food is absolutely delicious. Some of the dishes have a black sauce that I guess is a mix of soja sauce with something more, that has such an intense taste, buff...

Friday 16 December 2022

Boolean Coercion/Conversion, JavaScript vs Python

How a not boolean value is mapped to true or false (either converted using a function or operator, or coerced when used in a boolean context) is one of those things that I need to rethink from time to time. Adding to this that my 2 main languages as of today, Python and JavaScript, have some differences on this topic, I've thought it useful to put a small summary here.

Javascript
This post is a pretty good reference. Falsy values in JavaScript are:
undefined and null (the 2 nullish values), false, NaN, 0 and "" (empty string).
We can convert any value to boolean either with '!!value' or with 'Boolean(value)'

There's something more to bear in mind. Not al falsy values have the same behaviour with the == operator. 0 is equal to false, and "" is equal to false:

0 == false
true
"" == false
true
1 == true
true

undefined == false
false
null == false
false
NaN == false
false

null == undefined
true

Python
Answers here are a pretty good reference. The following values are considered false:
None, False, 0, "" (empty string), any other empty container: (), [] and any empty mapping, for example, {}..
Additionally, a custom class can define the __bool__() method, that will be used when converting instances of that class to boolean.
We can convert any value to boolean either with 'not not value' or with 'bool(value)'

We also have to bear in mind what happens when using the equality operator "==". Only 0 == False and 1 == True are true. All other cases are false:

>>> 1==True
True
>>> 0==False
True
>>> None==False
False
>>> [] == False
False
>>> [] == True
False
>>> 2==False
False
>>> 2==True
False

So the big difference betwewn Javascript and Python regarding boolean conversion/coercion is that in JavaScript an empty array and an empty object are coerced to true, while in Python they are coerced to False. In addition, in Python we can customize the behaviour of our classes by implementing the __bool__ method.

Sunday 4 December 2022

Future vs Future (asyncio vs concurrent.futures)

I've been recently working with Python's very nice concurrent.futures.Executor (the ProcessPoolExecutor particularly). When combining it with the async - await magic I've come across an important gotcha that had me confused for a while.

So I have a function running inside an eventloop. In that function I create a ProcesPoolExecutor and submit some actions to it. As soon as one action completes I want to do something with its result and then continue to wait for the next action, so until all of them are done. My code looked like this:


async def parse_blocks(blocks):
	parser = BlockParser()
	pending_blocks = []
	for block in blocks:
		future_result = executor.submit(parser.parse, block, 0)
		pending_blocks.append(future_result)) 
	while len(pending_blocks):
		done_blocks, pending_blocks = await asyncio.wait(pending_blocks, return_when=asyncio.FIRST_COMPLETED)
		for done_block in done_blocks:
			print("block parsed!)
			result_writer.write(done_block)
	print("all blocks parsed")


The above code was giving me an odd exception in the wait call: TypeError: An asyncio.Future, a coroutine or an awaitable is required. But, executor.submit returns a Future, so what's happening?. Well, executor.submit returns a concurrent.futures.Future, and asyncio.wait is expecting an asyncio.Future. Hopefully we can obtain an asyncio.Future from a concurrent.futures.Future by means of asyncio.wrap_future. I found about it here.

To convert a concurrent.futures.Future into an asyncio.Future, you can call asyncio.wrap_future. The returned asyncio future is awaitable in the asyncio event loop and will complete when the underlying threading future completes. This is effectively how run_in_executor is implemented.

So this code now works fine:


async def parse_blocks(blocks):
	parser = BlockParser()
	pending_blocks = []
	for block in blocks:
		future_result = executor.submit(parser.parse, block, 0)
		pending_blocks.append(asyncio.wrap_future(concurrent_futures_future)) 
	while len(pending_blocks):
		done_blocks, pending_blocks = await asyncio.wait(pending_blocks, return_when=asyncio.FIRST_COMPLETED)
		for done_block in done_blocks:
			print("block parsed!)
			result_writer.write(done_block)
	print("all blocks parsed")


It seems odd to have to different Future classes, that both represent the same, a result that will be provided in the future. Well one of the differences that I get (for example from this discussion) is that asyncio.Future.add_done_callback will invoke its callbacks through the event loop, which I guess is necessary for the coopeative nature of asyncio. A concurrent.futures.Future will not use the eventloop for those callbacks, so this probably would break that cooperativism. This discussion goes a bit more in depth.