Re:Gleam: a type safe language on the Erlang VM
by vips7L on Wednesday November 08, 2023 @12:45AM
(#38187201)
How does this work if you rename a variable? Does it break all callers?
[ Parent
| on HN ]
Re:Gleam: a type safe language on the Erlang VM
by tczMUFlmoNk on Wednesday November 08, 2023 @02:01AM
(#38187523)
In this example, the local variables are `string`, `pattern`, and `replacement`, and are implementation details; only the names `in`, `each`, and `with` are part of the public API. Renaming the local variables doesn't break anyone. Renaming the labels would break callers, just as changing the names of keyword arguments in other languages.
Re:Gleam: a type safe language on the Erlang VM
by vips7L on Wednesday November 08, 2023 @12:47PM
(#38194098)
Why are there both labels and variable names?
Re:Gleam: a type safe language on the Erlang VM
by tczMUFlmoNk on Wednesday November 08, 2023 @02:08PM
(#38195336)
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...
Re:Gleam: a type safe language on the Erlang VM
by vips7L on Wednesday November 08, 2023 @03:41PM
(#38196635)
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.