How to compare an ordered abstract type in a Scala trait?

Based on the code below, the foo method should map the specified bar to the operator with lowerBound and upperBound , all of which are of the abstract abstract type bar .

 trait Foo { type Bar <: Ordered[Bar] val lowerBound: Bar val upperBound: Bar def foo(bar: Bar) = bar >= lowerBound && bar <= upperBound } 

In this way, the sign foo can be defined. Problems begin with below a specific FooImpl class.

 class FooImpl extends Foo { type Bar = Int val lowerBound = 0 val upperBound = 5 } 

I understand that scala.Int does not implement what scala.runtime.RichInt does, effectively scala.math.Ordered[Int] . Defining bar as RichInt does not work instead, since it does not match scala.math.Ordered[RichInt] . My third attempt is to define type bar as Ordered[Ord] , where Ord declared as type Ord and define it in FooImpl , since Int also does not work.

What will a similar solution look like?

+4
source share
1 answer

There may be a more elegant solution, but you can achieve this by moving the type constraint to a method, rather than a type declaration:

 trait Foo { type Bar val lowerBound: Bar val upperBound: Bar def foo(bar: Bar)(implicit ev: Bar => Ordered[Bar]) = { bar >= lowerBound && bar <= upperBound } } 

Then your FooImpl works as it is:

 class FooImpl extends Foo { type Bar = Int val lowerBound = 0 val upperBound = 5 } 

In REPL:

 scala> new FooImpl() res0: FooImpl = FooImpl@2dbbec72 scala> res0.foo(3) res1: Boolean = true scala> res0.foo(7) res2: Boolean = false 

The disadvantage here is that this attribute can be extended with unordered types (although foo cannot be called in this case):

 class A // not Ordered class BrokenFoo extends Foo { type Bar = A val lowerBound = new A val upperBound = new A } // compiles new BrokenFoo().foo(new A) // doesn't compile 

Alternatively, you can keep the requirement at the class level (and therefore stop any BrokenFoo creation) as follows, but FooImpl should change a bit:

 trait Foo { type Bar implicit val baz: Bar => Ordered[Bar] val lowerBound: Bar val upperBound: Bar def foo(bar: Bar) = { bar >= lowerBound && bar <= upperBound } } class FooImpl extends Foo { type Bar = Int val baz = implicitly[Bar => Ordered[Bar]] val lowerBound = 0 val upperBound = 5 } 

This problem looks like this: the view or context boundaries should be applicable, but, unfortunately, it seems that you cannot use them in type declarations or in general type parameter parameters.

+7
source

Source: https://habr.com/ru/post/1396091/


All Articles