Hacker News new | past | comments | ask | show | jobs | submit login

They serve different purposes.

Without labels—i.e., with only traditional positional arguments—the example would simply be a function taking three string parameters:

    replace(String, String, String)
Of course, the documentation should specify which arguments are which, but still at call sites it would be easy to accidentally permute the arguments:

    replace("https://[^/]*", "", url)  // wrong!
(In this case, the problem is exacerbated since different languages/libraries pick different orders here! For instance, the incorrect ordering above is correct for Python's `re.sub`, so it's easy to see how mistakes might arise.)

Labels solve this problem by making the binding explicit at the call site:

    replace(each: "https://[^/]*", with: "", in: url)  // now correct!
(Looking at the Gleam docs [1], it seems that labeled arguments "can be given in any order".)

Now, how does the implementation of this function look? The obvious first approach is to require the labels to be the same as the local variable names, but this often leads to awkward "grammar", because (in the convention of Gleam and some other languages, like those in the Smalltalk/ObjC/Swift heritage) good label names tend to be more like prepositions, whereas variable names like to be nouns:

    pub fn replace(in: String, each: String, with: String) {
        // variables `in`, `each`, and `with` in scope...
        in.split(each).intersperse(with).join()  // hmm...
    }
Now, of course, the implementation can simply re-bind its arguments to new names:

    pub fn replace(in: String, each: String, with: String) {
        let string = in, pattern = each, replacement = with;
        string.split(pattern).intersperse(replacement).join()  // better.
    }
And labeled arguments are sugar for precisely that:

    pub fn replace(in string: String, each pattern: String, with replacement: String) {
        string.split(pattern).intersperse(replacement).join()
    }
[1]: https://gleam.run/book/tour/functions.html#labelled-argument...



Isn't this solvable just by using types and instances rather than just calling top level/static functions? If you have a "replace" function off of String and use a Pattern type instead of a raw string, the compiler will enforce the correct type and ordering.

    val p = Pattern("https://[^/]*")
    val in = "https://google.com/some/path"
    val path = in.replace(p, "") // /some/path
In fact this specific example is solved just by having a dedicated type, for example URI:

    val path = URI("https://google/com/some/path").path; // /some/path

This feels like to me an answer in search of a problem.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: