The Intellectual Wilderness There is nothing more useless than doing efficiently that which should not be done at all.

2020.09.24 11:02

Erlang: Dispatching Closures (aka: why we don’t do OOP)

Filed under: Computing — Tags: , , , , , — zxq9 @ 11:02

Oh my! It’s like “Creating nouns in the kingdom of verbs“!
(The link above is to a great post from Steve Yegge — read it and come back if you aren’t already familiar with it.)

A video talk-through of the code below and a bit of discussion

I wrote a funny little module today to demonstrate to a friend why FP folks sometimes refer to OOP objects as “dispatching closures” and occasionally make quips like “objects are a poor man’s closures”. I thought it would be fun to share it and also wanted a reference page to which I can refer people who have questions because this comes up every so often when a new OOP programmer starts pondering the nature of the universe after reading some introductory FP material.

Quite a lot of extra functionality could be added to this, such as distinguishing between functions that update the state of Self and functions that don’t to alleviate the annoyance of having to ignore the NewSelf return element of any “methods” beyond the pure built-in ‘get’, but we can leave that for another day as I really don’t expect anyone in their right mind would use the module below in real world code — it just introduces complexity, mental overhead, and potential weirdness if you pass an object between two different processes (send it to a process on another node and boom!), and in Erlang funs really shouldn’t be all that long-lived anyway.

In the below code a syntactic rewrite is needed to understand how to call the methods:

Pseudo PythonOOPsy Pseudo Erlang
class MyClass:
# stuff
MyClass = class(Data, Methods)
my_object.data_elementMyObject({get, DataElement})
my_object.data_element = valueMyObject({set, DataElement, Value})
my_object.do_something()MyObject({do, Something})
my_object.update(stuff).do_something(){ok, NextObject} = MyObject({do, update, Stuff}),
NextObject({do, something})

Here is the definition bit of the code, there is also a slightly more extensive and commented snippet on GitLab that has an additional demo/0 function that demonstrates one way dispatching closures can be called, manipulated, and extended through inheritance:

-module(oop).
-author("Craig Everett <zxq9@zxq9.com>").
-export([class/2, class/3, demo/0]).


-record(s,
        {data    = #{},
         methods = #{}}).


class(Defaults, Methods) ->
    fun
        (data) ->
            maps:keys(Defaults);
        (methods) ->
            maps:keys(Methods);
        (Data) when is_map(Data) ->
            State = #s{data = maps:merge(Defaults, Data), methods = Methods},
            object(State);
        ({subclass, NewDefaults, NewMethods}) ->
            class(maps:merge(Defaults, NewDefaults), maps:merge(Methods, NewMethods))
    end.


class(Inherits, Defaults, Methods) ->
    Inherits({subclass, Defaults, Methods}).


object(State = #s{data = Data, methods = Methods}) ->
    fun
        ({get, Label}) ->
            maps:get(Label, Data);
        ({set, Label, Value}) ->
            NewData = maps:put(Label, Value, Data),
            object(State#s{data = NewData});
        ({add, Label, Method}) ->
            NewMethods = maps:put(Label, Method, Methods),
            object(State#s{methods = NewMethods});
        ({do, Label}) ->
            F = maps:get(Label, Methods),
            F(object(State));
        ({do, Label, Args}) ->
            F = maps:get(Label, Methods),
            F(object(State), Args);
        (data) ->
            maps:keys(Data);
        (methods) ->
            maps:keys(Methods)
    end.

While this is an interesting construct, it is absolutely insane that anyone thought it was so utterly and all-encompassingly important that an entire new syntax should be developed just to hide the mechanics of it, and further, than entire languages should be created that enforce that this is the One True Way and impose it on the programmer. It’s cool, but not that cool.

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment

Powered by WordPress