Add max/min to floating point types


#1

Today, one can get max/min by doing:

let max = Float.greatestFiniteMagnitude
let min = -Float.greatestFiniteMagnitude

I propose that the floating point types expose properties for max/min.

max, in particular, is used quite a lot in UI code for fixed-width layout of text. But having to spell out greatestFiniteMagnitude every time is a pain. For example…

Compare this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
      textContainer?.widthTracksTextView = true
   }
}

To this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.max, height: CGFloat.max)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width, height: CGFloat.max)
      textContainer?.widthTracksTextView = true
   }
}

The latter snippet is much more understandable (and less typing). It is more understandable because users don’t have to know exactly how floating point works in order to get the equivalent of Int.max/Int.min for CGFloat.

One of the concerns with naming them max/min is that infinity/-infinity is technically the real max/min. We could name them finiteMax/finiteMin, but I think keeping the names consistent with Int et al. is important since they serve the same purpose. Besides, I think dealing with infinity is rare in real-world usage. Those that are using infinity know that it is obviously the true max.

I think adding these floating point properties is in line with Swift 3’s goals of consistency and refinement.

Thoughts?


(Erica Sadun) #2

CGFloat has .max and .min. And if you use them, you get:
2016-06-10 13:32:14.185 Untitled Page 10[18435:13174627] This NSLayoutConstraint is being configured with a constant that exceeds internal limits. A smaller value will be substituted, but this problem should be fixed. Break on void _NSLayoutConstraintNumberExceedsLimit() to debug. This will be logged only once. This may break in the future.

-- E

···

On Jun 10, 2016, at 12:24 PM, Darren Mo via swift-evolution <swift-evolution@swift.org> wrote:

Today, one can get max/min by doing:

let max = Float.greatestFiniteMagnitude
let min = -Float.greatestFiniteMagnitude

I propose that the floating point types expose properties for max/min.

max, in particular, is used quite a lot in UI code for fixed-width layout of text. But having to spell out greatestFiniteMagnitude every time is a pain. For example…

Compare this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
      textContainer?.widthTracksTextView = true
   }
}

To this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.max, height: CGFloat.max)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width, height: CGFloat.max)
      textContainer?.widthTracksTextView = true
   }
}

The latter snippet is much more understandable (and less typing). It is more understandable because users don’t have to know exactly how floating point works in order to get the equivalent of Int.max/Int.min for CGFloat.

One of the concerns with naming them max/min is that infinity/-infinity is technically the real max/min. We could name them finiteMax/finiteMin, but I think keeping the names consistent with Int et al. is important since they serve the same purpose. Besides, I think dealing with infinity is rare in real-world usage. Those that are using infinity know that it is obviously the true max.

I think adding these floating point properties is in line with Swift 3’s goals of consistency and refinement.

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


(Xiaodi Wu) #3

Today, one can get max/min by doing:

let max = Float.greatestFiniteMagnitude
let min = -Float.greatestFiniteMagnitude

On review of the proposal for the new FloatingPoint, I too commented on the
lack of `max` and `min`. You've pointed out the issue with infinity. But
also, FLT_MIN (from your local friendly C universe and available in Swift,
obviously) is actually the smallest representable positive value, so
`Float.min` is of ambiguous meaning. It was therefore decided not to use
those words `max` and `min`.

···

On Fri, Jun 10, 2016 at 1:24 PM, Darren Mo via swift-evolution < swift-evolution@swift.org> wrote:

I propose that the floating point types expose properties for max/min.

max, in particular, is used quite a lot in UI code for fixed-width layout
of text. But having to spell out greatestFiniteMagnitude every time is a
pain. For example…

Compare this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude,
height: CGFloat.greatestFiniteMagnitude)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width,
height: CGFloat.greatestFiniteMagnitude)
      textContainer?.widthTracksTextView = true
   }
}

To this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.max, height: CGFloat.max)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width, height:
CGFloat.max)
      textContainer?.widthTracksTextView = true
   }
}

The latter snippet is much more understandable (and less typing). It is
more understandable because users don’t have to know exactly how floating
point works in order to get the equivalent of Int.max/Int.min for CGFloat.

One of the concerns with naming them max/min is that infinity/-infinity
is technically the real max/min. We could name them finiteMax/finiteMin,
but I think keeping the names consistent with Int et al. is important
since they serve the same purpose. Besides, I think dealing with infinity
is rare in real-world usage. Those that are using infinity know that it
is obviously the true max.

I think adding these floating point properties is in line with Swift 3’s
goals of consistency and refinement.

Thoughts?

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


#4

Interesting. I didn’t know that you couldn’t use CGFloat.max/CGFloat.min (aka CGFloat.greatestFiniteMagnitude/CGFloat.leastNormalMagnitude) with auto layout. Good to know.

However, I was not referring to auto layout, but to the calculation of text height based on a fixed width. Like:

let fixedWidthSize = CGSize(width: myWidth, height: CGFloat.greatestFiniteMagnitude)
let textHeight = myLabel.sizeThatFits(fixedWidthSize).height

I have done this many times before with no errors and I have seen other people do this too. (Surely you have as well!)

···

On Jun 10, 2016, at 3:32 PM, Erica Sadun <erica@ericasadun.com> wrote:

CGFloat has .max and .min. And if you use them, you get:
2016-06-10 13:32:14.185 Untitled Page 10[18435:13174627] This NSLayoutConstraint is being configured with a constant that exceeds internal limits. A smaller value will be substituted, but this problem should be fixed. Break on void _NSLayoutConstraintNumberExceedsLimit() to debug. This will be logged only once. This may break in the future.

-- E

On Jun 10, 2016, at 12:24 PM, Darren Mo via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Today, one can get max/min by doing:

let max = Float.greatestFiniteMagnitude
let min = -Float.greatestFiniteMagnitude

I propose that the floating point types expose properties for max/min.

max, in particular, is used quite a lot in UI code for fixed-width layout of text. But having to spell out greatestFiniteMagnitude every time is a pain. For example…

Compare this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
      textContainer?.widthTracksTextView = true
   }
}

To this:
extension NSTextView {
   func configureForFixedWidth() {
      minSize = NSSize.zero
      maxSize = NSSize(width: CGFloat.max, height: CGFloat.max)
      isHorizontallyResizable = false
      isVerticallyResizable = true

      textContainer?.containerSize = NSSize(width: bounds.width, height: CGFloat.max)
      textContainer?.widthTracksTextView = true
   }
}

The latter snippet is much more understandable (and less typing). It is more understandable because users don’t have to know exactly how floating point works in order to get the equivalent of Int.max/Int.min for CGFloat.

One of the concerns with naming them max/min is that infinity/-infinity is technically the real max/min. We could name them finiteMax/finiteMin, but I think keeping the names consistent with Int et al. is important since they serve the same purpose. Besides, I think dealing with infinity is rare in real-world usage. Those that are using infinity know that it is obviously the true max.

I think adding these floating point properties is in line with Swift 3’s goals of consistency and refinement.

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


(Stephen Canon) #5

It’s worth noting that this issue has been pretty extensively discussed both on- and off-list. Although convenience is good, the objections to the ambiguity of `.max` and `.min` would be *very* hard to overcome:

– They’re not actually the maximum and minimum values of the type. In particular, that `max(Float.infinity, .max)` wouldn’t be `Float.max` is pretty seriously confusing.

– The proposed `.min` doesn't align with the meaning of the "float-min-thing” in most other major languages:

  In C, FLT_MIN is the smallest positive normal
  In C++, std::numeric_limits<float>::min() is the smallest positive normal
  In Python, sys.float_info.min is the smallest positive normal
  In C#, .minValue is documented as “the smallest possible value”, but is actually the value you want, rather than the documented –infinity.
  In Java, MIN_VALUE is the smallest positive value (including subnormals)
  In Ruby, MIN is the smallest positive normal
  In R, double.xmin is the smallest positive normal
  In MATLAB, realmin is the smallest positive normal
  Actually, Rust is the only language I know of where `MIN` is the value you want *and* correctly documented as such.

All that’s not to say that Swift can’t do this, but there’s a lot of opportunity for confusion on this point, and having a very explicit name isn’t really a bad thing.

– There is also some concern that having `.min` and `.max` with the same names as on Integer types would lead people to try to use them the same way in code, which generally isn’t going to work the way users expect.

– Steve

···

On Jun 10, 2016, at 12:38 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Fri, Jun 10, 2016 at 1:24 PM, Darren Mo via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Today, one can get max/min by doing:

let max = Float.greatestFiniteMagnitude
let min = -Float.greatestFiniteMagnitude

On review of the proposal for the new FloatingPoint, I too commented on the lack of `max` and `min`. You've pointed out the issue with infinity. But also, FLT_MIN (from your local friendly C universe and available in Swift, obviously) is actually the smallest representable positive value, so `Float.min` is of ambiguous meaning. It was therefore decided not to use those words `max` and `min`.


#6

Thanks for the summary of the arguments against max/min! Comments inline.

Today, one can get max/min by doing:

let max = Float.greatestFiniteMagnitude
let min = -Float.greatestFiniteMagnitude

On review of the proposal for the new FloatingPoint, I too commented on the lack of `max` and `min`. You've pointed out the issue with infinity. But also, FLT_MIN (from your local friendly C universe and available in Swift, obviously) is actually the smallest representable positive value, so `Float.min` is of ambiguous meaning. It was therefore decided not to use those words `max` and `min`.

It’s worth noting that this issue has been pretty extensively discussed both on- and off-list. Although convenience is good, the objections to the ambiguity of `.max` and `.min` would be *very* hard to overcome:

– They’re not actually the maximum and minimum values of the type. In particular, that `max(Float.infinity, .max)` wouldn’t be `Float.max` is pretty seriously confusing.

Infinity is a special value. I would argue that people who use infinity know exactly what they are doing and would not be thrown by Float.infinity being greater than Float.max. I am willing to bet that most regular users don’t even know that infinity can be represented since it is rarely needed in real-world usage.

– The proposed `.min` doesn't align with the meaning of the "float-min-thing” in most other major languages:

  In C, FLT_MIN is the smallest positive normal
  In C++, std::numeric_limits<float>::min() is the smallest positive normal
  In Python, sys.float_info.min is the smallest positive normal
  In C#, .minValue is documented as “the smallest possible value”, but is actually the value you want, rather than the documented –infinity.
  In Java, MIN_VALUE is the smallest positive value (including subnormals)
  In Ruby, MIN is the smallest positive normal
  In R, double.xmin is the smallest positive normal
  In MATLAB, realmin is the smallest positive normal
  Actually, Rust is the only language I know of where `MIN` is the value you want *and* correctly documented as such.

All that’s not to say that Swift can’t do this, but there’s a lot of opportunity for confusion on this point, and having a very explicit name isn’t really a bad thing.

I think if we have .min *and* .leastNormalMagnitude *and* .leastNonzeroMagnitude, then there is no ambiguity or confusion. Moreover, I would suspect most people naturally think of .min as the most-negative number that can be represented (c.f. the top search results for “FLT_MIN”). If this is true, then we have an opportunity to align the language with the user’s true desires instead of just following precedent.

– There is also some concern that having `.min` and `.max` with the same names as on Integer types would lead people to try to use them the same way in code, which generally isn’t going to work the way users expect.

What is an example of this?

···

On Jun 10, 2016, at 6:51 PM, Stephen Canon <scanon@apple.com> wrote:
On Jun 10, 2016, at 12:38 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Fri, Jun 10, 2016 at 1:24 PM, Darren Mo via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

– Steve


(David Hart) #7

Agree with all you said

···

On 11 Jun 2016, at 02:20, Darren Mo via swift-evolution <swift-evolution@swift.org> wrote:

Thanks for the summary of the arguments against max/min! Comments inline.

On Jun 10, 2016, at 6:51 PM, Stephen Canon <scanon@apple.com> wrote:

On Jun 10, 2016, at 12:38 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Fri, Jun 10, 2016 at 1:24 PM, Darren Mo via swift-evolution <swift-evolution@swift.org> wrote:
Today, one can get max/min by doing:

let max = Float.greatestFiniteMagnitude
let min = -Float.greatestFiniteMagnitude

On review of the proposal for the new FloatingPoint, I too commented on the lack of `max` and `min`. You've pointed out the issue with infinity. But also, FLT_MIN (from your local friendly C universe and available in Swift, obviously) is actually the smallest representable positive value, so `Float.min` is of ambiguous meaning. It was therefore decided not to use those words `max` and `min`.

It’s worth noting that this issue has been pretty extensively discussed both on- and off-list. Although convenience is good, the objections to the ambiguity of `.max` and `.min` would be *very* hard to overcome:

– They’re not actually the maximum and minimum values of the type. In particular, that `max(Float.infinity, .max)` wouldn’t be `Float.max` is pretty seriously confusing.

Infinity is a special value. I would argue that people who use infinity know exactly what they are doing and would not be thrown by Float.infinity being greater than Float.max. I am willing to bet that most regular users don’t even know that infinity can be represented since it is rarely needed in real-world usage.

– The proposed `.min` doesn't align with the meaning of the "float-min-thing” in most other major languages:

  In C, FLT_MIN is the smallest positive normal
  In C++, std::numeric_limits<float>::min() is the smallest positive normal
  In Python, sys.float_info.min is the smallest positive normal
  In C#, .minValue is documented as “the smallest possible value”, but is actually the value you want, rather than the documented –infinity.
  In Java, MIN_VALUE is the smallest positive value (including subnormals)
  In Ruby, MIN is the smallest positive normal
  In R, double.xmin is the smallest positive normal
  In MATLAB, realmin is the smallest positive normal
  Actually, Rust is the only language I know of where `MIN` is the value you want *and* correctly documented as such.

All that’s not to say that Swift can’t do this, but there’s a lot of opportunity for confusion on this point, and having a very explicit name isn’t really a bad thing.

I think if we have .min *and* .leastNormalMagnitude *and* .leastNonzeroMagnitude, then there is no ambiguity or confusion. Moreover, I would suspect most people naturally think of .min as the most-negative number that can be represented (c.f. the top search results for “FLT_MIN”). If this is true, then we have an opportunity to align the language with the user’s true desires instead of just following precedent.

– There is also some concern that having `.min` and `.max` with the same names as on Integer types would lead people to try to use them the same way in code, which generally isn’t going to work the way users expect.

What is an example of this?

– Steve

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


(Stephen Canon) #8

For clarity, what use cases do you have in mind where the largest finite value is more appropriate than infinity?

···

On Jun 10, 2016, at 5:20 PM, Darren Mo <darren.mo@me.com> wrote:

– They’re not actually the maximum and minimum values of the type. In particular, that `max(Float.infinity, .max)` wouldn’t be `Float.max` is pretty seriously confusing.

Infinity is a special value. I would argue that people who use infinity know exactly what they are doing and would not be thrown by Float.infinity being greater than Float.max. I am willing to bet that most regular users don’t even know that infinity can be represented since it is rarely needed in real-world usage.


#9

That… is a very good question.

My main use case was laying out fixed-width text. In the Objective-C days, I would use CGFLOAT_MAX. I guess when I started to write the same code in Swift, I didn’t stop to think about whether there was a better value. Now thanks to you, I see that CGFloat.infinity is the clearest and most appropriate value.

Proposal cancelled. Thanks! :slight_smile:

···

On Jun 12, 2016, at 11:35 PM, Stephen Canon <scanon@apple.com> wrote:

On Jun 10, 2016, at 5:20 PM, Darren Mo <darren.mo@me.com <mailto:darren.mo@me.com>> wrote:

– They’re not actually the maximum and minimum values of the type. In particular, that `max(Float.infinity, .max)` wouldn’t be `Float.max` is pretty seriously confusing.

Infinity is a special value. I would argue that people who use infinity know exactly what they are doing and would not be thrown by Float.infinity being greater than Float.max. I am willing to bet that most regular users don’t even know that infinity can be represented since it is rarely needed in real-world usage.

For clarity, what use cases do you have in mind where the largest finite value is more appropriate than infinity?