Category: Programming

  • Better Enumerations in Python

    When dealing with more than one language, we look for similar approaches across languages. In Rust, there’s a keyword called enum to define and use enumerations. It’s easy to use, let’s look at this example from the official document:

    enum IpAddrKind {
        V4,
        V6,
    }
    
    struct IpAddr {
        kind: IpAddrKind,
        address: String,
    }
    
    let home = IpAddr {
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };
    
    let loopback = IpAddr {
        kind: IpAddrKind::V6,
        address: String::from("::1"),
    };
    Rust

    If we want to write this code in Python, we can define two classes and two variables simply. Let’s start with a simple alternative first:

    class IpAddrKind:
        V4 = 1
        V6 = 2
    
    
    class IpAddr:
        def __init__(self, kind: IpAddrKind, address: str) -> None:
            self.kind = kind
            self.address = address
    
    
    home = IpAddr(kind=IpAddrKind.V4, address="127.0.0.1")
    loopback = IpAddr(kind=IpAddrKind.V6, address="::1")
    Python

    It’s absolutely not the same thing with the Rust one but it can help you to meet your expectations about keeping the parameter consistencies between the IP address objects and you can group or filter the objects when you need it. I could also use dataclass for IpAddr, it came with the version 3.7:

    import dataclasses
    
    
    @dataclasses.dataclass(frozen=True)
    class IpAddrKind:
        V4 = 1
        V6 = 2
    
    
    @dataclasses.dataclass
    class IpAddr:
        kind: IpAddrKind
        address: str
    Python

    But as you know, they’re not enumerated indeed. Let’s discuss why we need a specific keyword or a language feature for enumerations:

    • The enumeration class should only do one thing. Currently it’s just a class, there’s nothing to explain that it’s an enumerator. Even if we set the values manually, we don’t know which are enumerated types. There’s no relationship between the members of the class.
    • When I read the code, I should quickly understand that it’s an enum with unique constants, so I can use these constants to define types of some objects and compare them. In other words, if I have an enum type for colors and I want check the type of a color, it should be a Color for example. Not integer, not string, I expect a custom enum type.
    • All enumerations have common basic functionalities. Members should be immutable, iterable, accessible by value and by name, and it should also be possible to get members as a list. I should not have to create a base class to add them to.

    Actually there’s an Enum type since version 3.4. But the feeling of using enum in Python is like using an external package like dateutil. You’re importing Enum class, and inheriting it on your enum type. Let me show:

    from enum import Enum
    import dataclasses
    
    
    class IpAddrKind(Enum):
        V4 = 1
        V6 = 2
    
    
    @dataclasses.dataclass
    class IpAddr:
        kind: IpAddrKind
        address: str
    Python

    I think it’s still better than using dataclass, because it gives some expectations of what we want, there’s a specific enum type, there are value and name attributes for each member, the values of members are immutable, if you try to redefine it, it will give an AttributeError, etc. All is fine.

    >>> home = IpAddr(kind=IpAddrKind.V4, address="127.0.0.1")
    
    # type type is enum.
    >>> home.kind
    <IpAddrKind.V4: 1>
    
    >>> type(home.kind)
    <enum 'IpAddrKind'>
    
    # there's a value and the type of value is integer.
    # the best practice is not using the value directly, because 1 is meaningless.
    >>> home.kind.value
    1
    
    >>> type(home.kind.value)
    <class 'int'>
    
    # it's also possible to access to name of member.
    # sometimes we need it if we're getting a data from an external service and want to remap the values, it depends.
    >>> home.kind.name
    'V4'
    Python (REPL)

    Technically, we have achieved what we want, but let’s think about what we can do about usability. Do I have to assign a numerical value to the members? Partially yes, it’s not possible to define just member names without values, as in Rust. But there are some options:

    from enum import auto, Enum
    
    
    # option 1
    class IpAddrKind(Enum):
        V4, V6 = range(1, 3)
    
    
    # option 2: functional way
    IpAddrKind = Enum("IpAddrKind", "V4 V6")
    
    
    # option 3: just assign the first value
    class IpAddrKind(Enum):
        V4 = 1
        V6 = auto()  # or you can leave it as `None`
    Python

    I’m not sure which option is better, I guess the first one doesn’t improve readability, option 2 is better than 1. Also I would prefer to write the values manually instead of auto() in option 3. But yeah, it depends again. It’s also possible to set the value of a member by its name. I haven’t written all the features of the enum module in this article, but it’s also possible to support bitwise operators using Flag instead of Enum, to determine the member values str instead of int using StrEnum, or to force the value types to be numbers using IntEnum, etc. See the official documentation for more information.


    Before I conclude my article, I would like to add one last thing about enum use in Rust. I remember that it’s possible to use algebraic data types in Rust, but you probably won’t need it in Python. Because Rust is not a dynamically typed language and it forces you to work with types every time. Actually there’s a better example in Kobzol’s blog (see the section Algebraic data types) but let’s keep in the same sample here:

    enum IpAddr {
        V4(String),
        V6(String),
    }
    
    let home = IpAddr::V4(String::from("127.0.0.1"));
    let loopback = IpAddr::V6(String::from("::1"));
    Rust

    How could we write it in Python? Should we use Enum or dataclass, or just a class?

  • Syntax Errors in Logical Operators

    Python favours letters and meaningful keywords for the logical operators, and all of them return a value depending on the conditions:

    1. not: The opposite of a condition, the reverse of the logical state of its operand. If the condition is True, it returns False, or vice versa.
    2. and: It needs to compare two operands, It returns True if both operands are True.
    3. or: It’s similar to and, but it returns True if at least one of the operands is True.

    The operands do not have to be boolean, Python will return the condition itself through the comparison logic to keep the code writing simple. Now let’s look at this output to see the difference between not and the other operators, focusing on the position of the hats (^):

    >>> not
      File "<stdin>", line 1
        not
           ^
    SyntaxError: invalid syntax
    
    >>> and
      File "<stdin>", line 1
        and
        ^^^
    SyntaxError: invalid syntax
    
    >>> or
      File "<stdin>", line 1
        or
        ^^
    SyntaxError: invalid syntax
    
    >>> or 0
      File "<stdin>", line 1
        or 0
        ^^^
    SyntaxError: invalid syntax

    The syntax error starts in the first character of and and or, but the end of not, after t. Is this normal? Absolutely, yes. As I said before, we don’t need a comparison for using not, but we can not say the same thing for the others, the keyword should be between in two conditions. Now let’s try to give a condition for not to solve the syntax error:

    >>> bool(1)
    True
    
    >>> not 1
    False
    
    >>> bool(0)
    False
    
    >>> not 0
    True

    1 is a truthy value, it’s something like YES or ON in programming logic, but it returned False when we added not keyword before 1. I am aware that I am explaining very simple and boring things but please be patient. Let’s make the syntax a bit confusing:

    >>> not(1)
    False
    
    >>> not(0)
    True
    
    >>> not()
    True
    
    >>> bool()
    False

    Wait.. Is there also a built-in function for not? No, it’s definitely not a function. Honestly, I would expect a syntax error because of the missing space between the not keyword and the parentheses, but the formatter tools will probably add it automatically anyway. So, you can consider using parentheses to group the conditions, that’s all. And, when you ran not with an empty parentheses, it will return always True because empty tuples, lists, dictionaries are falsy values:

    >>> not{}
    True
    
    >>> not[]
    True
    
    >>> not      ()
    True

    The best thing to do is to use a code formatter and read the code that way. This is not always possible, so we have to get our eyes used to strange syntax. Let me end the article with a more ugly syntax (but meaningful):

    if not(False or False) and(True):
        print("This will print")

    Will it print the expected output, or raise a syntax error?

  • The Future of Mobility

    I wanted to repost the part about the mobility of an article I wrote in Turkish for 2024 Trends in the Software World on my blog. The topic of mobility is still in my focus and I am still following the developments closely.


    … Now I will end my article with a topic I haven’t mentioned before: Electric vehicles, or in general terms, automobiles. We have entered a strange period that will closely concern the software industry. It is like the Quartz revolution in watches (or the Quartz crisis if we look at it from the Swiss perspective).

    To put it simply, a Japanese wristwatch company called Seiko produced the first commercially mass-produced quartz wristwatch in the world, the Astron model. In appearance, there were still hour and minute hands on the dial, but instead of mechanical parts, it was powered by an electrical technology. These watches could show the time accurately for longer periods of time than mechanical watches, were lighter, and as production became easier and costs decreased, they took over the watch market. Mechanical watches currently have a certain user base, and there are very valuable companies that produce these watches.

    Now we see something similar in the automobile market. An American company called Tesla brought electric vehicles into our lives, then Chinese battery and electric vehicle companies sprang up like hotcakes, and European automobile manufacturers fell into the same situation as Swiss watch companies. These electric vehicles have very powerful computer hardware and operating systems, and I think this will be a new field of work for software developers.

    Cars with internal combustion engines will continue to exist, just like mechanical watches; however, the mobility experience that electric vehicles provide to the user makes us think that we need to look at those vehicles with a different perspective. I just imagine, there is a screen in the middle, being able to put it in camping mode and sleep in the car all night without getting cold, being able to play games, listen to music, have a living space where you can isolate yourself in a capsule, being able to connect to the internet and download applications, being able to do things in the car that you can do on your phone, being able to control the car from your phone or computer, being able to remotely monitor the vehicle’s data, being able to access its cameras… I could list more, there are many possibilities and do you know who is needed to do these? Yes, you guessed it.

  • Configuration Updates With Emacs 29

    As I mentioned in my last post, I started using VSCode to see what I’m missing and I thought that it’s a good time to take all the risks and break my Emacs configuration. In the last changes, I tried to use the built-in alternatives of the packages like eglot instead of lsp-mode. Now I’ve made the decision to update Emacs to version 29.

    When I first switched to Emacs 28, all my performance problems were solved thanks to native compilation support. Most of these problems were caused by LSP1 and it was very annoying to wait even half a second to see syntax errors in the code. Now I don’t close Emacs on the server for months. This was the most significant change to Emacs 28 that I can’t forget.

    Now, if you ask what the equivalent important update is on Emacs 29, I guess I can claim that Emacs has become quite useful even if you don’t install any extensions. Many extensions I used are now included in the project, for example:

    • Modus-Vivendi and Modus-Operandi, the themes I have been using for years and cannot give up, now come in.
    • The package configuration tool use-package is now included.
    • The internal LSP service eglot is now available. I’ve previously used the lsp-mode extension.
    • For tree-sitter support, nothing needs to be installed any longer.

    Furthermore, TRAMP2, which functions similarly to VSCode’s remote development extensions, has started to support Docker and Kubernetes; however, I have not yet verified whether LSP can be used in a remote development environment. I prefer to use MOSH3 to connect to the server and execute Emacs remotely, unless this occurs.

    As many extensions were included, I also reviewed the other extensions I used. Although it is possible to use Emacs without any installed extensions, it is very difficult for me to give up some extensions. For instance, magit is far superior to many competitors, both as an Emacs and a git client.

    Another extension that I can’t give up is doom-modeline. The default mode-line view in Emacs is also quite ineffective. It wastes space, uses the right half of the line very inefficiently, and shows minor modes needlessly. I began utilizing doom-modeline to address all of these issues. You can see the screenshot to see how it looks:

    With Emacs 29, I suppose the major modification I made was to cease using popups for text completion. I’m not sure if it’s a good idea yet, but I’ll keep trying. I use all of Emacs’ capabilities that make use of minibuffers considerably more effectively by using the following extensions:

    • consult: an extension for minibuffer completion.
    • vertico: a minibuffer completion UI. It’s necessary for consult.
    • orderless: completion style with various algorithms to find more search results.
    • marginalia: an extension to see more information about the search results.

    When I started using minibuffer instead of popup for completion, there was a lot of space left for a second text completion. so I thought why not use copilot or codium. Look at the screenshot to see how it works:

    I didn’t turn on a lot of UI components, like line numbers, tabs, fringe, and scroll bars, so it’s likely that my configuration isn’t optimal for a graphical user interface. And to be honest, I didn’t need it; perhaps I’ll keep the UI in zen mode and continue using Emacs in my preferred terminal program, WeztTerm. But for the time being, I intend to continue working with VSCode. You may find a new version of Emacs with my setup in my emacs.d repository if you want to try it out.


    1. LSP: Language Server Protocol ↩︎
    2. TRAMP: Transparent Remote Access, Multiple Protocol ↩︎
    3. MOSH: Mobile Shell ↩︎
  • Status Update on Emacs

    I’ve used Emacs for years, and it’s not easy to get rid of this archaic (what?) editor. Although it helped me do my job better, my setup was not as stable as in the editor. When I started working as a web developer, I was installing all the project requirements on the local machine, even though I was not using virtual environments. Emacs was good enough to make development possible.

    Then, I started using tools like vagrant, docker, and virtual environments that made it easy to install the project but difficult to use Emacs because I needed to configure the editor to find the right Python interpreter, Node version, etc. Having the language server protocols (LSP) was a great help, but I still had to create a virtual environment for each project.

    Then I switched to remote development; I had a remote server to access the same development environment from all my devices. I was using a good terminal emulator like WezTerm, connecting to the server using MOSH or Eternal Terminal, and running Emacs on the server remotely. This has never been as comfortable as working locally.

    In each case where my setup has changed, I have updated Emacs and reconfigured it for the new environment. If you take a look at my Emacs configuration, you will see that I’m using vanilla Emacs with the minimum configuration, and I try to use built-in packages as much as possible. But now I’m at a new crossroads because I started using AI tools actively and am getting bored waiting for the tools to support my editor. I’m looking at the GitHub Copilot, and even they don’t have a plan to support Emacs officially. You can say that it’s a tactic to force them to use their own editors or that they don’t have time to support all the editors. Maybe it’s better to help the community take initiative for preparing the extension. But anyway, that’s not fair or helpful for maintaining the diversity of the editors.

    Probably it’s not easy to change my habits quickly, but I plan to use VSCode for a while and see what I’m missing. I know that VSCode has good remote development tools and official GitHub Copilot support. During this period, I will update Emacs to have the same features as VSCode and try to use it again.

    For now, I want to compare the two editors for the extensions I’m using in Emacs. These extensions are mostly not needed on VSCode because they are built-in features:

    • company, company-prescient: autocomplete extension.
    • ctrlf: better search and replace.
    • deadgrep: ripgrep integration for Emacs. I’m using the built-in search and find commands on VSCode.
    • diff-hl: shows git diff in the fringe.
    • eglot: LSP client.
    • find-file-in-project: Helpful for finding a file in a project.
    • multiple-cursors: Another extension for editing multiple lines at once.
    • expand-region: Not easy to do this on VSCode (CTRL+CMD+SHIFT+Left what the hell?) but yes it’s a built-in feature.
    • magit: Git app for Emacs. I don’t think that I can find an equivalent in any editor. Don’t suggest me GitLens, please.
    • minions: Hides minor modes on Emacs mode line. Not necessary on VSCode.
    • modus-themes: My favorite theme for Emacs. I’m using the GitHub theme on VSCode.
    • puni: Structured editing tool for Emacs. Not sure if I can find an equivalent on VSCode.
    • vertico, vertico-prescient: Similar to CTRL|CMD+SHIFT+P or CTRL|CMD+P on VSCode.
    • tree-sitter, tree-sitter-langs: Not sure if VSCode needs this extension, but it’s a great synax parsing library for Emacs.
    • unfill: For unfilling paragraphs with a shortcut.

    My Emacs configuration is available on GitHub.

  • Rust Essentials

    Mostly I do not prefer to read the books written for teaching a programming language. Because a good language community already places the importance on their websites to promote the programming language beautifully as in Python and Rust. In these websites, you can find documentation, tutorials, even a free ebook that allows you to read from the website directly, and they’re mostly up-to-date.

    As you know, Rust is not an easy-to-learn programming language. So I frequently look at the official documentation of Rust, and sometimes I choose a random topic and read them again and again. Before starting to read this book, I took a look at the pages and saw some details that I still missed on the Rust documentation. Then I read the entire book thoroughly.

    My ebook was the first edition, and there were missing topics like async programming. The author published the second edition in 2017, and it seems he will need to prepare a new version to include the last changes in the language. That’s why I do not prefer to learn a programming language from a book. Rust is improving rapidly, so you need to follow the official documentation always.

    Another issue that I feel most lacking right now is macros. I know that they’re similar to Lisp macros, but I still couldn’t have a chance to try it in my pet projects yet. The book shows me an example of usage, but I don’t understand how and where to use it. I wish to see the samples from a specific project or all samples come from the same project.

    Finally, I share a table about the pointer types in Rust, when I started learning Rust, it was pretty intimidating. Now it seems a little more meaningful.

    TypeNameDescription
    &TReferenceOne or more references to read T
    &mut TMutable referenceSingle reference to read and write T
    Box<T>BoxHeap-allocated T with a single owner that may read and write T
    Rc<T>Rc pointerHeap-allocated T with many readers
    Arc<T>Arc pointerLike Rc, but enables safe mutable sharing accross threads
    *const TRaw pointerUnsafe read access to T
    *mut TMutable raw pointerUnsafe read and write access to T
  • Being a Polyglot Developer

    My objective for the year 2019 was joining one more programming language community after Python and Lisp. I followed .NET Core in my first six months and did some projects using C# and F#. But then, I decided that learning Rust is a better idea. Some of the Python and Django developers I’ve followed have had a significant impact on my decision.

    Python is a programming language that easy to learn, it has a significant and active community, and I believe that it will keep its popularity for a longer time. Therefore, when choosing another programming language, I make sure that it has different features and priorities. I’m not sure, but I think that that’s why I couldn’t continue with .NET community. I already produce microservices, REST API, gRPC server, or even classifying things using machine learning libraries in Python. But I would not have preferred Python if I want to make a mobile application, that would not make sense. Or I would use Rust for embedded or blockchain projects; I would code data or text mining tools in Lisp, for example.

    In the past, being a full-stack developer was an extremely wanted job position. Now I don’t know how it is, but I suggest you stay away and become a polyglot developer instead.

  • My First Wrong After The Vacation

    At the end of my three-week vacation, I was asked for a seemingly easy task. We were going to release the new version of the project we developed:

    • Is today is the last working of the week? No.
    • Is there any problem with the unit tests? No.
    • Are all changes confirmed by the product manager, in the staging server? Yes.

    I always note everything, and so I write this article to remind this experience. My other habit is to define dosh sub-commands to access frequently used commands in my whole projects. It doesn’t matter if the project is written in .NET Core or used Django;

    • I know that the project will start in my development environment with dosh start,
    • I know that the project will build with dosh build,
    • I know that dosh deploy command will be running if I push my commits to some specific git branches. All these things are common sub-commands in my projects.

    So what was not a standard?

    I manage everything in a project except the server maintenance. Today the site was offline about an hour because of the communication failure. Sometimes there are small but critical upgrades on the servers, and one of them broke SSL module of the project’s psycopg2 dependency. I had only these logs:

    DAMN ! worker 1 (pid: 28018) died :( trying respawn ...
    Respawned uWSGI worker 1 (new pid: 28021)
    !!! uWSGI process 27988 got Segmentation Fault !!!
    *** backtrace of 27988 ***
    /usr/bin/uwsgi-core(uwsgi_backtrace+0x2a) [0x55a0ad5c498a]
    /usr/bin/uwsgi-core(uwsgi_segfault+0x23) [0x55a0ad5c4d73]
    /lib/x86_64-linux-gnu/libc.so.6(+0x3ef20) [0x7f4811ecaf20]
    /project/venv/lib/python3.6/site-packages/psycopg2/.libs/./libssl-8bb9b3dd.so.1.0.2o(ssl3_cleanup_key_block+0xb) [0x7f480a747cbb]
    /project/venv/lib/python3.6/site-packages/psycopg2/.libs/./libssl-8bb9b3dd.so.1.0.2o(ssl3_clear+0x16) [0x7f480a7455b6]
    /project/venv/lib/python3.6/site-packages/psycopg2/.libs/./libssl-8bb9b3dd.so.1.0.2o(tls1_clear+0x9) [0x7f480a751229]
    /usr/lib/x86_64-linux-gnu/libssl.so.1.1(SSL_new+0x3f2) [0x7f4812b429d2]
    /project/venv/lib/python3.6/site-packages/psycopg2/.libs/libpq-239f9ac8.so.5.10(+0x23399) [0x7f480a9dc399]
    

    You may know Segmentation Fault if you coded in C or if you worked with a package manager. Some included libraries that are coming with psycopg2 binary package are linked to the old version of libssl, so the last server update broke the dependencies1.

    lib/python3.6/site-packages/psycopg2/.libs/libssl-8bb9b3dd.so.1.0.2o   # from 1.0
    lib/python3.6/site-packages/psycopg2/.libs/libssl-7a80b951.so.1.1.1b   # to 1.1
    

    In some projects, it’s not possible to solve the problems as we wanted because of some regulations and source limits. I could find prevention for that case, but somehow, I forgot to check the updates in the source code and server packages and tried to make the deployment. And the worst thing, I didn’t realise the problem until someone warned me.

    So, I added one more rule for myself to make a deployment:

    • Is today the first day after the vacation? Yes (so, don’t touch it.).

    1. “Don’t break the dependencies”, I missed contributing a Linux distro like Pardus. ↩︎
  • Configure Windows for Development

    Environment Variables

    I still use some development tools that are used by most Linux users and these tools need some environment variables like LC_ALLHOME, etc. When I have a new PC with Windows 10, I start to use with defining these variables. Take a look at this post for more detail.

    PowerShell Core

    It’s possible to use BASH on Windows indeed, but I think PowerShell Core is a good alternative. Git integration is working well, defining aliases and functions is easy:

    # Extensions
    Import-Module posh-git
    Import-Module PSReadLine
    
    # DOSH settings
    $env:ENV = "DEV"
    Set-Alias dosh .\do.ps1
    
    # Readline settings
    Set-PSReadLineOption -EditMode Emacs
    
    # Git prompt settings
    $GitPromptSettings.DefaultPromptPath.ForegroundColor = 0xFFA500
    $GitPromptSettings.DefaultPromptWriteStatusFirst = $true
    $GitPromptSettings.DefaultPromptBeforeSuffix.Text = '`n$([DateTime]::now.ToString("MM-dd HH:mm:ss"))'
    $GitPromptSettings.DefaultPromptBeforeSuffix.ForegroundColor = 0x808080
    $GitPromptSettings.DefaultPromptSuffix = ' $((Get-History -Count 1).id + 1)$(" >" * ($nestedPromptLevel + 1)) '
    
    # Helper commands
    function which ($command) {
        Get-Command $command | Select-Object -ExpandProperty Definition
    }
    
    function touch ($filename) {
        $null > $filename
    }

    Readline is a familiar extension for BASH users. If you want to use Emacs key bindings in PowerShell, I suggest you add Readline to the dependencies list.

    What if we want to use a Linux command-line app? Like Nano? Indeed, it’s possible to use it as a default git-commit editor but, let’s consider it’s a program that only available in Linux. I use WSL for that case. Just install Ubuntu or another Linux distro with WSL, open PowerShell and run this command:

    > wsl -e nano README.md

    So you can reach all Ubuntu programs using this magic command. There’s only a little problem here, you have to keep your configuration files (like .nanorc) in your WSL instead of in your local. You can find my configuration repo here.

    Git-apply EOL Problem

    If you don’t ignore space changes in your patch command, you will get an error because the whitespaces in Linux environments. To solve this problem, use git-apply with these parameters:

    $ git apply --ignore-space-change --ignore-whitespace a.diff
  • String quotes in PEP8

    I use PEP8 in my Python projects except for a few rules.

    I think ‘single-quote’ and “double-quote” characters should NOT be the same. It could be better if these two characters had different counterparts in the Python language parser system. So we could use one of them for the template-strings (or f-strings). It doesn’t provide readability, causes inconsistency instead. Until now, I used string-quotes for the variable definitions and double-quotes for the visible texts. But now, I plan to use always double-quote as in many other programming languages.