What constraints to add to ensure invariance - compiler infers Any instead of String

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

What constraints to add to ensure invariance - compiler infers Any instead of String

Hugo Ferreira
Hello,

I have the following very basic code:

  trait Parameter[ T ] {
    type Self <: Parameter[ T ]
    def apply( v: T ): Self
  }

  import scala.language.higherKinds

  case class ParameterRange[ P[ X ] <: Parameter[ X ], T, U ](
      val param: P[ T ],
      val start: T,
      val stop: T,
      val config: U ){

    def toStream( f: ( T, T, U ) => Stream[ T ] ): Stream[ P[ T ]#Self ] = {
      val st = f( start, stop, config )
      val r = st.map{ x: T => param( x ) }
      r
    }
  }

If I use an Int as the Parameter type I have no problems:

  case class Param1( v: Int ) extends Parameter[ Int ] { type Self = Param1; def apply( v: Int ) = new Param1( v ) }

  val p1 = Param1( 0 )
  val pr1 = ParameterRange( p1, 0, 10, 1 )
  val p2 = Param1( 1 )
  val pr2 = ParameterRange( p2, 0, 10, 1 )

But if I use a string:

  case class Param3( v: String ) extends Parameter[ String ] { type Self = Param3; def apply( v: String ) = new Param3( v ) }

  val p3 : Parameter[String] = Param3( "" )
  val pr3  = ParameterRange( p3, 0, 10, 1 )

I get an error:

[error]  found   : NonConformanceToType.Parameter[String]
[error]  required: NonConformanceToType.Parameter[Any]
[error] Note: String <: Any, but trait Parameter is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error]   val pr3  = ParameterRange( p3, 0, 10, 1 )
[error]                              ^

How can I ensure that the invariance is maintained?
I take it this is a problem due to the use of the existential variable in ParameterRange (seems to be a common issue).
Any suggestions?

TIA,
Hugo


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What constraints to add to ensure invariance - compiler infers Any instead of String

Jasper-M
The error is a bit confusing, but you are supposed to get an error, no?
You pass in a Parameter[String] which sets the constraint T >: String, but then where a T is expected you pass in an Int, which sets T >: Int. To satisfy both constraints there is only one solution: T = Any. But Parameter is indeed invariant in T so Parameter[String] is not a subtype of Parameter[Any], hence the error.

The error is proof that invariance is indeed ensured.

Op dinsdag 31 januari 2017 16:41:56 UTC+1 schreef Hugo Ferreira:
Hello,

I have the following very basic code:

  trait Parameter[ T ] {
    type Self <: Parameter[ T ]
    def apply( v: T ): Self
  }

  import scala.language.higherKinds

  case class ParameterRange[ P[ X ] <: Parameter[ X ], T, U ](
      val param: P[ T ],
      val start: T,
      val stop: T,
      val config: U ){

    def toStream( f: ( T, T, U ) => Stream[ T ] ): Stream[ P[ T ]#Self ] = {
      val st = f( start, stop, config )
      val r = st.map{ x: T => param( x ) }
      r
    }
  }

If I use an Int as the Parameter type I have no problems:

  case class Param1( v: Int ) extends Parameter[ Int ] { type Self = Param1; def apply( v: Int ) = new Param1( v ) }

  val p1 = Param1( 0 )
  val pr1 = ParameterRange( p1, 0, 10, 1 )
  val p2 = Param1( 1 )
  val pr2 = ParameterRange( p2, 0, 10, 1 )

But if I use a string:

  case class Param3( v: String ) extends Parameter[ String ] { type Self = Param3; def apply( v: String ) = new Param3( v ) }

  val p3 : Parameter[String] = Param3( "" )
  val pr3  = ParameterRange( p3, 0, 10, 1 )

I get an error:

[error]  found   : NonConformanceToType.Parameter[String]
[error]  required: NonConformanceToType.Parameter[Any]
[error] Note: String <: Any, but trait Parameter is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error]   val pr3  = ParameterRange( p3, 0, 10, 1 )
[error]                              ^

How can I ensure that the invariance is maintained?
I take it this is a problem due to the use of the existential variable in ParameterRange (seems to be a common issue).
Any suggestions?

TIA,
Hugo


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What constraints to add to ensure invariance - compiler infers Any instead of String

Hugo Ferreira

Appreciate the help Jasper.


On Tuesday, 31 January 2017 16:04:01 UTC, Jasper-M wrote:
The error is a bit confusing, but you are supposed to get an error, no?

I would have though not.
 
You pass in a Parameter[String] which sets the constraint T >: String, but then where a T is expected you pass in an Int, which sets T >: Int. To satisfy both constraints there is only one solution: T = Any. But Parameter is indeed invariant in T so Parameter[String] is not a subtype of Parameter[Any], hence the error.


The explanation makes sense and shows a fundamental flaw in my understanding of the typing.

I create two Parameter, one for Int and another for String.
When I create a  ParameterRange and pass on a Parameter of Int, I assume that it is independent of another object ParameterRange
were I place the String.  I am therefore expecting two  ParameterRange:

ParameterRange[Parameter[Int], Int, Int]
ParameterRange[Parameter[String], String, Int]

 
The error is proof that invariance is indeed ensured.


If the type T is shared between ParameterRanges,  yes.
But aren't they two different objects with there own types and constraints?
 
TIA,
Hugo


Op dinsdag 31 januari 2017 16:41:56 UTC+1 schreef Hugo Ferreira:
Hello,

I have the following very basic code:

  trait Parameter[ T ] {
    type Self <: Parameter[ T ]
    def apply( v: T ): Self
  }

  import scala.language.higherKinds

  case class ParameterRange[ P[ X ] <: Parameter[ X ], T, U ](
      val param: P[ T ],
      val start: T,
      val stop: T,
      val config: U ){

    def toStream( f: ( T, T, U ) => Stream[ T ] ): Stream[ P[ T ]#Self ] = {
      val st = f( start, stop, config )
      val r = st.map{ x: T => param( x ) }
      r
    }
  }

If I use an Int as the Parameter type I have no problems:

  case class Param1( v: Int ) extends Parameter[ Int ] { type Self = Param1; def apply( v: Int ) = new Param1( v ) }

  val p1 = Param1( 0 )
  val pr1 = ParameterRange( p1, 0, 10, 1 )
  val p2 = Param1( 1 )
  val pr2 = ParameterRange( p2, 0, 10, 1 )

But if I use a string:

  case class Param3( v: String ) extends Parameter[ String ] { type Self = Param3; def apply( v: String ) = new Param3( v ) }

  val p3 : Parameter[String] = Param3( "" )
  val pr3  = ParameterRange( p3, 0, 10, 1 )

I get an error:

[error]  found   : NonConformanceToType.Parameter[String]
[error]  required: NonConformanceToType.Parameter[Any]
[error] Note: String <: Any, but trait Parameter is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error]   val pr3  = ParameterRange( p3, 0, 10, 1 )
[error]                              ^

How can I ensure that the invariance is maintained?
I take it this is a problem due to the use of the existential variable in ParameterRange (seems to be a common issue).
Any suggestions?

TIA,
Hugo


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What constraints to add to ensure invariance - compiler infers Any instead of String

Hugo Ferreira

Ok. I understand now.

On Tuesday, 31 January 2017 16:26:39 UTC, Hugo Ferreira wrote:

Appreciate the help Jasper.


On Tuesday, 31 January 2017 16:04:01 UTC, Jasper-M wrote:
The error is a bit confusing, but you are supposed to get an error, no?

I would have though not.
 
You pass in a Parameter[String] which sets the constraint T >: String, but then where a T is expected you pass in an Int, which sets T >: Int. To satisfy both constraints there is only one solution: T = Any. But Parameter is indeed invariant in T so Parameter[String] is not a subtype of Parameter[Any], hence the error.


The explanation makes sense and shows a fundamental flaw in my understanding of the typing.

I create two Parameter, one for Int and another for String.
When I create a  ParameterRange and pass on a Parameter of Int, I assume that it is independent of another object ParameterRange
were I place the String.  I am therefore expecting two  ParameterRange:

ParameterRange[Parameter[Int], Int, Int]
ParameterRange[Parameter[String], String, Int]

 
The error is proof that invariance is indeed ensured.


If the type T is shared between ParameterRanges,  yes.
But aren't they two different objects with there own types and constraints?
 
TIA,
Hugo


Op dinsdag 31 januari 2017 16:41:56 UTC+1 schreef Hugo Ferreira:
Hello,

I have the following very basic code:

  trait Parameter[ T ] {
    type Self <: Parameter[ T ]
    def apply( v: T ): Self
  }

  import scala.language.higherKinds

  case class ParameterRange[ P[ X ] <: Parameter[ X ], T, U ](
      val param: P[ T ],
      val start: T,
      val stop: T,
      val config: U ){

    def toStream( f: ( T, T, U ) => Stream[ T ] ): Stream[ P[ T ]#Self ] = {
      val st = f( start, stop, config )
      val r = st.map{ x: T => param( x ) }
      r
    }
  }

If I use an Int as the Parameter type I have no problems:

  case class Param1( v: Int ) extends Parameter[ Int ] { type Self = Param1; def apply( v: Int ) = new Param1( v ) }

  val p1 = Param1( 0 )
  val pr1 = ParameterRange( p1, 0, 10, 1 )
  val p2 = Param1( 1 )
  val pr2 = ParameterRange( p2, 0, 10, 1 )

But if I use a string:

  case class Param3( v: String ) extends Parameter[ String ] { type Self = Param3; def apply( v: String ) = new Param3( v ) }

  val p3 : Parameter[String] = Param3( "" )
  val pr3  = ParameterRange( p3, 0, 10, 1 )

I get an error:

[error]  found   : NonConformanceToType.Parameter[String]
[error]  required: NonConformanceToType.Parameter[Any]
[error] Note: String <: Any, but trait Parameter is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error]   val pr3  = ParameterRange( p3, 0, 10, 1 )
[error]                              ^

How can I ensure that the invariance is maintained?
I take it this is a problem due to the use of the existential variable in ParameterRange (seems to be a common issue).
Any suggestions?

TIA,
Hugo


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What constraints to add to ensure invariance - compiler infers Any instead of String

Jasper-M
In reply to this post by Hugo Ferreira
Nowhere in the code were you creating a ParameterRange[Parameter[String], String, Int]. You were trying to create a ParameterRange[Parameter[String], Int, Int], but that's impossible.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What constraints to add to ensure invariance - compiler infers Any instead of String

Hugo Ferreira
Yes. I realised that - only too late. Sorry for the noise.

On Wednesday, 1 February 2017 07:11:06 UTC, Jasper-M wrote:
Nowhere in the code were you creating a ParameterRange[Parameter[String], String, Int]. You were trying to create a ParameterRange[Parameter[String], Int, Int], but that's impossible.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.