Proposal: Allow operators to have parameters with default values

Hi SE,

As I’ve been using my own custom operators like “?!”, “!!”, or operators provided by libraries (<|, ~>, etc), I’ve often wanted to capture the #file and #line where the operators are used to make debugging their use a lot easier.

For example, given something the unwrap-or-die operator (https://github.com/erica/swift-evolution/blob/2c1be72e34c970894e4ba7ed9df5cee3298d4282/proposals/XXXX-unwrap-or-die.md\), you’d want to capture the #file and #line so you could pass it on to the underlying call to fatalError().

Or, if you’re using a custom bind operator and something goes wrong, it’d be great to be able to capture the file and line where the operator is used so you can quickly triage the bug in your code.

Unfortunately, Swift has the hard limit the the implementations of unary operators may have one-and-only-one parameter, and that binary operators may only have two parameters.

I’d like to propose a very minor change to Swift, whereby operator implementations may have more than their one or two parameters, provided that all subsequent parameters come with a default value. This would make it trivial to add in #file, #line, #function, etc to your operator implementations, which you can then capture for your own purposes.

An implementation of this change, with passing tests, can be found here: https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697

Dave

I like this idea as it's presented here, for the debugging/logging reasons
that you stated.

Should we tighten the shackles a little be to validate that *only* the
special #file/#line/function directives can be permitted for these extra
parameters? I'm struggling to think of a case where we would want to allow
something else, since there's no way to provide the values for them in a
standard call.

···

On Thu, Nov 2, 2017 at 5:26 PM Dave DeLong via swift-evolution < swift-evolution@swift.org> wrote:

Hi SE,

As I’ve been using my own custom operators like “?!”, “!!”, or operators
provided by libraries (<|, ~>, etc), I’ve often wanted to capture the #file
and #line where the operators are used to make debugging their use a lot
easier.

For example, given something the unwrap-or-die operator (
https://github.com/erica/swift-evolution/blob/2c1be72e34c970894e4ba7ed9df5cee3298d4282/proposals/XXXX-unwrap-or-die.md\),
you’d want to capture the #file and #line so you could pass it on to the
underlying call to fatalError().

Or, if you’re using a custom bind operator and something goes wrong, it’d
be great to be able to capture the file and line where the operator is used
so you can quickly triage the bug in your code.

Unfortunately, Swift has the hard limit the the implementations of unary
operators may have one-and-only-one parameter, and that binary operators
may only have two parameters.

I’d like to propose a very minor change to Swift, whereby operator
implementations may have more than their one or two parameters, provided
that all subsequent parameters come with a default value. This would make
it trivial to add in #file, #line, function, etc to your operator
implementations, which you can then capture for your own purposes.

An implementation of this change, with passing tests, can be found here:
https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697

Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

While I agree that I can’t think of another use-case off the top of my head (curried operators, somehow? Maybe?), I also don’t necessarily see the benefit of restricting it.

As the implementation currently stands, we could add new keywords, like module or #context (which would capture #file, #line, function, module, etc as a single type), without having to change the implementation of IsBinaryOperator() and IsUnaryOperator().

It’s also nice that if a legit use-case ever did come up, the language would support it out-of-the-box without requiring another change.

Dave

···

On Nov 2, 2017, at 6:34 PM, Tony Allevato <tony.allevato@gmail.com> wrote:

I like this idea as it's presented here, for the debugging/logging reasons that you stated.

Should we tighten the shackles a little be to validate that *only* the special #file/#line/function directives can be permitted for these extra parameters? I'm struggling to think of a case where we would want to allow something else, since there's no way to provide the values for them in a standard call.

On Thu, Nov 2, 2017 at 5:26 PM Dave DeLong via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi SE,

As I’ve been using my own custom operators like “?!”, “!!”, or operators provided by libraries (<|, ~>, etc), I’ve often wanted to capture the #file and #line where the operators are used to make debugging their use a lot easier.

For example, given something the unwrap-or-die operator (https://github.com/erica/swift-evolution/blob/2c1be72e34c970894e4ba7ed9df5cee3298d4282/proposals/XXXX-unwrap-or-die.md\), you’d want to capture the #file and #line so you could pass it on to the underlying call to fatalError().

Or, if you’re using a custom bind operator and something goes wrong, it’d be great to be able to capture the file and line where the operator is used so you can quickly triage the bug in your code.

Unfortunately, Swift has the hard limit the the implementations of unary operators may have one-and-only-one parameter, and that binary operators may only have two parameters.

I’d like to propose a very minor change to Swift, whereby operator implementations may have more than their one or two parameters, provided that all subsequent parameters come with a default value. This would make it trivial to add in #file, #line, function, etc to your operator implementations, which you can then capture for your own purposes.

An implementation of this change, with passing tests, can be found here: https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697

Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I think this makes more sense as part of a hygienic macro system. These “hidden” parameters could be made available to standard functions using some sort of convention to exclude them from autocompletion.

Eric

···

On Nov 2, 2017, at 8:35 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

I like this idea as it's presented here, for the debugging/logging reasons that you stated.

Should we tighten the shackles a little be to validate that *only* the special #file/#line/function directives can be permitted for these extra parameters? I'm struggling to think of a case where we would want to allow something else, since there's no way to provide the values for them in a standard call.

On Thu, Nov 2, 2017 at 5:26 PM Dave DeLong via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi SE,

As I’ve been using my own custom operators like “?!”, “!!”, or operators provided by libraries (<|, ~>, etc), I’ve often wanted to capture the #file and #line where the operators are used to make debugging their use a lot easier.

For example, given something the unwrap-or-die operator (https://github.com/erica/swift-evolution/blob/2c1be72e34c970894e4ba7ed9df5cee3298d4282/proposals/XXXX-unwrap-or-die.md\), you’d want to capture the #file and #line so you could pass it on to the underlying call to fatalError().

Or, if you’re using a custom bind operator and something goes wrong, it’d be great to be able to capture the file and line where the operator is used so you can quickly triage the bug in your code.

Unfortunately, Swift has the hard limit the the implementations of unary operators may have one-and-only-one parameter, and that binary operators may only have two parameters.

I’d like to propose a very minor change to Swift, whereby operator implementations may have more than their one or two parameters, provided that all subsequent parameters come with a default value. This would make it trivial to add in #file, #line, function, etc to your operator implementations, which you can then capture for your own purposes.

An implementation of this change, with passing tests, can be found here: https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697

Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think the use case is legitimate, but I'm uncomfortable with the proposed
solution. Firstly, because for the proposed use case it's not a "default"
parameter in that it's not overridable: you can't actually pass another
argument. Secondly, because you wouldn't want the two parameters of an
infix operator function, or the single parameter of a non-infix operator
function, to allow a default value (that totally gums up the distinction
between prefix, infix, and postfix operators). I agree with Eric that the
use case feels like it calls for a "macro-like" solution.

···

On Thu, Nov 2, 2017 at 7:50 PM, Eric Summers via swift-evolution < swift-evolution@swift.org> wrote:

I think this makes more sense as part of a hygienic macro system. These
“hidden” parameters could be made available to standard functions using
some sort of convention to exclude them from autocompletion.

Eric

On Nov 2, 2017, at 8:35 PM, Tony Allevato via swift-evolution < > swift-evolution@swift.org> wrote:

I like this idea as it's presented here, for the debugging/logging reasons
that you stated.

Should we tighten the shackles a little be to validate that *only* the
special #file/#line/function directives can be permitted for these extra
parameters? I'm struggling to think of a case where we would want to allow
something else, since there's no way to provide the values for them in a
standard call.

On Thu, Nov 2, 2017 at 5:26 PM Dave DeLong via swift-evolution < > swift-evolution@swift.org> wrote:

Hi SE,

As I’ve been using my own custom operators like “?!”, “!!”, or operators
provided by libraries (<|, ~>, etc), I’ve often wanted to capture the #file
and #line where the operators are used to make debugging their use a lot
easier.

For example, given something the unwrap-or-die operator (
https://github.com/erica/swift-evolution/blob/
2c1be72e34c970894e4ba7ed9df5cee3298d4282/proposals/XXXX-unwrap-or-die.md),
you’d want to capture the #file and #line so you could pass it on to the
underlying call to fatalError().

Or, if you’re using a custom bind operator and something goes wrong, it’d
be great to be able to capture the file and line where the operator is used
so you can quickly triage the bug in your code.

Unfortunately, Swift has the hard limit the the implementations of unary
operators may have one-and-only-one parameter, and that binary operators
may only have two parameters.

I’d like to propose a very minor change to Swift, whereby operator
implementations may have more than their one or two parameters, provided
that all subsequent parameters come with a default value. This would make
it trivial to add in #file, #line, function, etc to your operator
implementations, which you can then capture for your own purposes.

An implementation of this change, with passing tests, can be found here:
https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e
9d70bfa697

Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Yeah. There are so many pitfalls to passing parameters implicitly. It only works for exceptions because the function is annotated with throws.

Eric

···

On Nov 2, 2017, at 10:05 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

I think the use case is legitimate, but I'm uncomfortable with the proposed solution. Firstly, because for the proposed use case it's not a "default" parameter in that it's not overridable: you can't actually pass another argument. Secondly, because you wouldn't want the two parameters of an infix operator function, or the single parameter of a non-infix operator function, to allow a default value (that totally gums up the distinction between prefix, infix, and postfix operators). I agree with Eric that the use case feels like it calls for a "macro-like" solution.

On Thu, Nov 2, 2017 at 7:50 PM, Eric Summers via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I think this makes more sense as part of a hygienic macro system. These “hidden” parameters could be made available to standard functions using some sort of convention to exclude them from autocompletion.

Eric

On Nov 2, 2017, at 8:35 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like this idea as it's presented here, for the debugging/logging reasons that you stated.

Should we tighten the shackles a little be to validate that *only* the special #file/#line/function directives can be permitted for these extra parameters? I'm struggling to think of a case where we would want to allow something else, since there's no way to provide the values for them in a standard call.

On Thu, Nov 2, 2017 at 5:26 PM Dave DeLong via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi SE,

As I’ve been using my own custom operators like “?!”, “!!”, or operators provided by libraries (<|, ~>, etc), I’ve often wanted to capture the #file and #line where the operators are used to make debugging their use a lot easier.

For example, given something the unwrap-or-die operator (https://github.com/erica/swift-evolution/blob/2c1be72e34c970894e4ba7ed9df5cee3298d4282/proposals/XXXX-unwrap-or-die.md\), you’d want to capture the #file and #line so you could pass it on to the underlying call to fatalError().

Or, if you’re using a custom bind operator and something goes wrong, it’d be great to be able to capture the file and line where the operator is used so you can quickly triage the bug in your code.

Unfortunately, Swift has the hard limit the the implementations of unary operators may have one-and-only-one parameter, and that binary operators may only have two parameters.

I’d like to propose a very minor change to Swift, whereby operator implementations may have more than their one or two parameters, provided that all subsequent parameters come with a default value. This would make it trivial to add in #file, #line, function, etc to your operator implementations, which you can then capture for your own purposes.

An implementation of this change, with passing tests, can be found here: https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697

Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

That’s cool, but a hygienic macro system isn’t anywhere on the Swift roadmap.

Chris has mentioned in interviews that such a system is "a big feature that’s open-ended and requires a huge design process” which makes off-the-table for Swift 5, and (I’m guessing) unlikely for Swift 6 too.

Personally I’d like to be able to better debug my apps in Swift 4.1 rather than waiting another 2 or 3 years for a magical macro system to somehow solve this.

Dave

···

On Nov 2, 2017, at 6:50 PM, Eric Summers <eric_summers@icloud.com> wrote:

I think this makes more sense as part of a hygienic macro system. These “hidden” parameters could be made available to standard functions using some sort of convention to exclude them from autocompletion.

Eric

On Nov 2, 2017, at 8:35 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like this idea as it's presented here, for the debugging/logging reasons that you stated.

Should we tighten the shackles a little be to validate that *only* the special #file/#line/function directives can be permitted for these extra parameters? I'm struggling to think of a case where we would want to allow something else, since there's no way to provide the values for them in a standard call.

On Thu, Nov 2, 2017 at 5:26 PM Dave DeLong via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi SE,

As I’ve been using my own custom operators like “?!”, “!!”, or operators provided by libraries (<|, ~>, etc), I’ve often wanted to capture the #file and #line where the operators are used to make debugging their use a lot easier.

For example, given something the unwrap-or-die operator (https://github.com/erica/swift-evolution/blob/2c1be72e34c970894e4ba7ed9df5cee3298d4282/proposals/XXXX-unwrap-or-die.md\), you’d want to capture the #file and #line so you could pass it on to the underlying call to fatalError().

Or, if you’re using a custom bind operator and something goes wrong, it’d be great to be able to capture the file and line where the operator is used so you can quickly triage the bug in your code.

Unfortunately, Swift has the hard limit the the implementations of unary operators may have one-and-only-one parameter, and that binary operators may only have two parameters.

I’d like to propose a very minor change to Swift, whereby operator implementations may have more than their one or two parameters, provided that all subsequent parameters come with a default value. This would make it trivial to add in #file, #line, function, etc to your operator implementations, which you can then capture for your own purposes.

An implementation of this change, with passing tests, can be found here: https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697

Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Sure you can. Remember, you can call an operator with function-call syntax:

  (+)(1, 2)

We could allow you to specify the non-default parameters when you need to using this syntax:

  // Normal use:
  value !! MyError.missingValue

  // With defaulted parameters changed:
  (!!)(value, MyError.missingValue, file: someFile, line: someLine)

We could also—as part of a separate proposal, perhaps in a future version of Swift—explore a more elegant syntax for adding options to operator calls. This could be useful for things like string comparisons where you need to decide whether a comparison should be locale-aware, case-sensitive, etc.

  // Strawman syntax of possible future expansion:
  value !! MyError.missingValue #(file: someFile, line: someLine)

···

On Nov 2, 2017, at 7:05 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Firstly, because for the proposed use case it's not a "default" parameter in that it's not overridable: you can't actually pass another argument.

--
Brent Royal-Gordon
Architechies

You’re assuming somehow that this is an “easy” feature. I haven’t seen a concrete proposal, but I don’t see how adding hidden options to operators compose into the existing system.

-Chris

···

On Nov 3, 2017, at 8:40 AM, Dave DeLong via swift-evolution <swift-evolution@swift.org> wrote:

That’s cool, but a hygienic macro system isn’t anywhere on the Swift roadmap.

Chris has mentioned in interviews that such a system is "a big feature that’s open-ended and requires a huge design process” which makes off-the-table for Swift 5, and (I’m guessing) unlikely for Swift 6 too.

Personally I’d like to be able to better debug my apps in Swift 4.1 rather than waiting another 2 or 3 years for a magical macro system to somehow solve this.

Heh. I sort of feel that adding procedural macros to a language with a complex syntax and semantics like Swift doesn’t make much sense at all. I would be pretty strongly opposed to any macro system proposal unless a compelling case could be made that it would improve implementation quality by significantly simplifying the code (for example, by moving parts of the type checker into the standard library).

Slava

···

On Nov 3, 2017, at 8:40 AM, Dave DeLong via swift-evolution <swift-evolution@swift.org> wrote:

That’s cool, but a hygienic macro system isn’t anywhere on the Swift roadmap.

Chris has mentioned in interviews that such a system is "a big feature that’s open-ended and requires a huge design process” which makes off-the-table for Swift 5, and (I’m guessing) unlikely for Swift 6 too.

Personally I’d like to be able to better debug my apps in Swift 4.1 rather than waiting another 2 or 3 years for a magical macro system to somehow solve this.

That’s cool, but a hygienic macro system isn’t anywhere on the Swift roadmap.

Chris has mentioned in interviews that such a system is "a big feature that’s open-ended and requires a huge design process” which makes off-the-table for Swift 5, and (I’m guessing) unlikely for Swift 6 too.

Personally I’d like to be able to better debug my apps in Swift 4.1 rather than waiting another 2 or 3 years for a magical macro system to somehow solve this.

You’re assuming somehow that this is an “easy” feature. I haven’t seen a concrete proposal, but I don’t see how adding hidden options to operators compose into the existing system.

-Chris

It’s possible I missed something, but my attempt at implementing it only touched 3 files. One was the actual implementation, another was adapting the diagnostics messages, and the third was the tests.

I’m still new to building swift myself, but the tests all passed...

https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697

As for a formal proposal, I’ll hopefully have some time this weekend to put that together.

Can you expound some more on what you mean by hidden options to operators not composing into the existing system? I’m not sure I follow.

Dave

···

On Nov 3, 2017, at 9:59 PM, Chris Lattner <clattner@nondot.org> wrote:

On Nov 3, 2017, at 8:40 AM, Dave DeLong via swift-evolution <swift-evolution@swift.org> wrote:

If you’re looking to move forward with this proposal, you should also add a SILGen test, and an executable test too.

Slava

···

On Nov 3, 2017, at 9:16 PM, Swift via swift-evolution <swift-evolution@swift.org> wrote:

It’s possible I missed something, but my attempt at implementing it only touched 3 files. One was the actual implementation, another was adapting the diagnostics messages, and the third was the tests.

I’m still new to building swift myself, but the tests all passed...

https://github.com/davedelong/swift/commit/c65c634a59b63add0dc9df1ac8803e9d70bfa697