Skip to content
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

SI-9656 Distinguish Numeric with step type #5175

Merged
merged 1 commit into from May 24, 2016

Conversation

som-snytt
Copy link
Contributor

@som-snytt som-snytt commented May 18, 2016

Shorthand toString for Range and NumericRange.

scala> 1 to 10 by 2
res0: scala.collection.immutable.Range = inexact Range 1 to 10 by 2

scala> 1 until 1 by 2
res1: scala.collection.immutable.Range = empty Range 1 until 1 by 2

scala> .1 to 1.0 by .1
<console>:1: error: ';' expected but double literal found.
res1.1 to 1.0 by .1
    ^

scala> 0.1 to 1.0 by .1
res2: scala.collection.immutable.NumericRange[Double] = NumericRange 0.1 to 1.0 by 0.1

scala> Range.Double(.1, 1.0, .1)
res3: scala.collection.immutable.NumericRange[Double] = NumericRange 0.1 until 1.0 by 0.1 (using NumericRange 0.1 until 1.0 by 0.1 of BigDecimal)

scala> 0.0 to 1.0
res4: Range.Partial[Double,scala.collection.immutable.NumericRange[Double]] = Range requires step

scala> 0 to 1
res5: scala.collection.immutable.Range.Inclusive = Range 0 to 1

No parens because Range(0 to 1) looks like a factory but just gives a confusing error message.

@scala-jenkins scala-jenkins added this to the 2.12.0-M5 milestone May 18, 2016
val preposition = if (isInclusive) "to" else "until"
f"$start $preposition $end${
if (step == 1) "" else f" by $step"
}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to use f instead of s? f will pull in a lot of code in Scala.js code bases that do not otherwise use String.format.

Also, I'm not convinced the nested interpolator is more readable than:

s"$start $preposition $end" + (if (step == 1) "" else s" by $step")

Copy link
Contributor Author

@som-snytt som-snytt May 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a finger twitch. At first I wrote f"$start%d", I think. But it's interesting to hear the JS consequences. f-interpolator needs to special case if it's just appending strings. It already detects constant results.

For some reason, I really want the multiline interpolated expression to be readable, but that hasn't actually happened yet.

ps) created an issue for f"". https://issues.scala-lang.org/browse/SI-9784

@som-snytt
Copy link
Contributor Author

Observes @sjrd observations, and adds whether a range is empty or inexact.

Squashed to recognize @stevorobs3 initiative.

@som-snytt
Copy link
Contributor Author

Also fixes the bogus hashCode doc. You know your doc mechanism is severely broken if that can happen. Hint: the double-star convention is actually broken.

@adriaanm
Copy link
Contributor

/rebuild

@som-snytt
Copy link
Contributor Author

Thanks @adriaanm . I just sent the error to my colleague who was dealing with groovy exceptions in gradle last week. I said, "It's easy to make fun of things when they don't work, so that's what I'll do."

@adriaanm
Copy link
Contributor

Pleasure! This time we squirreled away too many snapshots. You never know when they might come in handy, I guess.

@szeiger
Copy link
Member

szeiger commented May 19, 2016

I like this version. It gives a nice readable output like #5001 while preserving the distinction between Range and NumericRange. LGTM.

@soc
Copy link
Member

soc commented May 19, 2016

I'm a bit concerned as this change makes Range's toString completely different and inconsistent compared to all other collection classes. I know many people who write a collection in the REPL and expect that the toString gives them a reasonable hint about the class involved.

Wouldn't it be possible to wrap the output in Range()?

@som-snytt
Copy link
Contributor Author

How about empty|inexact NumericRange 0 days until 0 days by 1 second of FiniteDuration. I'm open to better word for inexact, to mean the step doesn't cover the range exactly. It can't be both empty and inexact.

@soc
Copy link
Member

soc commented May 19, 2016

NumericRange[FiniteDuration](0 days until 0 days by 1 second) <empty>?

@som-snytt
Copy link
Contributor Author

The idea was just to distinguish what the step is.

scala> 0.0 until 2.0 by 0.1
res0: scala.collection.immutable.NumericRange[Double] = NumericRange 0.0 until 2.0 by 0.1 of Double

scala> 0.0 until 2.0 by 1
res1: scala.collection.immutable.NumericRange[Double] = NumericRange 0.0 until 2.0

scala> List(1,2,3)
res2: List[Int] = List(1, 2, 3)

This could be nicer:

scala> 0.0 until 0.0
res3: Range.Partial[Double,scala.collection.immutable.NumericRange[Double]] = scala.collection.immutable.Range$Partial@498c535d

@som-snytt
Copy link
Contributor Author

Actually, I'm not convinced by "step of". It would be better if the mapRange instance overrode toString to indicate what it is really doing, namely, (precise) stepping using the underlying range.

Also, strings are typically ambiguous:

scala> List(BigDecimal("0.1"))
res10: List[scala.math.BigDecimal] = List(0.1)

scala> List(0.1)
res11: List[Double] = List(0.1)

@som-snytt
Copy link
Contributor Author

So I didn't even realize that you don't normally get precise stepping goodness. Possibly the comments about it not being complete mean you must opt in:

scala> 0.0 to 1.0 by 0.1
res0: scala.collection.immutable.NumericRange[Double] = NumericRange 0.0 to 1.0 by 0.1

scala> .toList
res1: List[Double] = List(0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999)

scala> Range.Double(0.0, 1.0, 0.1)
res2: scala.collection.immutable.NumericRange[Double] = NumericRange 0.0 until 1.0 by 0.1 (NumericRange 0.0 until 1.0 by 0.1 of BigDecimal)

scala> .toList
res3: List[Double] = List(0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9)

Maybe this is an improvement:

scala> 0.0 to 1.0
res4: Range.Partial[Double,scala.collection.immutable.NumericRange[Double]] = scala.collection.immutable.Range$Partial@112c2930 Range requires step

For Range and NumericRange, toString will indicate the step
if it is not 1.

Additionally, indicate empty ranges and ranges which are not
"exact".

For a "mapped" range, used by `Range.Double`, toString
includes the underlying range and the simple type of the step
(to distinguish Double from BigDecimal).
@som-snytt
Copy link
Contributor Author

Edited the first comment.

@szeiger
Copy link
Member

szeiger commented May 20, 2016

Marking as on-hold for now in case you want to make further changes. I think the current state is acceptable but the proposed changes would also be fine with me.

@szeiger szeiger self-assigned this May 20, 2016
@som-snytt
Copy link
Contributor Author

I believe I'm done. As in done done.

@adriaanm adriaanm removed the on-hold label May 24, 2016
@szeiger
Copy link
Member

szeiger commented May 24, 2016

LGTM

@som-snytt som-snytt deleted the issue/9656-range-toString branch May 31, 2016 16:54
@adriaanm adriaanm added 2.12 and removed 2.12 labels Oct 29, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants