Code assistants

I’ve Co-pilot enabled while following a book, The Rust Programming Language (Klabnick and Nichols, 2023). Can’t help but notice that I get code recommendations that are identical to the book.

I assume this is because not only is the book’s code on GitHub but there’s a bunch of people following along using GitHub.

At what point can we say that something is intelligent rather than I’ve seen the same code repeatedly?

Rust

Picked up a book, Programming Rust (2nd Edition) by Jim Blandy, and have been working through it over the holidays (non-stop party here).

Published in late 2021, it’s surprising how much of the code doesn’t work and it isn’t encouraging to spend half an hour searching for solutions to an early worked example. Nothing in the book’s errata.

So if you’re stuck with the early “serving pages to the web” example on page 15, it was caused by a breaking change in actix-web crate‘s chrono dependency. I ended up setting the version before the change.

[package]
name = "actix-gcd"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chrono = { version = "= 0.4.29" }
actix-web = "1.0.8"
serde = { version = "1.0", features = ["derive"] }

Funnily the author wrote “One of Rust’s strengths is the collection of freely available library packages […]” and “[…] by naming the specific versions we tested this code against, we can ensure the code will continue to compile even as new versions of the packages are published.“. True, as long as every dependency behaves itself and it reminded me of this XKCD:

XKCD

Anyway it’s a great read and these things happen. There’s updated version of the completed exercise code on Github.

Rainbows, decorators arguments & threads

Playing with Rainbow Hat I learned a few things about Python as a result I found out what a decorator is, the difference between args and kwargs and threads. I also learned that a lot of guides don’t understand either.

If you can’t explain it simply, you don’t understand it well enough1.

Decorators

Rainbow Hat documentation says, “use touch handlers either by passing in a function by name or using the method as a decorator”.

Learning Python (Lutz, 2013) dedicates a chapter to decorators and sums it up well:

In short, decorators provide a way to insert automatically run code at the end of function and class definition statements—at the end of a def for function decorators, and at the end of a class for class decorators2.

With similar notation to Java’s annotations:

@decorator_function def function(arguments): ...

Python is running one function through another and binding the result to the original function name.

def function(arguments):
    ...
function = decorator_function(function)

For example, Python has a built-in function that returns a static method staticmethod(function). To make example_func static, we put:

@staticmethod
def example_func(arg)
    ...

Which is rebound to:

staticmethod(example_func)(arg)

So now I know what a decorator is in Python, I used it for the buttons. What to use them for though? I figure that they should control speed of LED, sequence, or colour. That’s going to need a thread running as an event handler.

A short digression on arguments

What is a key-worded argument? Lots of documentation refers to *args and **kwargs but had no idea what it was. Arguments passed to functions are read left to right:

function('Dougie', 42)

But we can also use a key-value pair:

function(name='Dougie', age=42)

Apart from improving readability in the function call, default arguments can be assigned in the function definition:

def function(name='Dougie', age=42)

By convention these are referred to as arg and kwarg. That just leaves the *. Python lets you define functions that take any number of arguments, assembling them into a tuple. If you use key-value arguments, it assembles a dictionary.

def function(**kwargs): {...}

Now the clever(er) bit because if you do the same on the function call, Python unpacks the argument into individual arguments (*arg) or key-value pairs (**kwarg).

function(**kwargs)

Back to the main thread

The Rainbow Hat has buttons, so I want to use these to control rainbow speed. This seems suited to a thread running an event handler. The syntax for the thread library (hopefully explaining the digression) is:

thread.start_new_thread (function_name, (*args, **kwargs))

Concurrency in Python is a post in its own right. The CPython interpreter bytecode isn’t fully thread safe. There are different interpretations of what that means so I’ll use the Open University definition:

A class is considered thread-safe if its instances behave under concurrent method calls as if they were called sequentially3).

Python source code is compiled to bytecode which is run in a VM as machine code. To ensure only one thread executes bytecode at once the current thread has to hold a global lock (Global Interpreter Lock (GIL)).

This means multiple processor cores aren’t being used. In this application it doesn’t matter because the interpreter emulates concurrency by routinely switching threads.

  1. Albert Einstein []
  2. Learning Python (Lutz, 2013), pp1034 “Chapter 32: Advanced Class Topics” []
  3. M362 Developing concurrent distributed systems (THE OU, 2008 []