Scala types and F bounded types












0














I'm learning about F-bound types in Scala, and I have come across a situation where I don't know what's wrong.



I've made three tests, the code is as follows:



import scala.collection.mutable

def test1() = {

trait Abstract {
type ThisType <: Abstract
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test2() = {

trait Abstract {
type ThisType
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test3() = {


trait Abstract[T <: Abstract[T]] {
def deepCopy(): T
}

case class Concrete1(a: Int) extends Abstract[Concrete1] {
override def deepCopy(): Concrete1 = this.copy()

}

case class Concrete2(a: Int) extends Abstract[Concrete2] {
override def deepCopy(): Concrete2 = this.copy()

}

val set = new mutable.HashSet[Abstract[_]]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())

}


test1 works fine. test2 and test3 produce a compile-time error.



In test2, I ommit that ThisType is a subtype of Abstract. I understand that if I don't set this upper bound, ThisType can be anything. But if I have a Set of Abstract and I perform a deepCopy() of it's elements, wouldn't it be of the same type? The compiler produces this error:



Error:(53, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^


I don't understand why in this case (test2) Abstract#ThisType is not the same type as Abstract and in test1 is. Does it have something to do with path-dependent types? If so, what is the explanation?



In test3 I try to do de same as in test1 but with type parameters, this complier throws an error at line val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy()) saying:



Error:(78, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^
Error:(140, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^
Error:(166, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^


It's something related to wildcards, but I don't know how to declare such types without wildcards.










share|improve this question


















  • 1




    test3 will compile if def deepCopy(): Abstract[T]. No other changes needed, but it should be noted that without the "self type" (self :T => ) you're not getting the safety guarantees of F-bounded polymorphism.
    – jwvh
    Nov 21 '18 at 11:24












  • @jwvh why is that?
    – vicaba
    Nov 21 '18 at 11:27










  • Without the "self type" restriction, the compiler will allow class Concrete2(a: Int) extends Abstract[Concrete1] {.., which usually isn't what you want.
    – jwvh
    Nov 21 '18 at 11:31
















0














I'm learning about F-bound types in Scala, and I have come across a situation where I don't know what's wrong.



I've made three tests, the code is as follows:



import scala.collection.mutable

def test1() = {

trait Abstract {
type ThisType <: Abstract
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test2() = {

trait Abstract {
type ThisType
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test3() = {


trait Abstract[T <: Abstract[T]] {
def deepCopy(): T
}

case class Concrete1(a: Int) extends Abstract[Concrete1] {
override def deepCopy(): Concrete1 = this.copy()

}

case class Concrete2(a: Int) extends Abstract[Concrete2] {
override def deepCopy(): Concrete2 = this.copy()

}

val set = new mutable.HashSet[Abstract[_]]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())

}


test1 works fine. test2 and test3 produce a compile-time error.



In test2, I ommit that ThisType is a subtype of Abstract. I understand that if I don't set this upper bound, ThisType can be anything. But if I have a Set of Abstract and I perform a deepCopy() of it's elements, wouldn't it be of the same type? The compiler produces this error:



Error:(53, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^


I don't understand why in this case (test2) Abstract#ThisType is not the same type as Abstract and in test1 is. Does it have something to do with path-dependent types? If so, what is the explanation?



In test3 I try to do de same as in test1 but with type parameters, this complier throws an error at line val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy()) saying:



Error:(78, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^
Error:(140, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^
Error:(166, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^


It's something related to wildcards, but I don't know how to declare such types without wildcards.










share|improve this question


















  • 1




    test3 will compile if def deepCopy(): Abstract[T]. No other changes needed, but it should be noted that without the "self type" (self :T => ) you're not getting the safety guarantees of F-bounded polymorphism.
    – jwvh
    Nov 21 '18 at 11:24












  • @jwvh why is that?
    – vicaba
    Nov 21 '18 at 11:27










  • Without the "self type" restriction, the compiler will allow class Concrete2(a: Int) extends Abstract[Concrete1] {.., which usually isn't what you want.
    – jwvh
    Nov 21 '18 at 11:31














0












0








0


1





I'm learning about F-bound types in Scala, and I have come across a situation where I don't know what's wrong.



I've made three tests, the code is as follows:



import scala.collection.mutable

def test1() = {

trait Abstract {
type ThisType <: Abstract
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test2() = {

trait Abstract {
type ThisType
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test3() = {


trait Abstract[T <: Abstract[T]] {
def deepCopy(): T
}

case class Concrete1(a: Int) extends Abstract[Concrete1] {
override def deepCopy(): Concrete1 = this.copy()

}

case class Concrete2(a: Int) extends Abstract[Concrete2] {
override def deepCopy(): Concrete2 = this.copy()

}

val set = new mutable.HashSet[Abstract[_]]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())

}


test1 works fine. test2 and test3 produce a compile-time error.



In test2, I ommit that ThisType is a subtype of Abstract. I understand that if I don't set this upper bound, ThisType can be anything. But if I have a Set of Abstract and I perform a deepCopy() of it's elements, wouldn't it be of the same type? The compiler produces this error:



Error:(53, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^


I don't understand why in this case (test2) Abstract#ThisType is not the same type as Abstract and in test1 is. Does it have something to do with path-dependent types? If so, what is the explanation?



In test3 I try to do de same as in test1 but with type parameters, this complier throws an error at line val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy()) saying:



Error:(78, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^
Error:(140, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^
Error:(166, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^


It's something related to wildcards, but I don't know how to declare such types without wildcards.










share|improve this question













I'm learning about F-bound types in Scala, and I have come across a situation where I don't know what's wrong.



I've made three tests, the code is as follows:



import scala.collection.mutable

def test1() = {

trait Abstract {
type ThisType <: Abstract
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test2() = {

trait Abstract {
type ThisType
def deepCopy(): ThisType
}

case class Concrete1(a: Int) extends Abstract {
override type ThisType = Concrete1
override def deepCopy(): ThisType = this.copy()

}

case class Concrete2(a: Int) extends Abstract {
override type ThisType = Concrete2
override def deepCopy(): ThisType = this.copy()

}

val set = new mutable.HashSet[Abstract]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test3() = {


trait Abstract[T <: Abstract[T]] {
def deepCopy(): T
}

case class Concrete1(a: Int) extends Abstract[Concrete1] {
override def deepCopy(): Concrete1 = this.copy()

}

case class Concrete2(a: Int) extends Abstract[Concrete2] {
override def deepCopy(): Concrete2 = this.copy()

}

val set = new mutable.HashSet[Abstract[_]]()

set ++= List(Concrete1(1), Concrete2(2))

val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())

}


test1 works fine. test2 and test3 produce a compile-time error.



In test2, I ommit that ThisType is a subtype of Abstract. I understand that if I don't set this upper bound, ThisType can be anything. But if I have a Set of Abstract and I perform a deepCopy() of it's elements, wouldn't it be of the same type? The compiler produces this error:



Error:(53, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^


I don't understand why in this case (test2) Abstract#ThisType is not the same type as Abstract and in test1 is. Does it have something to do with path-dependent types? If so, what is the explanation?



In test3 I try to do de same as in test1 but with type parameters, this complier throws an error at line val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy()) saying:



Error:(78, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^
Error:(140, 45) type mismatch;
found : scala.collection.mutable.HashSet[Abstract#ThisType]
required: scala.collection.mutable.Set[Abstract]
val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
^
Error:(166, 48) type mismatch;
found : scala.collection.mutable.HashSet[Any]
required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
^


It's something related to wildcards, but I don't know how to declare such types without wildcards.







scala f-bounded-polymorphism






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 21 '18 at 9:27









vicabavicaba

1,15911527




1,15911527








  • 1




    test3 will compile if def deepCopy(): Abstract[T]. No other changes needed, but it should be noted that without the "self type" (self :T => ) you're not getting the safety guarantees of F-bounded polymorphism.
    – jwvh
    Nov 21 '18 at 11:24












  • @jwvh why is that?
    – vicaba
    Nov 21 '18 at 11:27










  • Without the "self type" restriction, the compiler will allow class Concrete2(a: Int) extends Abstract[Concrete1] {.., which usually isn't what you want.
    – jwvh
    Nov 21 '18 at 11:31














  • 1




    test3 will compile if def deepCopy(): Abstract[T]. No other changes needed, but it should be noted that without the "self type" (self :T => ) you're not getting the safety guarantees of F-bounded polymorphism.
    – jwvh
    Nov 21 '18 at 11:24












  • @jwvh why is that?
    – vicaba
    Nov 21 '18 at 11:27










  • Without the "self type" restriction, the compiler will allow class Concrete2(a: Int) extends Abstract[Concrete1] {.., which usually isn't what you want.
    – jwvh
    Nov 21 '18 at 11:31








1




1




test3 will compile if def deepCopy(): Abstract[T]. No other changes needed, but it should be noted that without the "self type" (self :T => ) you're not getting the safety guarantees of F-bounded polymorphism.
– jwvh
Nov 21 '18 at 11:24






test3 will compile if def deepCopy(): Abstract[T]. No other changes needed, but it should be noted that without the "self type" (self :T => ) you're not getting the safety guarantees of F-bounded polymorphism.
– jwvh
Nov 21 '18 at 11:24














@jwvh why is that?
– vicaba
Nov 21 '18 at 11:27




@jwvh why is that?
– vicaba
Nov 21 '18 at 11:27












Without the "self type" restriction, the compiler will allow class Concrete2(a: Int) extends Abstract[Concrete1] {.., which usually isn't what you want.
– jwvh
Nov 21 '18 at 11:31




Without the "self type" restriction, the compiler will allow class Concrete2(a: Int) extends Abstract[Concrete1] {.., which usually isn't what you want.
– jwvh
Nov 21 '18 at 11:31












1 Answer
1






active

oldest

votes


















1














heres a version that shows some parts from my explanation https://scalafiddle.io/sf/Wnk3ekK/2



so the problem in 2 scalac canno't prove that Abstract is a common supertype for the typemeber due to the missing bound. see that ThisType can e.g. be Int which indeed is not a subtype of Abstract and thus not eligible to be in Set[Abstract]



in 3 is the problem that Abstract[_] is an existential and that doesn't work quite like that so you could interject a common supertype as shown.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53408879%2fscala-types-and-f-bounded-types%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    heres a version that shows some parts from my explanation https://scalafiddle.io/sf/Wnk3ekK/2



    so the problem in 2 scalac canno't prove that Abstract is a common supertype for the typemeber due to the missing bound. see that ThisType can e.g. be Int which indeed is not a subtype of Abstract and thus not eligible to be in Set[Abstract]



    in 3 is the problem that Abstract[_] is an existential and that doesn't work quite like that so you could interject a common supertype as shown.






    share|improve this answer


























      1














      heres a version that shows some parts from my explanation https://scalafiddle.io/sf/Wnk3ekK/2



      so the problem in 2 scalac canno't prove that Abstract is a common supertype for the typemeber due to the missing bound. see that ThisType can e.g. be Int which indeed is not a subtype of Abstract and thus not eligible to be in Set[Abstract]



      in 3 is the problem that Abstract[_] is an existential and that doesn't work quite like that so you could interject a common supertype as shown.






      share|improve this answer
























        1












        1








        1






        heres a version that shows some parts from my explanation https://scalafiddle.io/sf/Wnk3ekK/2



        so the problem in 2 scalac canno't prove that Abstract is a common supertype for the typemeber due to the missing bound. see that ThisType can e.g. be Int which indeed is not a subtype of Abstract and thus not eligible to be in Set[Abstract]



        in 3 is the problem that Abstract[_] is an existential and that doesn't work quite like that so you could interject a common supertype as shown.






        share|improve this answer












        heres a version that shows some parts from my explanation https://scalafiddle.io/sf/Wnk3ekK/2



        so the problem in 2 scalac canno't prove that Abstract is a common supertype for the typemeber due to the missing bound. see that ThisType can e.g. be Int which indeed is not a subtype of Abstract and thus not eligible to be in Set[Abstract]



        in 3 is the problem that Abstract[_] is an existential and that doesn't work quite like that so you could interject a common supertype as shown.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 21 '18 at 10:21









        Dominic EggerDominic Egger

        67817




        67817






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53408879%2fscala-types-and-f-bounded-types%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Create new schema in PostgreSQL using DBeaver

            Deepest pit of an array with Javascript: test on Codility

            Costa Masnaga