Function Overloading or Pattern Matching of functions in Ecma

# bishwendu kundu (6 years ago)

Hello All,

I have been a great fan of the evolution of JavaScript in the recent past. The language is steadily closing the gap to ideal functional paradigm. One of the things that I have liked the most about languages like Erlang/Elixir/Haskell is their ability to define functions with same name and different airty. The decision of invoking the correct function-argument pattern is dependent on the invocation of the function. Implicit pattern matching in aforementioned languages helps avoid costly cognitive loads introduced by explicit if/else based pattern of logic flow branching.

The greatest power of the pattern matching which amazed me was, dropping the whole of looping construct, altogether. Elixir/Erlang have no LOOPS. Stack based recursive calls combined with JavaScript's closures suddenly strikes me as a very powerful programming model that not only increases readability of code but also promotes immutability of the data structures in use. The loops would continue to exist but more modern codes can be written leveraging the recursive model of JavaScript.

With de-structuring of arrays & objects already in place in JavaScript, pattern-matching of functions can fit right in perfectly, thereby taking JavaScript another step closer to ideal functional programming model.

Looking forward to your response.

Thanks & , Bishwendu.

# kai zhu (6 years ago)

javascript is first-and-foremost a tool designed for web-product-development, a growing field that has eclipsed low-level general-purpose programming (where jobs are harder and harder to find) in the IT industry.

you need to give compelling reasons (for such significant language-change) why i, a web-developer would benefit from from having overloaded-functions in my (mostly expendable-code) web-projects, as opposed to creating confusion and maintennance-headaches, when i typically have to rewrite code multiple-times during the web-integration process.

kai zhu kaizhu256 at gmail.com

# Isiah Meadows (6 years ago)

In general, you can do this via arguments.length, and if/once the pattern matching proposal 1 hits stage 4, you could do this to emulate it very closely:

function foo(...args) {
    case (args) {
        when [] -> { /* zero args*/ },
        when [x] -> { /* one arg */ },
        // and so on...
    }
}

In general, that proposal would most interest you.

# bishwendu kundu (5 years ago)

Zhu,

I agree with you the new proposition should be of value to a web developer in daily work. If we observe the pattern it more closely resembles a more declarative form of solution implementation which is easy to code and understand. For example lets consider below piece of code:

function sum_list(input, result){
    if(!input.length)
        return result;
    [head, ...input] = input;
    return sum_list(input, result + head);
}

Now the same code in the new proposal form

function sum_list([head, ...tail], result){
    result = result + head;
    return sum_list(tail, result);
}

function sum_list([], result){
    return result;
}

This declarative model of coding also forces an immutable form of state management allowing for removing a family of bugs.

Thanks & , Bishwendu.

# Isiah Meadows (5 years ago)

As mentioned previously, the pattern matching proposal does a lot to help here:

function sum_list(input, result = 0) {
    case (input) {
        when [head, ...tail] -> return sum_list(input, result + head),
        when _ -> return result,
    };
}

Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# Matthew Robb (5 years ago)

Perhaps the following form could eventually make sense for pattern matching in function declarations:

function sum_list(input, result = 0) case (input) {
    when [head, ...tail] -> {
        return sum_list(input, result + head);
    },
    when _ -> { return result; }
}
  • Matthew Robb
# Isiah Meadows (5 years ago)

You might want to check out the proposal's repo and make the suggestion there (it's been considered already IIRC, and I believe it was already noted in the repo as a possible future extension): tc39/proposal

# Cyril Auburtin (5 years ago)
# kai zhu (5 years ago)

if it helps, you can already "pattern-match" using string-concat like this full-working-demo [1] derived from a closed-source real-world example.

<style>
*,
*:after,
*:before {
    box-sizing: border-box;
}
body { background: #eee; display: flex; flex-flow: column; font-family: Arial, Helvetica, sans-serif; margin: 0; padding: 10px;
}
body > div { background: #fff; border: 1px solid #ddd; margin-top: 10px; padding: 10px; }

body > div:first-child { margin-top: 0; }
#panelBody1 { border: 0; display: flex; flex: 1; padding: 0; }
#panelBody1 > div { border: 1px solid #ddd; padding: 10px; }
#panelBody1 > #borderResize1 { background: #fbb; border: 0; cursor: ew-resize; padding: 5px; }
</style>

<div id="header1">
    #header1 - drag
    <span style="background: #fbb; padding: 2px;">red-bar</span>
    between #panelSidebar1 and #panelSidebar2 to resize
</div>
<div id="panelBody1">
    <div id="panelSidebar1">#panelSidebar1 (width: <span>0</span>px)</div>
    <div id="borderResize1"></div>
    <div id="panelContent1" style="flex: 1;">#panelContent1 (width: <span>0</span>px)</div>
</div>
<div id="footer1">#footer1</div>

<script>
/* jslint browser */
(function () {
    "use strict";
    var local;
    local = {};

    // init event-handling - resize panel
    local.domOnEventDrag = function (event) {
    /*
     * this function will handle <event> to drag-and-drop
     */
        // "pattern-match" with string-concat
        switch (Boolean(local.domOnEventDragEvent) + "." + event.type) {
        case "false.mousedown":
            local.domOnEventDragEvent = event;
            return;
        case "true.mouseenter":
        case "true.mouseup":
            local.domOnEventDragEvent = null;
            return;
        case "true.mousemove":
            switch (local.domOnEventDragEvent.target.id) {
            case "borderResize1":
                event.preventDefault();
                event.stopPropagation();
                document.querySelector(
                    "#panelContent1"
                ).style.width = "0";
                document.querySelector(
                    "#panelSidebar1"
                ).style.width = event.x + "px";
                local.domOnEventWindowResize();
                // display resize-info
                document.querySelectorAll(
                    "#panelContent1 span, #panelSidebar1 span"
                ).forEach(function (elem) {
                    elem.textContent = elem.parentElement.offsetWidth;
                });
                return;
            }
            return;
        }
    };
    Array.from(document.querySelectorAll(
        "#borderResize1"
    )).forEach(function (elem) {
        elem.addEventListener("mousedown", local.domOnEventDrag);
    });
    document.addEventListener("mouseenter", local.domOnEventDrag);
    document.body.addEventListener("mousemove", local.domOnEventDrag);
    document.body.addEventListener("mouseup", local.domOnEventDrag);

    // init event-handling - resize window
    local.domOnEventWindowResize = function () {
    /*
     * this function will handle <event> to resize window
     */
        // resize body
        document.body.style.height = window.innerHeight + "px";
        // resize - #panelBody1 > div
        document.querySelectorAll(
            "#panelBody1 > div"
        ).forEach(function (elem) {
            elem.height = elem.parentElement.clienthHeight + "px";
        });
        // display resize-info
        document.querySelectorAll(
            "#panelContent1 span, #panelSidebar1 span"
        ).forEach(function (elem) {
            elem.textContent = elem.parentElement.offsetWidth;
        });
    };
    window.addEventListener("resize", local.domOnEventWindowResize);
    local.domOnEventWindowResize();
}());
</script>

[1] using pattern-match to resize html-panels codepen.io/kaizhu256/pen/rRBLLP

# Jordan Harband (5 years ago)

That only allows you to switch on things that have a string representation; object identity (more complex than the basic form that switch currently allows) is a particularly common use case that the pattern matching proposal addresses.