I want to thank the community for the previous feedback for SE-0177
and also address the issue of the proposal being sent back for revisions.
The current status being "Returned for revisions" reflects the detailed
design section being incomplete and not working against the latest Swift 4
snapshot.
Another reason mentioned by Ben Cohen was that the proposal did not take
advantage of `RangeExpression` and take advantage of a generic
implementation.
This has been added in the "Alternatives Considered" section in the pull
request that
is open now but I personally favor the generic approach despite the added
cost of extending `RangeExpression` enough to make the implementation
possible.
In short, at this time `RangeExpression` is lacking functionality to
implement `clamp(to:)`
in a generic fashion so if the community is in favor of extending
`RangeExpression` I am
more than happy to go with a generic implementation rather than the current
concrete
implementation that is in the proposal pull request now.
I have tried to address these issues and expand the proposal in this pull
request here:
Thank you all so much for the feedback and support, I look forward to
exploring where
we can go with this proposal and making Swift 4 the best release yet.
RangeExpression is a protocol for all ranges, including partial and
unbounded ranges. It would not make sense for such a protocol to have an
upper bound or a lower bound.
The way in which your proposal could dovetail with RangeExpression is for
it to add a requirement to that protocol named `clamping(_:)`. Each type of
range (_, closed, countable, countable closed, partial from, partial up to,
etc.) would then implement that requirement. Then, implementations of
`clamped(to:)` could call `clamping(_:)`. Although, at that point, it would
be an open question whether having both clamped(to:) and clamping(_:) would
be useful. I would be inclined to think that at most one of these is
necessary, and only the latter is compatible with a protocol-based approach.
I remain unconvinced, however, that this API meets the very high bar for
standard library inclusion.
ยทยทยท
On Tue, Jun 27, 2017 at 20:57 Nicholas Maccharoli via swift-evolution < swift-evolution@swift.org> wrote:
Swift Evolution,
I want to thank the community for the previous feedback for SE-0177
and also address the issue of the proposal being sent back for revisions.
The current status being "Returned for revisions" reflects the detailed
design section being incomplete and not working against the latest Swift 4
snapshot.
Another reason mentioned by Ben Cohen was that the proposal did not take
advantage of `RangeExpression` and take advantage of a generic
implementation.
This has been added in the "Alternatives Considered" section in the pull
request that
is open now but I personally favor the generic approach despite the added
cost of extending `RangeExpression` enough to make the implementation
possible.
In short, at this time `RangeExpression` is lacking functionality to
implement `clamp(to:)`
in a generic fashion so if the community is in favor of extending
`RangeExpression` I am
more than happy to go with a generic implementation rather than the
current concrete
implementation that is in the proposal pull request now.
I have tried to address these issues and expand the proposal in this pull
request here:
Thank you all so much for the feedback and support, I look forward to
exploring where
we can go with this proposal and making Swift 4 the best release yet.
Well, as to if this meets the standard thats something more subjective than
objective so
after hearing a few opinions (hopefully differing) the community could
piece together
a cleaner image of if this is a good idea or not.
From the previous feedback on the mailing list there were people in favor
and Ben from the
core swift team gave some feedback here saying:
The core team reviewed this proposal and are returning the proposal for
revision. This is a welcome proposal in principal, but should be revised to
account for the recent addition of the RangeExpression protocol, in order
to allow for clamping over different kinds of range expression.
So since the proposal is being "Returned for revisions" I wanted to propose
those revisions here:
- Nick
ยทยทยท
On Wed, Jun 28, 2017 at 1:13 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
RangeExpression is a protocol for all ranges, including partial and
unbounded ranges. It would not make sense for such a protocol to have an
upper bound or a lower bound.
The way in which your proposal could dovetail with RangeExpression is for
it to add a requirement to that protocol named `clamping(_:)`. Each type of
range (_, closed, countable, countable closed, partial from, partial up to,
etc.) would then implement that requirement. Then, implementations of
`clamped(to:)` could call `clamping(_:)`. Although, at that point, it would
be an open question whether having both clamped(to:) and clamping(_:) would
be useful. I would be inclined to think that at most one of these is
necessary, and only the latter is compatible with a protocol-based approach.
I remain unconvinced, however, that this API meets the very high bar for
standard library inclusion.
On Tue, Jun 27, 2017 at 20:57 Nicholas Maccharoli via swift-evolution < > swift-evolution@swift.org> wrote:
Swift Evolution,
I want to thank the community for the previous feedback for SE-0177
and also address the issue of the proposal being sent back for revisions.
The current status being "Returned for revisions" reflects the detailed
design section being incomplete and not working against the latest Swift
4
snapshot.
Another reason mentioned by Ben Cohen was that the proposal did not take
advantage of `RangeExpression` and take advantage of a generic
implementation.
This has been added in the "Alternatives Considered" section in the pull
request that
is open now but I personally favor the generic approach despite the added
cost of extending `RangeExpression` enough to make the implementation
possible.
In short, at this time `RangeExpression` is lacking functionality to
implement `clamp(to:)`
in a generic fashion so if the community is in favor of extending
`RangeExpression` I am
more than happy to go with a generic implementation rather than the
current concrete
implementation that is in the proposal pull request now.
I have tried to address these issues and expand the proposal in this pull
request here:
Thank you all so much for the feedback and support, I look forward to
exploring where
we can go with this proposal and making Swift 4 the best release yet.
Sorry, it's been a while but I don't understand your reply. As far as I can
tell, nothing has changed since June: the revised proposal continues to
propose an API that is not protocol-based, and the alternative continues to
propose additions to RangeExpression that do not make sense, as partial
ranges do not have both upper and lower bounds.
As I wrote in June, _even if clamping is determined to be a suitable
addition to the standard library_, your revision appears not to address the
core team feedback. I suggested one way in which you could revise your
proposal to address that issue--namely, a `clamping` requirement on
RangeExpression. However, I do not see where you have addressed this
feedback. What am I missing?
ยทยทยท
On Wed, Jul 19, 2017 at 22:48 Nicholas Maccharoli <nmaccharoli@gmail.com> wrote:
Xiaodi,
Sorry for the delay and thanks for replying!
Well, as to if this meets the standard thats something more subjective
than objective so
after hearing a few opinions (hopefully differing) the community could
piece together
a cleaner image of if this is a good idea or not.
From the previous feedback on the mailing list there were people in favor
and Ben from the
core swift team gave some feedback here saying:
The core team reviewed this proposal and are returning the proposal for
revision. This is a welcome proposal in principal, but should be revised to
account for the recent addition of the RangeExpression protocol, in
order to allow for clamping over different kinds of range expression.
So since the proposal is being "Returned for revisions" I wanted to
propose those revisions here:
On Wed, Jun 28, 2017 at 1:13 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
RangeExpression is a protocol for all ranges, including partial and
unbounded ranges. It would not make sense for such a protocol to have an
upper bound or a lower bound.
The way in which your proposal could dovetail with RangeExpression is for
it to add a requirement to that protocol named `clamping(_:)`. Each type of
range (_, closed, countable, countable closed, partial from, partial up to,
etc.) would then implement that requirement. Then, implementations of
`clamped(to:)` could call `clamping(_:)`. Although, at that point, it would
be an open question whether having both clamped(to:) and clamping(_:) would
be useful. I would be inclined to think that at most one of these is
necessary, and only the latter is compatible with a protocol-based approach.
I remain unconvinced, however, that this API meets the very high bar for
standard library inclusion.
On Tue, Jun 27, 2017 at 20:57 Nicholas Maccharoli via swift-evolution < >> swift-evolution@swift.org> wrote:
Swift Evolution,
I want to thank the community for the previous feedback for SE-0177
and also address the issue of the proposal being sent back for
revisions.
The current status being "Returned for revisions" reflects the detailed
design section being incomplete and not working against the latest Swift
4
snapshot.
Another reason mentioned by Ben Cohen was that the proposal did not take
advantage of `RangeExpression` and take advantage of a generic
implementation.
This has been added in the "Alternatives Considered" section in the pull
request that
is open now but I personally favor the generic approach despite the
added cost of extending `RangeExpression` enough to make the implementation
possible.
In short, at this time `RangeExpression` is lacking functionality to
implement `clamp(to:)`
in a generic fashion so if the community is in favor of extending
`RangeExpression` I am
more than happy to go with a generic implementation rather than the
current concrete
implementation that is in the proposal pull request now.
I have tried to address these issues and expand the proposal in this
pull request here:
Thank you all so much for the feedback and support, I look forward to
exploring where
we can go with this proposal and making Swift 4 the best release yet.
It would be great to see this included โ It's something that I seem to encounter on a near daily basis.
I've attempted my own version with the suggestions of @xwu. A deviation from the original proposal is to constrain the ClosedRange and PartialRangeUpTo variants to FloatingPoint types. clamping to something like (0..<0) would be undefined anyhow, but FloatingPoint at least allows us to return .nan in this case โ so I think this might make more sense than Strideable which doesn't seem to have the concept of a minimum stride as far as I can tell.
public func clamped<T>(_ lowerBound: T, _ upperBound: T, _ value: T) -> T where T : Comparable {
return min(upperBound, max(lowerBound, value))
}
Which seems like it would fit alongside the existing min and max implementations quite neatly to me, but I understand there has been some discussion which discourages this direction.
Either way, it would be good to get a solution of some sort.
Looking a little further, for the the Range and PartialRangeUpTo variants it would in fact make sense to constrain them to Strideable. However, it does seem we also need the concept of .nextDown from Decimal added to the Ints.
Perhaps a new protocol, Decrementable could be created which can then have all the Ints, Decimals, etc. conforming to it.
This would allow for:
extension Range: ClampableRangeExpression where Bound: Strideable & Decrementable {
func clamping(_ value: Bound) -> Bound {
return (lowerBound...).clamping((..<upperBound).clamping(value))
}
}
extension PartialRangeUpTo: ClampableRangeExpression where Bound: Strideable & Decrementable {
func clamping(_ value: Bound) -> Bound {
return (...upperBound.nextDown).clamping(value)
}
}
// Decrementable protocol
protocol Decrementable {
var nextDown: Self { get }
}
// Conformance for all the Decimals...
extension Decimal: Decrementable {}
extension CGFloat: Decrementable {}
// ...
// Conformance for all the Ints...
extension Int: Decrementable {
var nextDown: Int { return advanced(by: -1) }
}
// ...
Hi, it doesn't look like there is much activity on this โ but for the record:
Having thought about this further and playing around it with it myself I think there's definitely some design issues that need working out.
Specifically, the case of Int types and their Range and PartialRangeUpTo implementations have an unfortunate edge case which is, if you specify a Range / PartialRangeUpTo where the upper and lower bounds (explicit or implicitly in the case of PartialRangeUpTo ) are equal, then there is the risk of a runtime error. What's more, this will happen pretty frequently, and in the case of using clamping(_:) to 'safely' access elements of an array, a zero length array will cause the very runtime error that was meant to be avoided!
Of course, one could guard against this and just return the lower bound, but this seems imprecise.
With that in mind, I would avoid implementation of clamped for Range / PartialRangeUpTo specifically for Ints, and I would agree that without support for the full set of ranges, they shouldn't be supported at all.
Here, I would vote to falling back to a simple clamped(min:,max:_) free function to sit alongside min(_:_:) and max(_:_:) in the stdlib.
I do believe there is a case for a clamped function for FloatingPoint types, however. This is able to fit the full range of RangeExpression types maintaining mathematical integrity (as far as I can tell). It also seems to gel well with the frequent need/use for clamped functions in mathematical and computer graphics applications. It also simplifies the implementation.