Skip to content

Correct example of expanded using clauses in Using Clauses guide #17011

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

Merged
merged 1 commit into from
Feb 27, 2023

Conversation

mgyucht
Copy link
Contributor

@mgyucht mgyucht commented Feb 26, 2023

The example of how using clauses are expanded by the compiler is not correct. descending accepts a context parameter for an ordering of the elements of the list, not an ordering of lists. I just tested this out in the repl:

scala> trait Ord[T]:
     |   def compare(x: T, y: T): Int
     |   extension (x: T)
     |     def < (y: T) = compare(x, y) < 0
     |     def > (y: T) = compare(x, y) > 0
     |
// defined trait Ord

scala> def max[T](x: T, y: T)(using ord: Ord[T]): T =
     |   if ord.compare(x, y) < 0 then y else x
     |
def max[T](x: T, y: T)(using ord: Ord[T]): T

scala> def maximum[T](xs: List[T])(using Ord[T]): T =
     |   xs.reduceLeft(max)
     |
def maximum[T](xs: List[T])(using x$2: Ord[T]): T

scala> given intOrd: Ord[Int] with
     |   def compare(x: Int, y: Int) =
     |     if x < y then -1 else if x > y then +1 else 0
     |
     | given listOrd[T](using ord: Ord[T]): Ord[List[T]] with
     |
     |   def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match
     |     case (Nil, Nil) => 0
     |     case (Nil, _) => -1
     |     case (_, Nil) => +1
     |     case (x :: xs1, y :: ys1) =>
     |       val fst = ord.compare(x, y)
     |       if fst != 0 then fst else compare(xs1, ys1)
     |
// defined object intOrd
// defined class listOrd
def listOrd[T](using ord: Ord[T]): listOrd[T]

scala> val xs = List(1, 10, 2, 9, 3, 8, 4, 7, 5, 6)
val xs: List[Int] = List(1, 10, 2, 9, 3, 8, 4, 7, 5, 6)

scala> maximum(xs)
val res0: Int = 10

scala> def descending[T](using asc: Ord[T]): Ord[T] = new Ord[T]:
     |   def compare(x: T, y: T) = asc.compare(y, x)
     |
     | def minimum[T](xs: List[T])(using Ord[T]) =
     |   maximum(xs)(using descending)
     |
def descending[T](using asc: Ord[T]): Ord[T]
def minimum[T](xs: List[T])(using x$2: Ord[T]): T

scala> maximum(xs)(using descending)
val res1: Int = 1

scala> maximum(xs)(using descending(using intOrd))
val res2: Int = 1

scala> maximum(xs)(using descending(using listOrd))
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |maximum(xs)(using descending(using listOrd))
  |                                   ^^^^^^^
  |                                   Found:    listOrd[Int]
  |                                   Required: Ord[Int]
  |
  | longer explanation available when compiling with `-explain`
1 error found

I have just signed the CLA.

The example of how using clauses are expanded by the compiler is not correct. `descending` accepts a context parameter for an ordering of the elements of the list, not an ordering of the list itself. I just tested this out in the repl:

```scala
scala> trait Ord[T]:
     |   def compare(x: T, y: T): Int
     |   extension (x: T)
     |     def < (y: T) = compare(x, y) < 0
     |     def > (y: T) = compare(x, y) > 0
     |
// defined trait Ord

scala> def max[T](x: T, y: T)(using ord: Ord[T]): T =
     |   if ord.compare(x, y) < 0 then y else x
     |
def max[T](x: T, y: T)(using ord: Ord[T]): T

scala> def maximum[T](xs: List[T])(using Ord[T]): T =
     |   xs.reduceLeft(max)
     |
def maximum[T](xs: List[T])(using x$2: Ord[T]): T

scala> given intOrd: Ord[Int] with
     |   def compare(x: Int, y: Int) =
     |     if x < y then -1 else if x > y then +1 else 0
     |
     | given listOrd[T](using ord: Ord[T]): Ord[List[T]] with
     |
     |   def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match
     |     case (Nil, Nil) => 0
     |     case (Nil, _) => -1
     |     case (_, Nil) => +1
     |     case (x :: xs1, y :: ys1) =>
     |       val fst = ord.compare(x, y)
     |       if fst != 0 then fst else compare(xs1, ys1)
     |
// defined object intOrd
// defined class listOrd
def listOrd[T](using ord: Ord[T]): listOrd[T]

scala> val xs = List(1, 10, 2, 9, 3, 8, 4, 7, 5, 6)
val xs: List[Int] = List(1, 10, 2, 9, 3, 8, 4, 7, 5, 6)

scala> maximum(xs)
val res0: Int = 10

scala> def descending[T](using asc: Ord[T]): Ord[T] = new Ord[T]:
     |   def compare(x: T, y: T) = asc.compare(y, x)
     |
     | def minimum[T](xs: List[T])(using Ord[T]) =
     |   maximum(xs)(using descending)
     |
def descending[T](using asc: Ord[T]): Ord[T]
def minimum[T](xs: List[T])(using x$2: Ord[T]): T

scala> maximum(xs)(using descending)
val res1: Int = 1

scala> maximum(xs)(using descending(using intOrd))
val res2: Int = 1

scala> maximum(xs)(using descending(using listOrd))
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |maximum(xs)(using descending(using listOrd))
  |                                   ^^^^^^^
  |                                   Found:    listOrd[Int]
  |                                   Required: Ord[Int]
  |
  | longer explanation available when compiling with `-explain`
1 error found
```
@mgyucht mgyucht changed the title Correct example of expanded using clauses Correct example of expanded using clauses in Using Clauses guide Feb 26, 2023
@Kordyjan Kordyjan merged commit a46d730 into scala:language-reference-stable Feb 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants