What is a difference between refinement type and anonymous subclass in Scala 3? - scala

Anonymous class definition is
An anonymous class is a synthetic subclass generated by the Scala
compiler from a new expression in which the class or trait name is
followed by curly braces. The curly braces contains the body of the
anonymous subclass, which may be empty. However, if the name following
new refers to a trait or class that contains abstract members, these
must be made concrete inside the curly braces that define the body of
the anonymous subclass.
Refinement type definition is
A type formed by supplying a base type a number of members inside
curly braces. The members in the curly braces refine the types that
are present in the base type. For example, the type of “animal that
eats grass” is Animal { type SuitableFood = Grass }
-- Both definitions are taken from book Programming in Scala Fifth Edition by Martin Odersky and others.
What is the difference? Can you illustrate it with simple examples?
Let's see my code example which compiles:
abstract class A:
type T
// anonymous class
var o1 = new A { type T = String }
// refinement type
var o2: A { type T = String } = null
o1 = o2 // OK
o2 = o1 // OK
It seems to me that refinement type is a handy way to create a new type, which anonymous class does implicitly.

As Dmytro Mitin pointed out in [1] and [2], the main difference is the same as the difference between class and type.
A type restricts the possible values to which a variable can refer, or an expression can produce, at run time. Refinement type is still a type, which may be used instead of defining a new class.
Without using the refinement type in the example, you would have to define a new class.
class AString extends A:
type T = String
A class is a blueprint for objects. Once you define a class, you can create objects from the class blueprint with the keyword new.

Type and class are different (and actually orthogonal) concepts. Types belong to type theory, classes belong to OOP. Classes exist in bytecode, types mostly don't exist in bytecode (if they are not persisted to runtime specially or if they don't correspond to classes obviously).
What is the difference between a class and a type in Scala (and Java)?
What is the difference between Type and Class?
https://typelevel.org/blog/2017/02/13/more-types-than-classes.html
new A { type T = String } is a shorthand for
{
class AImpl extends A {
type T = String
}
new AImpl
}
If you define an anonymous class
val o1 = new A { type T = String }
the type of o1 can be, for example, refined
val o1: A { type T = String } = new A { type T = String }
or even structural
val o1: A { type T = String; def foo(): Unit } = new A {
type T = String
def foo(): Unit = println("foo")
}
or not refined if we statically upcast, just
val o1: A = new A { type T = String }
So defining an anonymous class doesn't mean that the type of variable is a refinement type.
On the other hand, you can consider refined type
type X = A { type T = String }
val o2: A { type T = String } = null
not introducing an anonymous class. The only class in bytecode now is A, there is no AImpl (until you instantiate new ...).
Scala refined types can be compared with refinement types in type theory (or programming languages with dependent types), i.e. (dependent) types endowed with a predicate.

Related

Scala collection whose elements can construct sibling instances using named parameters and default values?

I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.

Uses of the type class and difference between type class and type trait

Two questions
Questions 1
What is the use of a class which takes type parameter
I could understand the usefulness of
trait SomeTrait[T]
I am struggling to comprehend what could be a use case of something like
class SomeClass[A](a:A) {...}
When we pass a parameter of a known type to a function or a class, we know which operations are allowed on that parameter. So if I have a class as follows, I know that as the parameter is of type Int, I can perform '+' on the parameter 'a'
scala> class IntTest(a:Int) {
| def plusandPrintInt = {println(a+1)} //as 'a' is Int, we can do +
| }
defined class IntTest
scala> val i = new IntTest(1).plusandPrintInt
2
i: Unit = ()
But when I create a class which accepts type parameter [A], then the parameter could be of any type. Thus I do not what operations can be done on the passed parameter
scala> class TypeClass [A](a:A) {
| // what possibly can be done on A without knowing what A is?
| }
defined class TypeClass
Traits are different because we do not implement functions in trait but let other class do so. When a Trait which accepts Type parameter is extended, it is generally extended by specifying the real parameter type. Thus we can call specific operations on parameters as we know what the type of parameters are
scala> trait TraitClass [T] {
| def whatever (t:T) // I am not bothered as I do not need to implement this function
| }
defined trait TraitClass
scala> class extendTraitClass extends TraitClass[Int] {
| def whatever(t:Int) {println(t+1)} //I know that t is Int so I can use +
| }
defined class extendTraitClass
scala> (new extendTraitClass).whatever(1)
2
It seems the only operations available to 'a' are follows
scala> def someFunction[A](a:A) {
| a. //double tabbed to get this list
!= + == ensuring formatted hashCode toString
## -> asInstanceOf equals getClass isInstanceOf ?
Question 2
Is type class same as type trait?
What is the use of a class which takes type parameter
A polymorphic class is useful when you can abstract over the type parameter. It means that the operations your class is exposing aren't specific to some concrete type.
Take the very common case of collections. If we look at a List[A] for example, should the List[A] be created for every type that list should hold? of course not, since the underlying operations can be performed for any type.
Another good example in Scala is Option[A]. If you were the implementer, would you want to create an option for each possible value that exists? i.e:
class IntOption(a: Int)
class StringOption(a: String)
You wouldn't want to that because there is no reason. Since we can abstract over any type parameter A, the class or trait can be made generic such that operations such as map can take higher order functions of those abstract types.
Is type class same as type trait?
Not sure what you mean by "same as". classes and traits are different in nature and posses different qualities.
"Type class" in Scala means something different from "a class which takes type parameter". It is a specific pattern which you shouldn't care about until you are comfortable with type parameters in general, so I'll consider your question 2 to be
is a class which takes type parameter the same as a trait which which takes type parameter
The answer is that there are of course differences between classes and traits (or there wouldn't be two different notions!), but these differences are the same independent of whether class/trait has type parameters.
Traits are different because we do not implement functions in trait but let other class do so.
No, you can implement methods in a trait. Here is an example:
trait Trait[T] {
def whatever(t: T) = Some(t)
}
When a Trait which accepts Type parameter is extended, it is generally extended by specifying the real parameter type.
Again, no:
trait Trait2[T] extends Trait[T] { ... }
is not problematic in any way. Neither is
class SomeClassForInt extends SomeClass[Int] { ... }

Injecting (implicit) value of abstract type into subtypes of trait

Here is a simplification of my scenario that I am trying to make it work
// the UnrelatedN are mostly used as tag traits, for type-checking purposes
trait Unrelated1
trait Unrelated2
trait HasUnrelatedSupertrait {
type Unrelated // abstract type
}
trait HasUnrelated[... /*TODO: Parametrize with (factory of) UnrelatedN*/]
extends HasUnrelatedSupertrait {
type Unrelated = UnrelatedType // path-dependent type
implicit val unrelated = ... // instantiate or access (singleton) instance of Unrelated
}
trait Subtype1 extends HasUnrelated[/* Something involving Unrelated1 */] with ...
trait Subtype2 extends HasUnrelated[/* Something involving Unrelated2 */] with ...
// ... (many more similar subtypes)
Basically, I would like to inject the implicit val instance of
abstract type into (subtypes of) HasUnrelated in a non-intrusive
way, hopefully through a type parameter that I have some flexibility
over (see TODO).
(I don't care if Unrelated1/2 instances are constructed via new,
factory and how those factories are defined (as objects, classes
etc.), as long as I can get 2 distinct instances of Unrelated1/2.)
Some of the constraining factors why my attempts have failed are:
HasUnrelated and HasUnrelatedSupertrait must be traits, not classes
traits cannot have parameters (so I cannot pass (implicit) val factory)
traits cannot have context or view bounds (to bring in ClassTag/TypeTag)
I am not willing to clutter all the subtypes of HasUnrelated with
additional type/val declarations
However, I am willing to do one or more of the following changes:
introduce (singleton) factories for Unrelated1/2
introduce arbitrary inheritance in Unrelated1/2 as long as those
types are still unrelated (neither is subtype of the other)
add supertype to HasUnrelated as long is it requires extra
declarations (if any) only in HasUnrelated, but not any of its subtypes
Is there a way to achieve this in Scala and if so how?
Probably type class is something you are looking for? Consider this example
trait Companion[T] {
val comp: T
}
object Companion {
def apply[T: Companion] = implicitly[Companion[T]]
}
object UnrelatedType {
implicit val thisComp =
new Companion[UnrelatedType.type] {
val comp = UnrelatedType
}
}
// Somewhere later
type Unrelated = UnrelatedType
implicit val unrelated = Companion[UnrelatedType]

Context bounds for type members or how to defer implicit resolution until member instantiation

In the following example, is there a way to avoid that implicit resolution picks the defaultInstance and uses the intInstance instead? More background after the code:
// the following part is an external fixed API
trait TypeCls[A] {
def foo: String
}
object TypeCls {
def foo[A](implicit x: TypeCls[A]) = x.foo
implicit def defaultInstance[A]: TypeCls[A] = new TypeCls[A] {
def foo = "default"
}
implicit val intInstance: TypeCls[Int] = new TypeCls[Int] {
def foo = "integer"
}
}
trait FooM {
type A
def foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
def foo: String = implicitly[TypeCls[A]].foo
}
class MyFooP extends FooP[Int]
class MyFooM extends FooM { type A = Int }
object Main extends App {
println(s"With type parameter: ${(new MyFooP).foo}")
println(s"With type member: ${(new MyFooM).foo}")
}
Actual output:
With type parameter: integer
With type member: default
Desired output:
With type parameter: integer
With type member: integer
I am working with a third-party library that uses the above scheme to provide "default" instances for the type class TypeCls. I think the above code is a minimal example that demonstrates my problem.
Users are supposed to mix in the FooM trait and instantiate the abstract type member A. The problem is that due to the defaultInstance the call of (new MyFooM).foo does not resolve the specialized intInstance and instead commits to defaultInstance which is not what I want.
I added an alternative version using type parameters, called FooP (P = Parameter, M = Member) which avoids to resolve the defaultInstance by using a context bound on the type parameter.
Is there an equivalent way to do this with type members?
EDIT: I have an error in my simplification, actually the foo is not a def but a val, so it is not possible to add an implicit parameter. So no of the current answers are applicable.
trait FooM {
type A
val foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
val foo: String = implicitly[TypeCls[A]].foo
}
The simplest solution in this specific case is have foo itself require an implicit instance of TypeCls[A].
The only downside is that it will be passed on every call to foo as opposed to just when instantiating
FooM. So you'll have to make sure they are in scope on every call to foo. Though as long as the TypeCls instances are in the companion object, you won't have anything special to do.
trait FooM {
type A
def foo(implicit e: TypeCls[A]): String = e.foo
}
UPDATE: In my above answer I managed to miss the fact that FooM cannot be modified. In addition the latest edit to the question mentions that FooM.foo is actually a val and not a def.
Well the bad news is that the API you're using is simply broken. There is no way FooM.foo wille ever return anything useful (it will always resolve TypeCls[A] to TypeCls.defaultInstance regardless of the actual value of A). The only way out is to override foo in a derived class where the actual value of A is known, in order to be able to use the proper instance of TypeCls. Fortunately, this idea can be combined with your original workaround of using a class with a context bound (FooP in your case):
class FooMEx[T:TypeCls] extends FooM {
type A = T
override val foo: String = implicitly[TypeCls[A]].foo
}
Now instead of having your classes extend FooM directly, have them extend FooMEx:
class MyFoo extends FooMEx[Int]
The only difference between FooMEx and your original FooP class is that FooMEx does extend FooM, so MyFoo is a proper instance of FooM and can thus be used with the fixed API.
Can you copy the code from the third party library. Overriding the method does the trick.
class MyFooM extends FooM { type A = Int
override def foo: String = implicitly[TypeCls[A]].foo}
It is a hack, but I doubt there is anything better.
I do not know why this works the way it does. It must be some order in which the type alias are substituted in the implicitly expression.
Only an expert in the language specification can tell you the exact reason.

Passing a type parameter for instantiation

Why wouldn't the scala compiler dig this:
class Clazz
class Foo[C <: Clazz] {
val foo = new C
}
class type required but C found
[error] val a = new C
[error] ^
Related question - How to get rid of : class type required but T found
This is a classic generic problem that also happens in Java - you cannot create an instance of a generic type variable. What you can do in Scala to fix this, however, is to introduce a type evidence to your type parameter that captures the runtime type:
class Foo[C <: Clazz](implicit ct: ClassTag[C]) {
val foo = ct.runtimeClass.newInstance
}
Note that this only works if the class has a constructor without any arguments. Since the parameter is implicit, you don't need to pass it when calling the Foo constructor:
Foo[Clazz]()
I came up with this scheme, couldn't simplify it through a companion object thought.
class Clazz
class ClazzFactory {
def apply = new Clazz
}
class Foo(factory: ClazzFactory) {
val foo: Clazz = factory.apply
}
It's very annoying that ClazzFactory can't be an object rather than a class though. A simplified version:
class Clazz {
def apply() = new Clazz
}
class Foo(factory: Clazz) {
val foo: Clazz = factory.apply
}
This requires the caller to use the new keyword in order to provide the factory argument, which is already a minor enough annoyance relative to the initial problem. But, scala could have made this scenario all more elegant; I had to fallback here to passing a parameter of the type I wish to instantiate, plus the new keyword. Maybe there's a better way.
(motivation was to instantiate that type many times within the real Foo, that's why this is at all a solution; otherwise my pattern above is just redundantly meaningless).