Referring to the type of account assignment value in a method signature

I would like to add a method to scala.Enumeration. My first approach was to try to expand it, but was bitten by it . My second approach was to try to define a method and pass to Enumeration - if that worked, I was hoping to use an implicit conversion. However, it is difficult for me to save the type with the return type of the method.

object EnumExample { object SampleEnum extends Enumeration { val include, exclude = Value } def parse[T <: Enumeration](name:String, enum:T):T#Value = enum.valueOf(name) match { case Some(x) => x case x => throw new RuntimeException("No field named '" + name + "' found on enum " + enum + ", legal values = " + enum.values) } def main(args:Array[String]) = { //compiles fine, and preserves custom type val withNameExample:SampleEnum.Value = SampleEnum.withName("include") //also fine, but we lost type info val enumWithHash:Enumeration#Value = parse("include", SampleEnum) /** error: type mismatch; found : Main.$anon.EnumExample.SampleEnum#Value required: Main.$anon.EnumExample.SampleEnum.Value val parseExample:SampleEnum.Value = parse("include", SampleEnum) * */ val customTypeWithHash:SampleEnum.type#Value = parse("include", SampleEnum) //same error val customTypeWithDot:SampleEnum.Value = parse("include", SampleEnum) } } 

One obvious fix would be to simply remove the return type declaration from the parse method, but this gives me a "type of illegal dependent method". This leaves me with many questions:

  • Can this be indicated? Anyway, I would like to get a good error message when parsing an enumeration field into a String.

  • Why am I getting an "illegal dependent method type"?

  • What exactly does the # (?) Operator mean in this case?

+4
source share
1 answer

This looks like a bug to me (at least in 2.8.0 Beta1, where I tested it).

Particularly instructive is the following:

 scala> var x: SampleEnum.type#Value = null x: SampleEnum.Value = null 

Here we request an arbitrary internal type, but actually get a specific internal type. This is just broken (and I will write a bug report if it is not there already, unless someone quickly explains why it is not a mistake).

So what to do? Well, first, let's understand the original signature of the parse method:

 def parse[T <: Enumeration](name:String, enum:T):T#Value 

We have T , which is a subclass of Enumeration , enum , which is an instance of T , and - since there is no way to express that Value must be from this particular instance of T , we must resort to T#Value (i.e., the internal type T , regardless of which T it comes from).

Now we need to transfer a specific object, return the general internal object and make it in the face of ExampleObject.type#Value equal to ExampleObject.Value , even if they are printed in different ways.

So, we have to write our own object from scratch:

 class SampleWorkaroundClass extends Enumeration { val include, exclude = Value } lazy val SampleWorkaround = new SampleWorkaroundClass 

Here we have one instance of a specially defined class. Now we can get around the error in Object :

 scala> val typeWorks:SampleWorkaroundClass#Value = parse("include",SampleWorkaround) typeWorks: SampleWorkaroundClass#Value = include 

( lazy val is to get the same behavior as with objects where they are not created until they are used, but only val will be.)


Edit: Outer#Inner means "any inner class of type Inner originating from this outer class", unlike myOuter.Inner , which means "only the class of type Inner that has this Outer instance, myOuter , as its spanning class." Also, I am not getting a dependent type error in 2.8.0 Beta1 - but the inability to specify the type makes things pretty uncomfortable.


Edit: refresh the error report - the way it works now is obviously intentional. To use types in this way, you must explicitly specify the type of function call (since this is not displayed the way you want), e.g.

 val suggested: SampleEnum.type#Value = parse[SampleEnum.type]("include",SampleEnum) 

This method is easier if you need to do this several times. If you need to do this many times, creating your own class using val (or lazy val) may make things simpler / simpler.

+5
source

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


All Articles