Thread compares named-argument designs in Swift, ObjC, Gleam and OCaml
5 Sep 22 1:26 AM · 2d ago · 5 comments · 1 source · development 5 of 5
Commenters describe how Swift, Objective-C, Gleam and OCaml separate internal parameter names from external call-site labels, offering possible models for a future Rust design.
“Swift's approach to this is pretty neat, it separates internal parameter names and external argument labels, so you can rename the parameter without affecting the argument, and the other way around.”
masklinnbotahamec Blog authorekuber Lobsters commenterschneems Lobsters commenter
The whole story postscomments the bright band is this development · numbered dots are the others · click one to jump
What people said 24 voices · best of 34 · verbatim
-
> it makes parameter names part of the public API of the function, I really like the way gleam (and swift too I believe) goes about this. The public parameter name has to be picked explicitly rather than all arguments being named automatically. ```gleam pub fn replace( in string: String, each value: String, with replacement: String, ) -> String {…
-
I'm unsure why the parameter names being part of the API is presented as a problem? It's literally the point of feature. You just need to make sure that the syntax permits the implementation to use a different name, because it's the implementation - this is something that objective-c and swift both support, which means APIs are often written as…
-
> it makes parameter names part of the public API of the function, After using Python's equivalent (keyword arguments) and Ada's equivalent (named parameter associations) quite a bit, I went from "parameter names being part of the API is bad" to "perhaps this isn't a bad idea." You're forced to think more about clear parameter names, which…
-
In ObjC, the name and the label are separate, so you things like: - (NSString *) stringByPaddingToLength:(NSUInteger) len withString:(NSString *) pad startingAtIndex:(NSUInteger) idx; which you'd call something like: [str stringByPaddingToLength: 123 withString: @" " startingAtIndex: 10] the variables inside the function are named `len`, `pad`…
-
Swift’s approach to this is pretty neat, it separates internal parameter names and external argument labels, so you can rename the parameter without affecting the argument, and the other way around. In keeping with objc (and Smalltalk) it also defaults to named arguments, but you can opt out (or opt in positional arguments) on a per-argument basis.
-
> I'm unsure why the parameter names being part of the API is presented as a problem? When it’s implicit / opt out / default it is a routine problem because you declare an API without knowing it. It’s a relatively common problem in Python where the default argument mode is that they can be passed by position or keyword, and people routinely do not…
-
It takes a little bit of getting used to but I cannot understate how much it improves code readability. I have never had to consult the docs when reading someone else’s Objective-C code to see what the parameters meant to a function. I can’t say that about most other languages.
-
I fully agree that named and (named) optional arguments would be awesome to have in Rust. I do not have a strong preference for what that syntax should look like. (I generally care much more about semantics than syntax.) But that `spawn` example reminds me of Python, and it's not a good memory. Every time I need to spawn a process in Python I…
-
[Gleam has the same feature.](https://tour.gleam.run/functions/labelled-arguments/) Not sure whether it's inspired by or independent of Swift's.
-
I'm not sure I buy that it's so terrible to wade through n different functions with all the variations of input parameters. If, instead, it were one function with behavior dependent on something like kwargs, one still has to mentally wade through the implicit variations of the function. I'd much rather go through an explicit list produced by the…
-
enum Bold { Yes, No }; enum Italics { Yes, No }; enum Underline { Yes, No }; fn print(text: &str, bold: Bold, italics: Italics, underline: Underline) { ... } print("asdf", Bold::No, Italics::No, Underline::Yes);
-
> Parameter names being part of the API isn't so bad, but default values being part of the API can result in some unexpected behavior. For example, if you have some sort of compute(a, b = 10) function where b = 10 indicates an optional argument with the default value of 10, changing that default to e.g. 20 could produce unexpected results. I don't…
-
Although it looks exactly like just a language shortcoming, and the typical golang excuse "it's by design", I have to admit that I think that rust is okay without named nor optional arguments. Less god functions. It also forces you to think twice before bolting on (yet) another optional variant.
-
> I'm unsure why the parameter names being part of the API is presented as a problem? I think the problem is when the label is the internal name. Then, if you don’t have a way to choose which ones are public and which private, changing a parameter name breaks the public API.
-
In my reply to @masklinn I realized that if the named parameters are optional - e.g the same function can be called with or without named parameters that is a giant - and real - footgun. In swift, objc, smalltalk the named parameters are not the variable names - swift allows that as a short hand (and has syntax for no parameter name). E.g func…
-
> When it’s implicit / opt out / default it is a routine problem because you declare an API without knowing it. That's not my experience in the context of objective-c and swift: it's well understood that the parameter names are part of the function name. It may be more difficult if you start from a PoV that the parameter names are simply…
-
I think comparing with dynamically-typed languages is not optimal. With dynamically-typed languages, named parameters are nearly mandatory otherwise things are too error-prone. With statically-typed languages, I think any function which does not take arguments of types that can be confused is automatically fine. And functions with many arguments…
-
The author highlighted the exact "function which takes arguments of types that can be confused" case! Examples were given of, for example: ```rust // Without named arguments: what are these numbers? solar_elevation(1787517098.0, 38.897957, -77.036560) // With named arguments, it's obvious solar_elevation(timestamp: 1787517098.0, latitude…
-
*This* is what I mean when I talk about "syntax has to be orthogonal, one should be able to extrapolate from one language feature how another will work". I don't think it is the nicest syntax, but it *fits with the rest of the language*. It honestly looks like a sensible way of going about this. I suspect that it will be hard to actually get named…
-
Instead of using multiple bools which are privitive types make a strong type e.g. in Rust an enum for each which describes what the flag actually means and is a different type for each setting. This at first may look stupid for something as basic as a print function. It doesn't look stupid at all and makes the code much more readable for any…
-
A fun fact is that renaming parameters directly in the argument list is already possible in rust - thanks to the fact that arguments are bindings, and bindings are patterns! ``` fn replace(string @ input: String, value @ each: char, replacement @ with: char) { /* snip */ } ``` So now we only need the ability to have argument names at the callsites…
-
I don't like optional positional arguments (i.e Typescript. `function foo(a: Blah, b?: Baz) {...}`). When introducing additional arguments, I prefer if all call sites cause compilation errors so I can check that the introduction of the argument is correct for all cases. I don't mind named optional arguments as much.
-
I really like Swift's approach, where you can make it look C-like where appropriate, include the first argument in the method name (as in Objective-C, e.g. `performAction(withFoo:)` and get both `action` and `foo` out), or any combo of them.
-
> fn print(text: &str, bold: bool, italics: bool, underline: bool); This is easily addressed, use an enum.
All 5 developments of Rust blog post on missing named/optional arguments sparks… →
Hacker NewsLobsters