The challenge I've seen, faced, and had team members face time and time again, is that pattern matching only goes so far. The limitations are:

1. Maps are slower (significantly enough to avoid IMHO), but do give the flexibility desired (1.79x slower, which could compound if in the wrong place) 2. Keyword lists must be matched in exact order, and flexibility with them is limited

It's the frequent edge cases that end up causing problems: they end up being a little clunky in practical use.

-Brandon


On 10/27/22 2:30 PM, José Valim wrote:
[...]
And Elixir has opted into pattern matching for this particular feature set.

On Thu, Oct 27, 2022 at 10:19 PM Felipe Stival <v0id...@gmail.com> wrote:

    This library implements this functionality, albeit on a peculiar
    way: https://hex.pm/packages/defnamed. It suffers from the issues
    explained by Marc-André.

    On Thu, Oct 27, 2022, 21:05 Marc-André Lafortune
    <marc-an...@marc-andre.ca> wrote:

        If I understand your proposal, calling `do_a_thing(old: "older
        value", new: "newer value")` would need to know the signature
        of `do_a_thing` at *compile-time*. Among other things, two
        modules wouldn't be able to call each other's functions this
        way, as one couldn't be compiled without the other... Also
        there would be no way to know if `do_a_thing` uses named
        function arguments, so any function call using keywords would
        introduce a compile-time dependency.

        That being said, I miss Ruby's named arguments, and wish the
        default syntax for Elixir was building maps instead of
        keywords, but that can't change. Having a nice syntax for map
        arguments with defaults could be interesting though.
        On Thursday, 27 October 2022 at 09:59:48 UTC-4 Brandon
        Gillespie wrote:

            Ordering of arguments is an age-old programming challenge
            (creating many bugs). Type checking and pattern matching
            help, but are also limited. We currently have two indirect
            ways of having named arguments, but both have challenges:

             1. Keyword lists — pattern matching must match the exact
                order of the listed arguments, which doesn't help the
                issue here which is ordering, let alone optional
                arguments, leading to extraneous in-function calls to
                Keyword.get.
             2. Maps — while this supports optional arguments, it has
                the overhead of creating and destructing a map for a
                simple function call. Benchmarking this vs
                ordered arguments shows it's 1.79x slower than simply
                using ordered arguments. That's an overhead that
                builds up on every function (I didn't benchmark
                keyword lists, sorry).
             3. Existing syntax to handle named arguments as keywords
                should still be handled, for backwards compatibility,
                making it harder to do this sort of thing.

            To preface the proposal, I realize this may simply not be
            possible with the limitations of the parser/compiler that
            we have today.

            Proposal:

            Add a compile-time named/pinned argument syntax in the
            function declaration head, which allows the naming of
            arguments as if it were a keyword list, but instead, the
            keys are mapped to the variable names/pins and, if
            necessary, are rearranged to keep the ordering correct.

            This will not work with conventional keyword arguments,
            where one expects a keyword list—if using the named/pinned
            syntax, keyword arguments may not be used. It's one or the
            other, not both.

            If this named syntax exists on a function head, then a
            calling function may use the `name: value` syntax and it
            will align the values to the named argument at compile
            time (no keyword lists are used at runtime).

            Example:

            Using `&` as a reference for the naming (or possibly if
            not that, the asterisk):

              def do_a_thing(&new, &old)

            Would accept any of these calls, and in all cases the
            variable values within the called function would align
            properly:

              do_a_thing("newer value", "older value")
              do_a_thing(new: "newer value", old: "older value")
              do_a_thing(old: "older value", new: "newer value")

            Optional named arguments in the same manner as optional
            arguments today:

              def do_a_thing(&new, &old, &optional \\ "extra info")

            Optional ideas:

             1. If rearranging the arguments at compile time is not
                easily feasible, it could simply just raise a compiler
                error when out of order, and then strip the names when
                they are properly ordered.
             2. If using named/pinned arguments, always require them
                to be named (thus, the first example above would be
                invalid). However, this comes with its own challenge,
                notably what about when using pipelines? Perhaps just
                allow that.
             3. If it's too challenging to use the same syntax as
                keyword lists, another naming convention could be
                used. It's just ... uglier.  Perhaps if using `*`
                instead it would be on both sides (function head, and
                calling function), such as:

              def do_a_thing(*new, *old)
              ...
              do_a_thing(*new: "newer value", *old: "older value")

-- You received this message because you are subscribed to the
        Google Groups "elixir-lang-core" group.
        To unsubscribe from this group and stop receiving emails from
        it, send an email to
        elixir-lang-core+unsubscr...@googlegroups.com.
        To view this discussion on the web visit
        
https://groups.google.com/d/msgid/elixir-lang-core/0928ddde-8ca2-4110-a223-d62b711529a7n%40googlegroups.com
        
<https://groups.google.com/d/msgid/elixir-lang-core/0928ddde-8ca2-4110-a223-d62b711529a7n%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- You received this message because you are subscribed to the Google
    Groups "elixir-lang-core" group.
    To unsubscribe from this group and stop receiving emails from it,
    send an email to elixir-lang-core+unsubscr...@googlegroups.com.
    To view this discussion on the web visit
    
https://groups.google.com/d/msgid/elixir-lang-core/CAKC64%2Bz6yHpK%3DJpN1fd7fgz9Z-m2UmsA0a852obGrjCpXzN1-w%40mail.gmail.com
    
<https://groups.google.com/d/msgid/elixir-lang-core/CAKC64%2Bz6yHpK%3DJpN1fd7fgz9Z-m2UmsA0a852obGrjCpXzN1-w%40mail.gmail.com?utm_medium=email&utm_source=footer>.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2BsNgEUVdYQv_N6cu90O%2BzheNs1UPo5bZPw8-tT4UROhA%40mail.gmail.com <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2BsNgEUVdYQv_N6cu90O%2BzheNs1UPo5bZPw8-tT4UROhA%40mail.gmail.com?utm_medium=email&utm_source=footer>.

--
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/e77b7315-625a-4c8e-0e63-bbd03116fbbe%40cold.org.

Reply via email to