-
Notifications
You must be signed in to change notification settings - Fork 1k
SIP-NN - Allow referring to other arguments in default parameters #653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
--- | ||
layout: sip | ||
disqus: true | ||
title: SIP-NN - Allow referring to other arguments in default parameters | ||
--- | ||
|
||
**By: Pathikrit Bhowmick** | ||
|
||
## History | ||
|
||
| Date | Version | | ||
|---------------|------------------| | ||
| Jan 11th 2017 | Initial Draft | | ||
| Jan 12th 2017 | Initial Feedback | | ||
| Jan 16th 2017 | Minor Changes | | ||
|
||
## Introduction | ||
Currently there is no way to refer to other arguments in the default parameters list: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding a motivation section that showcases why this is useful would be great! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Working on it... |
||
|
||
Does not compile: | ||
```scala | ||
def substring(s: String, start: Int = 0, end: Int = s.length): String | ||
``` | ||
|
||
The workaround to achieve this is by using a curried-function: | ||
```scala | ||
def substring(s: String, start: Int = 0)(end: Int = s.length): String | ||
``` | ||
|
||
However, the above workaround is not always suitable in all situations since you may not want a curried function. | ||
|
||
The other more verbose alternative is by overloading: | ||
```scala | ||
def substring(s: String, start: Int): String | ||
= substring(s, start = 0, end = s.length) | ||
def substring(s: String, start: Int = 0, end: Int): String | ||
``` | ||
|
||
The above is quite verbose as it required 1 extra function definition per argument that refers other args. | ||
|
||
### Proposal | ||
Allow to refer to ***any*** parameters in the same (or left) curried parameter list: | ||
```scala | ||
def substring(s: String, start: Int = 0, end: Int = s.length) // Legal | ||
def substring(start: Int = 0, end: Int = s.length, s: String) // Legal !!! | ||
def substring(s: String, start: Int = 0)(end: Int = s.length) // Legal (works currently) | ||
def substring(start: Int = 0, end: Int = s.length)(s: String) // Illegal | ||
``` | ||
|
||
The same applies for class arguments: | ||
```scala | ||
class Substring(s: String, start: Int = 0, end: Int = s.length) // Legal | ||
class Substring(start: Int = 0, end: Int = s.length, s: String) // Legal | ||
class Substring(s: String, start: Int = 0)(end: Int = s.length) // Legal | ||
class Substring(start: Int = 0, end: Int = s.length)(s: String) // Illegal | ||
``` | ||
|
||
We should also be able to refer to ***multiple*** parameters: | ||
```scala | ||
def binarySearch(start: Int, end: Int, middle: Int = (start + end)/2) // Legal | ||
``` | ||
|
||
# Motivating examples: | ||
|
||
TBD | ||
|
||
## Interactions with other syntax | ||
|
||
#### Partially Applied Functions: | ||
Works as expected: | ||
```scala | ||
def substring(s: String, start: Int = 0, end: Int = s.length) | ||
|
||
substring(_, start = 0, end = 5) // Legal | ||
substring(_, end = 5) // Legal (start = 0) | ||
substring(_, start = 5) // Legal (same as s => substring(s, start = 5, end = s.length) | ||
``` | ||
|
||
#### Multiple Implicit Parameters | ||
[Multiple implicit parameters](https://github.com/scala/scala.github.com/pull/520) should also be allowed to refer to one another (left to right): | ||
```scala | ||
def codec[A](data: A)(implicit encoder: Encoder[A])(implicit decoder: Decoder[A] = encoder.reverse) // Legal | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I missing something, or this is not legal Scala syntax (multiple implicit parameter lists)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that what @pathikrit means is that this change should also be valid for implicit parameter lists. That would marry well with this SIP. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the link to the PR |
||
``` | ||
|
||
#### Referring to type members: | ||
The default parameters should be able to refer to type members of other arguments e.g.: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section seems orthogonal to the target of this PR (this issue was raised by @olafurpg). I think that the good approach here would be to create another SIP that keeps track of this feature, since I would expect the implementation of this to be different to the one requested. WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know much about scalac internals to comment. Maybe it is very similar (then keep 1 SIP) and maybe it isn't (2 SIPs). Can someone more familiar with scalac comment? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think they're similar in spirit, but I'm sure they're distinct in the implementation. To avoid a situation where the committee pushes you back a month to go look into and document this, I would keep it in. At the very least they can ask you to split it out - you can then drop it or pursue it as a separate SIP. |
||
```scala | ||
trait Codec { | ||
type Input | ||
type Output | ||
} | ||
|
||
def codec(codec: Codec, in: codec.Input, out: codec.Output) // Legal !!! | ||
``` | ||
|
||
### Other languages | ||
The following languages allow referring to previously declared arguments in the function signature: | ||
* [CoffeeScript](http://coffeescript.org/) | ||
* [Kotlin](http://kotlinlang.org) | ||
* [TypeScript](https://www.typescriptlang.org/) | ||
|
||
AFAIK, there are no major languages where referring to parameters declared to the ***right*** is allowed. | ||
|
||
### Discussions | ||
[Scala Lang Forum](https://contributors.scala-lang.org/t/refer-to-previous-argument-in-default-argument-list/215/6) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be useful to have an implementation sketch to accompany this SIP. In my opinion, information about why this proposal hasn't been implemented yet and why it is feasible would help the potential discussion during one of the upcoming SIP meetings. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've been looking into this today and will submit an implementation sketch very soon, along with a design document /cc @pathikrit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Other arguments" or "previous arguments"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe previous I guess if other is not feasible (circle dependencies)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually write "Allow references to left arguments of the same list in default parameters" if @pathikrit agrees with my previous analysis that doing it for all the arguments is unfeasible. 😄