News for hackers. Stuff that matters.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by kiawe_fire on Sunday June 14, 2020 @11:22AM (#23518318)
Maybe it's shallow of me, but named/keyword arguments are now at the top of my list of things I want in a programming language.

For all the attention given to static typing and unit testing for increasing developer confidence, I think named arguments belong up there as well. Makes reading code so much easier, especially the way they are implemented and encouraged in Swift.

As someone stuck doing PHP for my day job, they could buy an awful lot of goodwill from me by implementing something like this in PHP (well, that, and separating arrays from dictionaries, but that seems far less likely to happen).

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by simias on Sunday June 14, 2020 @11:43AM (#23518498)
I like named/keyword arguments too but I think one needs to be careful not to overdo it, especially in statically typed languages. I think it's sort of a last resort when the call syntax can't be disambiguated by other means.

As an example imagine a search function that returns the position of a character `c` in a string `str` that looks like that:

    int search(String str, char c, bool case_sensitive, bool from_end)
I'd say that I would avoid this signature in general, because those two `bool`s make for an awkward call syntax:

    search("foo", 'f', true, false)
That's pretty opaque, even if you know what the two options are it's easy to forget the order. Now you might say "well see, that's where keyword parameters shine!" and you'd be right, it does help a lot:

    search("foo", 'f', case_sensitive: true, from_end: false)
But I'd argue that while this is good enough if you're coding in a dynamically typed language, it's actually sub-obtimal if you're coding in Rust for instance. Here you can do something even better: give these two options different types, this way not only it makes the code more explicit, it also means that it gets enforced by the compiler:

    enum SearchCase { Sensitive, Insensitive };
    enum SearchDirection { FromStart, FromEnd };

    search("foo", 'f', SearchCase::Sensitive, SearchDirection::FromStart);
Now that's not to say that I don't want or like keyword arguments, I just think that it's one of these situations where "when you have a hammer, everything looks like a nail". I sometimes miss keyword arguments in Rust, but it's the exception rather than the rule for me.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by skohan on Sunday June 14, 2020 @12:32PM (#23519043)
I would question that your rust example is better than the named argument example. I think it's situational at best, and a workaround at worst.

For instance, even in the example you gave, it could be argued that the SearchCase type is really just a boolean which is being introduced to do the job of an argument label. If this enum is only used in this function call, that's going to add noise to the docs with fairly tenuous justification.

And this only works in the case of arguments which can be easily converted to enums. For instance if I have a signature which looks like this:

   void search_buffer(int match, int start, int end, int stride)
It's going to be very difficult to look at the call site and infer what the meanings of these arguments are.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by simias on Sunday June 14, 2020 @03:37PM (#23520642)
>For instance, even in the example you gave, it could be argued that the SearchCase type is really just a boolean which is being introduced to do the job of an argument label. If this enum is only used in this function call, that's going to add noise to the docs with fairly tenuous justification.

I don't really agree with this, I think in general it's a good idea to type your parameters as tightly as it's reasonable to do. I don't think that introducing a one-time enum is particularly unreasonable. I don't really get the argument for reducing noise in the docs, typically nowadays API documentations are hyperlinked document, not a big PDF, you either look the symbol up or you don't.

An argument in favour of using types here would be in the situation where the "case_sensitive" parameter is not a literal in the code but something that's being passed as argument from an other function or stored in an object. The names could be slightly different, the conventions could change from one part of the code to an other etc... With dedicated types you can be reasonably certain that if the types match then it's probably safe to pass to the function, with human-level semantics that may require more caution.

Of course my example is so trivial that it could be argued to be over-engineered, but consider a function that takes angles as floating point numbers vs. a dedicated "Angle" type for instance, with the float you have to make sure that the underlying representation is correct (degrees? radians? turns?) whereas a dedicated type would typically have well-defined semantics.

>And this only works in the case of arguments which can be easily converted to enums. For instance if I have a signature which looks like this:

   void search_buffer(int match, int start, int end, int stride)
I agree completely with you here. Keyword parameters definitely have their use cases. I just think that they should be used parsimoniously and, IMO, can be a code smell if used too often, especially in languages with a decent type system.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by oefrha on Sunday June 14, 2020 @11:49AM (#23518573)
You’re forgetting another important use case of keyword/named arguments: default values. In Rust either every call site needs to specify the default values, or you use a None for the default which is not at all readable.

Also, if Rust were to support named arguments (even better if with default values), you can use explicit types for your bools all the same. It’s not an either or situation.

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by kbenson on Sunday June 14, 2020 @03:10PM (#23520417)
Wouldn't a struct for named options that have defaults which is passed as the last option emulate optional named arguments with default values?
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by skohan on Sunday June 14, 2020 @03:54PM (#23520781)
Of course in the case of Rust this would mean potentially one type per function being added to your implementation. That’s a lot of boilerplate for a problem which is solved really well by defaultable named parameters
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by kbenson on Sunday June 14, 2020 @04:17PM (#23520945)
I agree it seems like a lot of boilerplate, but from what little I've played around with Rust, it seems they've already adopted strategies similar to this for instantiating objects with the builder pattern[1], but the nuts and bolts are abstracted away so the interface is slightly different.

If I understand it correctly, the equivalent builder pattern in Rust (which is essentially using methods to build a struct used to instantiate the object) would be:

    let search = Search::new("foo","f")
      .option_case_sensitive(true)
      .option_from_end(false)
      .build();
Where "new" returns a builder object/struct with passed in and default params, those options methods are optional and can change those defaults, and the build method actually builders the search object from the search builder struct with all the params.

I'm not sure how well this style works with simple functions, unless there's a macro or crate that can do most of this work for you from a a spec.

1: https://doc.rust-lang.org/1.0.0/style/ownership/builders.htm...

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by saagarjha on Sunday June 14, 2020 @01:07PM (#23519362)
> Here you can do something even better: give these two options different types, this way not only it makes the code more explicit, it also means that it gets enforced by the compiler

Bool is also enforced by the compiler; adding ad-hoc types for things that have only two values is generally not something you should do without good reason. By the way, constructs like these are fairly common in Swift:

  enum SearchType {
      case literal
      case regex
      case extendedRegex
  }

  extension String {
      func substring(matching needle: String, interpretedAs type: SearchType = .literal) -> Substring
  }
which you'd use as something like

  "foobar".substring(matching: "o*ba", interpretedAs: .regex) // "ooba"
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by barrkel on Sunday June 14, 2020 @02:45PM (#23520149)
In the absence of keyword arguments as a language feature, boolean arguments should almost always be avoided, and replaced by enums where possible. Boolean arguments are almost always inscrutable at the call site.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by skohan on Sunday June 14, 2020 @02:59PM (#23520300)
Then it would be very convenient to have keyword arguments, as in the case presented by the previous poster
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by kiawe_fire on Sunday June 14, 2020 @11:59AM (#23518710)
I still think there are wider use cases for named arguments. For example, even disambiguating between which argument is the "string" and which is the "substring to be found", or the classic "x, y, width, height" list in graphics programming.

But your point is well taken that, like many tools, you shouldn't abandon one set of good practices for another. There are certainly cases where a builder pattern or enum values are a better fit, which could be obscured as an option because keyword arguments "sorta kinda but don't really" address the same thing.

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by ridiculous_fish on Sunday June 14, 2020 @03:10PM (#23520413)
If this were a real API, you would need to add the trimmings:

    /// Doc comment doc comment doc comment
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
    pub enum SearchCase { Sensitive, Insensitive }
now it starts to feel like heavyweight clutter.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by simias on Sunday June 14, 2020 @03:43PM (#23520691)
I see what you mean, but if that's the problem I'd argue that the weakness is that Rust lacks a shorthand to declare simple enums, not necessarily that it lacks keyword parameters. #[derive] soup aside I don't think too bad at the moment though, and I'm not really sure how you could simplify that without introducing too much magic into the language.

After all, even with keyword parameters there'll always be plenty of opportunity for one-off enums, if only for situations where more than two choices are possible. Take a typical "seek" function for instance, who can usually be performed relative to the current location, from the start or from the end.

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by atombender on Sunday June 14, 2020 @02:49PM (#23520202)
In Go (and, I think, Rust?) variadic arguments are often used for optionals:

    search("foo", CaseSensitive, FromStart)
or options that take values:

    search("foo", WithCaseSensitivity(false))
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by yoz-y on Sunday June 14, 2020 @12:44PM (#23519145)
That's why Swift does support unnamed parameters as well, and they can interweave with named ones. If the type of the argument is explicit enough, you can make the parameter name at call site optional.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by wool_gather on Sunday June 14, 2020 @01:16PM (#23519438)
Nitpick (I think this is just a miswording rather than a misunderstanding): it's not optional. You can have unlabelled args, but that's enforced too: the label must be included or omitted at the call site according to the function declaration.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by yoz-y on Sunday June 14, 2020 @07:03PM (#23522176)
TBH I was usure and kind of lazy to check. Thanks for pointing it out!
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by frou_dh on Sunday June 14, 2020 @01:18PM (#23519449)
A sufficiently smart editor could show names in front of positional arguments, even if named arguments are not part of the language.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by skohan on Sunday June 14, 2020 @01:22PM (#23519469)
Tools are great, but I'm not a fan of the idea of needing special tooling outside of the source code itself in order to be able to understand it.

Maybe it's just me, but I would hate to imagine living in a world where my projects might be incomprehensible if I ever lost my .vimrc

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by frou_dh on Sunday June 14, 2020 @01:24PM (#23519482)
In this case it would be a pure value-add, because the fallback is the way everyone can evidently cope with anyway.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by adrianmsmith on Tuesday June 16, 2020 @02:03PM (#23542094)
I'm not sure that's entirely true. If a large proportion of people use a more advanced development tool, it sort of becomes indispensable, because people design the software to be edited with the tool, such that it becomes difficult to edit it without the tool.

For example if, today, I checked in code like performRequest(request, response, null, null, null) you probably wouldn't consider that good code, as it's not clear what the nulls mean there. Most people today would try to not write code like that. But if everyone was using an editor which displayed the parameter names, then it'd be fine. People would write that code, check it in, and so on. Which would mean that those people without the tool would have to confront such code.

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by adrianmsmith on Sunday June 14, 2020 @01:44PM (#23519636)
IntelliJ does this in Java. It only does it for those arguments where the meaning could be unclear. For example, true/false or null.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by anchpop on Sunday June 14, 2020 @01:49PM (#23519673)
Rust-analyzer does this, and I find it much more helpful than I thought I would
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by frank2 on Thursday June 18, 2020 @03:28PM (#23566796)
What editor or IDE do you use rust-analyzer with?
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by mariodiana on Sunday June 14, 2020 @12:10PM (#23518825)
If they could just add square brackets, it would be perfect.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by saagarjha on Sunday June 14, 2020 @01:12PM (#23519395)
I think you might be interested in a little language called Objective-C ;)
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by MrBuddyCasino on Sunday June 14, 2020 @11:34AM (#23518420)
Automatically generated builders are also nice, not sure yet which I prefer.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by kevincox on Sunday June 14, 2020 @11:53AM (#23518631)
I have long envisioned a language where these two things were tightly combined. The rough ideas are:

- All arguments are keyword arguments. - Each function implicitly defines a struct type equivalent to its arguments.

I think if you combined this with some nice structural typing you can get a lot of the argument forwarding/builders and similar that people enjoy in dynamic languages without much/any overhead. Rough example:

fn add(a: int, b: int): int { a + b }

fn add3(c: int, rest: add::args): int { add(rest) + 3 }

A somewhat silly example but I think you can see the point. Of course you could also add language-level builder syntax to these structs and have something really nice.

I think the key here is that once you make the arguments a static type you can add loads of convenience like builders very easily.

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by wwright on Sunday June 14, 2020 @02:16PM (#23519906)
This makes me wonder if there is some sort of relationship between currying and row polymorphism; that could be pretty sweet to capture succinctly in a language
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by MrBuddyCasino on Sunday June 14, 2020 @11:10PM (#23523417)
Args reified as structs, interesting! On the other hand, not exceptional at all when looking at it from a Lisp angle.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by eeereerews on Sunday June 14, 2020 @05:40PM (#23521618)
I've thought about this too, but keeping positional args. The basic data type would be a "blob", consisting of a struct part and a tuple part.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by oefrha on Sunday June 14, 2020 @11:45AM (#23518522)
Builders are nice when you actually need to build something with tons of optional arguments. The vast majority of cases where named arguments shine are function/method calls where builders just don’t make sense. Also, named arguments complement/augment the builder pattern.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by MrBuddyCasino on Sunday June 14, 2020 @11:52AM (#23518627)
Good point. Also, named arguments can be compiler checked for mandatory values, with builders the error happens at runtime.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by swsieber on Sunday June 14, 2020 @12:10PM (#23518829)
You can actually have type safe buildrs in rust where trying to call the method that consumes the builder fails to compile if not all the arguments are set correctly.

https://github.com/idanarye/rust-typed-builder/blob/master/R...

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by MrBuddyCasino on Sunday June 14, 2020 @03:21PM (#23520521)
Ah yes, linear types to the rescue! Nice.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by swsieber on Sunday June 14, 2020 @03:46PM (#23520713)
I think technically it's affine types. In this particular case it comes from really nice generics - you start out with a struct that's generic over all fields - one generic bound per field. And that let's you implement methods depending on what fields have been set. So you could even make a builder with mutually exclusive setters. But you'd probably just want to use an enum in that case for the mutually exclusive options.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by MrBuddyCasino on Monday June 15, 2020 @03:21AM (#23524703)
I still don't quite understand the generics magic required in order to not generate exponential amounts of code for it to allow random order of arguments, but I won't complain. That capability would have come in handy on Java/Lombok.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by swsieber on Wednesday June 17, 2020 @12:11PM (#23553060)
> exponential amounts of code for it to allow random order of arguments

The key is that it only generates code for types that actually get used. So if you always call the orders in the same order, it won't generate tons of code. That said, you could actually tweak the type-safe builder to enforce a certain order for calling the methods on the builder.

Also, it's not the order of arguments, it's the order of method calls :)

Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by ndotl on Sunday June 14, 2020 @01:26PM (#23519498)
Named arguments are great but should be used with care as they also create a reverse dependency. It prevents you from ever renaming the arguments in the future.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by wool_gather on Sunday June 14, 2020 @01:42PM (#23519624)
Accompanying saagarjha's point, you can freely rename the internal argument names, just not the external labels. Which is basically the same as changing the argument names in say C.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by paublyrne on Sunday June 14, 2020 @01:35PM (#23519566)
In the case of a library that would make this a breaking change you could add the new key rather than changing it, and support both while flagging old key usage with a deprecation warning.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by saagarjha on Sunday June 14, 2020 @01:28PM (#23519511)
Just like you can't ever rename the function in the future?
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by dep_b on Sunday June 14, 2020 @02:16PM (#23519897)
You can mark it as deprecated with a reference to the replacing function. As long as the argument types match you can automatically refactor
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by DagAgren on Sunday June 14, 2020 @03:23PM (#23520538)
This is already the case with the name of your function. And named arguments are basically just an extension of the name of your function.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by fsloth on Sunday June 14, 2020 @01:39PM (#23519594)
Why would it? When you change the name of nth argument from foo to bar, compile will fail and then you just need to do a global rename. Is there any scenario where this would not be feasible?
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by wool_gather on Sunday June 14, 2020 @02:05PM (#23519806)
The caller can't do a global rename if they don't own the source of the function -- because it's in a library. Which is what parent meant by "reverse dependency": the library's interface is constrained by the fact that it has users.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by fsloth on Monday June 15, 2020 @01:06AM (#23523963)
Surely if the library interface changes the users can change their own code? That's why we have versioning of libraries - so that users of the library can take intelligently new versions into use, and especially so they are aware if (and when) the interface changes.
Re:The Curious Case of Swift's Adoption of Smalltalk Keyword... by DagAgren on Sunday June 14, 2020 @03:22PM (#23520531)
But this is already the case for the name of the function. Semantically, named arguments are just part of the name of the function.