6 ms·
I'm really impressed by the syntax. I have yet to find a piece of syntax I wouldn't like. Labelled arguments for example are delightful: pub fn replace(
by xixixao 3y ago
I'm really impressed by the syntax. I have yet to find a piece of syntax I wouldn't like. Labelled arguments for example are delightful:
pub fn replace(
in string: String,
each pattern: String,
with replacement: String,
) {
// The variables `string`, `pattern`, and `replacement` are in scope here
}
replace(in: "A,B,C", each: ",", with: " ")
- hota_mazi 3y agoFYI Swift did this years ago.
- wiml 3y agoSwift probably did it for ObjC compatibility, and ObjC got it from Smalltalk.
- 698969 3y agoThe only part that rubs me the wrong way is, > The pipe operator will first check to see if the left hand value could be used as the first argument to the call, e.g. a |> b(1, 2) would become b(a, 1, 2). Optimizing for one less _ typed is a really bad trade-off in terms of clarity here.
- xixixao 3y agoI actually agree, this is the most questionable piece. I prefer (and have argued for in JS) Hack-style pipes, where the value "placement" always has to be specified. That allows arbitrary expressions on the RHS of the pipe, so for example this would be valid Gleam: pub fn main() { io.println( "Hello" |> (_ <> " world") ) }
- pharmakom 3y agoGleam has curried functions by default so F# style pipes make sense imo.
- hayleighdotdev 3y agoGleam doesn't have auto currying! Often folks find this (currying) a bit confusing to wrap their head around when learning functional programming and we don't feel like it really affords you much that couldn't already be achieved with just a little bit more work by the programmer. Applicative builder APIs are the only thing we've found would be much much better if we had auto currying.
- lpil 3y agoGleam did used to have this, but the community collectively decided that it was actually quite annoying in practice to always have to write `_, ` after every function
- vips7L 3y agoHow does this work if you rename a variable? Does it break all callers?
- tczMUFlmoNk 3y agoIn 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.
- vips7L 3y agoWhy are there both labels and variable names?
- tczMUFlmoNk 3y agoThey 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-arguments https://gleam.run/book/tour/functions.html#labelled-argument...
- troupo 3y agoFor me personally that's the part of syntax I don't like and don't understand the value of.
- danappelxx 3y agoGenerally stems from the philosophy that code is read more than written, and this helps readability.
- troupo 3y agoDoes it? Instead of a single parameter you now have two names, and a type info to boot pub fn replace( in string: String, each pattern: String, with replacement: String, ) { // The variables `string`, `pattern`, and `replacement` are in scope here } replace(in: "A,B,C", each: ",", with: " ") vs pub fn replace( in: String, each: String, with: String, ) { } replace(in: "A,B,C", each: ",", with: " ")
- _glass 3y agoWouldn't you have replace("A,B,C", ",", " "), which is quite unreadable.
- troupo 3y agoNot if you go the C# way: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments https://learn.microsoft.com/en-us/dotnet/csharp/programming-...
- lpil 3y agoWhen argument variable names and labels are combined you have two problems: 1. Labels are accidental. If all arguments automatically create labels then the programmer has not considered and deliberately designed the API. Gleam is designed to make sure that APIs are always carefully thought about and designed as appropriate. 2. Renaming a variable becomes a breaking change. We don't believe that renaming a variable should ever result in a semver major version bump.
- al_be_back 3y agoswift has that - it's smart. helps with documentation, and simplifies refactoring. I'm up for any features that reduce changes upstream.
- kabes 3y agoJavascript has supported this for many years.
- Hasnep 3y agoIt definitely hasn't, JavaScript doesn't even have named arguments.
- kabes 3y agoIf you pass your arguments as an object they are named and you can rename them. So for all practical purposes that's the same thing.
- deleted 3y ago[deleted]
- lpil 3y agoIt doesn't have labelled arguments. It can roughly simulate them using an object, but there's a slight performance cost to doing so.