Search code examples
assemblyfunctional-programmingx86-16tasmpure-function

Functional code in assembly? (pure functions)


I'm currently working on chess in TASM 16bit.

I recently learned about pure functions and how they are the coolest thing in the universe, so my question is,

Should go out of my way to make my functions pure and self contained with no side effects?

The thing is that doing this would make the code a bit more complex and require more parameters to be passed to each function.

What do you guys think I should do? Every answer is appreciated <3

===========================================================

Bonus Question: What is functional programming?

The way I understood it is that it's all about writing self-contained, pure functions that have no side effects.

That way the code is super easy to read and manage. Am I wrong?


Solution

  • Should go out of my way to make my functions pure and self contained with no side effects?

    I will answer in some indirect way but specific to "assembly", hope it helps.

    Any function that does not change something outside of arguments and results set is pure. (Rather relaxed definition but good to start.) There is none obstacle against writing pure functions in assembler, provided that definition of pure action is consistent with function calling convention and running environment.

    What I mean here: first, imagine a function that

    • gets two arguments in R0 and R1
    • makes their sum in R2

    this is really pure one, if it does the only action - adding of two values.

    But, imagine that calling convention requires passing arguments on stack. For x86-32, this will compile to something like

    f:
        movl    8(%esp), %eax
        addl    4(%esp), %eax
        ret
    

    this does pure action in sense it doesn't change anything explicitly except returning the value, but there is exception: its calling changes 12 bytes in memory (stack area): 2 arguments and return pointer. This is allowed side effect of function that is pure in another sense.

    But[2], if you change it that it adds first argument to a global variable:

    f:
        movl    4(%esp), %eax
        addl    %eax, sum_a
        addl    8(%esp), %eax
        ret
    

    this will not be pure in traditional sense: you have added a side effect.

    But[3], if some side effect is explictly declared as not affecting function purity - for example, this adding to sum_a is implemented for debugging and does not change the target functionality of the program - the function can again be considered as pure.

    So, "purity" is not an absolute concept. It gets real sense only when declared what real world effects are discarding its purity and what ones are not. Usually, the following effects are keeping purity:

    1. Execution time.
    2. Execution system implementation (hardware) effects, as RAM access, cache filling (and draining of previous cache state).
    3. Operation system (and other software) effects, as task switching, paging in/out.
    4. Application debugging and monitoring (while goal results are not changed).

    What side effects are allowed is up to you. The main thing you would keep in mind is that

    • Some effects are unavoidable by design (as cache change).
    • Despite this, you should minimize all other side effects, just because they are easy to forget and so will confuse you while writing. Sometimes it needs hours of debugging to catch a Total Recall for a tiny fact of side effect of a function you wrote a few years ago. And this is generally language-independent: assembler or Java, or even LISP, your functions have important side effects, or they don't.

    Bonus Question: What is functional programming?

    The way I understood it is that it's all about writing self-contained, pure functions that have no side effects.

    In general, it is not. But this is offtopic here (I mean both in this topic and this forum, youʼd better go to SE one, unless usual textbooks, wikipedia and googling is not enough.) I would better describe it as programming when you specify implementation in sense of elementary actions as functions and their argument-result relation, without specifying of operation order. But I wonʼt insist on it.