F-bounded types and methods with type parameters at argument and return sites
I have an F-bounded type, and my objective is to create a type-parametrized method in order to be able to reuse it. Here is the example code:
trait FType {
type ThisType <: FType
def deepCopy(): ThisType
}
class ConcreteType extends FType {
override type ThisType = ConcreteType
override def deepCopy(): ConcreteType = this
}
class ConcreteType2 extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = this
}
object FType {
def deepCopy[T <: FType](_type: T): T = {
_type.deepCopy()
}
/* def deepCopy2(c: ConcreteType2): ConcreteType2 = {
c.deepCopy()
}*/
def main(args: Array[String]): Unit = {
//deepCopy2(new ConcreteType2)
}
}
However, the code does not compile. The compiler throws this error:
Error:(29, 19) type mismatch;
found : _type.ThisType
required: T
_type.deepCopy()
I understand that it has something to to with path-dependent types since _type.ThisType
is not the same type as T
.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type? If the types are not exactly the same, how is that deepCopy2
compiles?
Note: I know I can avoid using type parameters in deepCopy
by using method overloading for each of the concrete types.
scala path-dependent-type f-bounded-polymorphism
add a comment |
I have an F-bounded type, and my objective is to create a type-parametrized method in order to be able to reuse it. Here is the example code:
trait FType {
type ThisType <: FType
def deepCopy(): ThisType
}
class ConcreteType extends FType {
override type ThisType = ConcreteType
override def deepCopy(): ConcreteType = this
}
class ConcreteType2 extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = this
}
object FType {
def deepCopy[T <: FType](_type: T): T = {
_type.deepCopy()
}
/* def deepCopy2(c: ConcreteType2): ConcreteType2 = {
c.deepCopy()
}*/
def main(args: Array[String]): Unit = {
//deepCopy2(new ConcreteType2)
}
}
However, the code does not compile. The compiler throws this error:
Error:(29, 19) type mismatch;
found : _type.ThisType
required: T
_type.deepCopy()
I understand that it has something to to with path-dependent types since _type.ThisType
is not the same type as T
.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type? If the types are not exactly the same, how is that deepCopy2
compiles?
Note: I know I can avoid using type parameters in deepCopy
by using method overloading for each of the concrete types.
scala path-dependent-type f-bounded-polymorphism
add a comment |
I have an F-bounded type, and my objective is to create a type-parametrized method in order to be able to reuse it. Here is the example code:
trait FType {
type ThisType <: FType
def deepCopy(): ThisType
}
class ConcreteType extends FType {
override type ThisType = ConcreteType
override def deepCopy(): ConcreteType = this
}
class ConcreteType2 extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = this
}
object FType {
def deepCopy[T <: FType](_type: T): T = {
_type.deepCopy()
}
/* def deepCopy2(c: ConcreteType2): ConcreteType2 = {
c.deepCopy()
}*/
def main(args: Array[String]): Unit = {
//deepCopy2(new ConcreteType2)
}
}
However, the code does not compile. The compiler throws this error:
Error:(29, 19) type mismatch;
found : _type.ThisType
required: T
_type.deepCopy()
I understand that it has something to to with path-dependent types since _type.ThisType
is not the same type as T
.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type? If the types are not exactly the same, how is that deepCopy2
compiles?
Note: I know I can avoid using type parameters in deepCopy
by using method overloading for each of the concrete types.
scala path-dependent-type f-bounded-polymorphism
I have an F-bounded type, and my objective is to create a type-parametrized method in order to be able to reuse it. Here is the example code:
trait FType {
type ThisType <: FType
def deepCopy(): ThisType
}
class ConcreteType extends FType {
override type ThisType = ConcreteType
override def deepCopy(): ConcreteType = this
}
class ConcreteType2 extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = this
}
object FType {
def deepCopy[T <: FType](_type: T): T = {
_type.deepCopy()
}
/* def deepCopy2(c: ConcreteType2): ConcreteType2 = {
c.deepCopy()
}*/
def main(args: Array[String]): Unit = {
//deepCopy2(new ConcreteType2)
}
}
However, the code does not compile. The compiler throws this error:
Error:(29, 19) type mismatch;
found : _type.ThisType
required: T
_type.deepCopy()
I understand that it has something to to with path-dependent types since _type.ThisType
is not the same type as T
.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type? If the types are not exactly the same, how is that deepCopy2
compiles?
Note: I know I can avoid using type parameters in deepCopy
by using method overloading for each of the concrete types.
scala path-dependent-type f-bounded-polymorphism
scala path-dependent-type f-bounded-polymorphism
edited Nov 26 '18 at 12:41
Alonso Dominguez
6,34311936
6,34311936
asked Nov 26 '18 at 12:18
vicabavicaba
1,17911528
1,17911528
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
If the types are not exactly the same, how is that deepCopy2 compiles?
That is quite simple. It works because there is no polymorphism involved. It's statically known that ConcreteType2
has deepCopy()
method that returns ConcreteType2
. You could even remove type ThisType
from whole hierarchy and it would still work the same way.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type?
You need to tell the compiler that it's the same, as you haven't specified enough. Let's take a look at an example that works and is polymorphic:
def deepCopy[A <: FType { type ThisType = A }](_type: A): A = _type.deepCopy()
// ^ --important bit-- ^
This defines a method that works for any A
that is FType
and also it's type member ThisType
is set to A
, tying them together. That means it would work for your definitions of ConcreteType
and ConcreteType2
. It would NOT compile, however, for classes that aren't defined properly, such as this one:
class Bogus extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = new ConcreteType2
}
deepCopy(new Bogus)
Alternatively, let's start with a slightly modified version of your method:
def deepCopyPD[A <: FType](_type: A): _type.ThisType = _type.deepCopy()
^path-dependent^
It puts no constraints on ThisType
, but in fact compiler would be able to infer proper versions of it for all cases:
val x: ConcreteType2 = deepCopyPD(new ConcreteType2)
val y: ConcreteType2 = deepCopyPD(new Bogus) // yep, this invocation is possible with such signature
However, it is also possible to further add constraints using type equality evidence as implicit parameter:
def deepCopyPD2[A <: FType](_type: A)(implicit ev: _type.ThisType =:= A): A = _type.deepCopy()
This, once more, forbids the invocation with Bogus
add a comment |
In F-bounded types, you'd normally have ThisType
as a type parameter instead of a type member:
trait FType[ThisType <: FType] {
def deepCopy(): ThisType
}
class ConcreteType extends FType[ConcreteType] {
override def deepCopy(): ConcreteType = this
}
// in object FType
def deepCopy[T <: FType[T]](_type: T): T = {
_type.deepCopy()
}
Note the difference: in FType.deepCopy
the compiler knows that the return type of _type.deepCopy()
is T
.
You can do the same with type members:
def deepCopy[T <: FType { type ThisType <: T }](_type: T): T =
_type.deepCopy()
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53480975%2ff-bounded-types-and-methods-with-type-parameters-at-argument-and-return-sites%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
If the types are not exactly the same, how is that deepCopy2 compiles?
That is quite simple. It works because there is no polymorphism involved. It's statically known that ConcreteType2
has deepCopy()
method that returns ConcreteType2
. You could even remove type ThisType
from whole hierarchy and it would still work the same way.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type?
You need to tell the compiler that it's the same, as you haven't specified enough. Let's take a look at an example that works and is polymorphic:
def deepCopy[A <: FType { type ThisType = A }](_type: A): A = _type.deepCopy()
// ^ --important bit-- ^
This defines a method that works for any A
that is FType
and also it's type member ThisType
is set to A
, tying them together. That means it would work for your definitions of ConcreteType
and ConcreteType2
. It would NOT compile, however, for classes that aren't defined properly, such as this one:
class Bogus extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = new ConcreteType2
}
deepCopy(new Bogus)
Alternatively, let's start with a slightly modified version of your method:
def deepCopyPD[A <: FType](_type: A): _type.ThisType = _type.deepCopy()
^path-dependent^
It puts no constraints on ThisType
, but in fact compiler would be able to infer proper versions of it for all cases:
val x: ConcreteType2 = deepCopyPD(new ConcreteType2)
val y: ConcreteType2 = deepCopyPD(new Bogus) // yep, this invocation is possible with such signature
However, it is also possible to further add constraints using type equality evidence as implicit parameter:
def deepCopyPD2[A <: FType](_type: A)(implicit ev: _type.ThisType =:= A): A = _type.deepCopy()
This, once more, forbids the invocation with Bogus
add a comment |
If the types are not exactly the same, how is that deepCopy2 compiles?
That is quite simple. It works because there is no polymorphism involved. It's statically known that ConcreteType2
has deepCopy()
method that returns ConcreteType2
. You could even remove type ThisType
from whole hierarchy and it would still work the same way.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type?
You need to tell the compiler that it's the same, as you haven't specified enough. Let's take a look at an example that works and is polymorphic:
def deepCopy[A <: FType { type ThisType = A }](_type: A): A = _type.deepCopy()
// ^ --important bit-- ^
This defines a method that works for any A
that is FType
and also it's type member ThisType
is set to A
, tying them together. That means it would work for your definitions of ConcreteType
and ConcreteType2
. It would NOT compile, however, for classes that aren't defined properly, such as this one:
class Bogus extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = new ConcreteType2
}
deepCopy(new Bogus)
Alternatively, let's start with a slightly modified version of your method:
def deepCopyPD[A <: FType](_type: A): _type.ThisType = _type.deepCopy()
^path-dependent^
It puts no constraints on ThisType
, but in fact compiler would be able to infer proper versions of it for all cases:
val x: ConcreteType2 = deepCopyPD(new ConcreteType2)
val y: ConcreteType2 = deepCopyPD(new Bogus) // yep, this invocation is possible with such signature
However, it is also possible to further add constraints using type equality evidence as implicit parameter:
def deepCopyPD2[A <: FType](_type: A)(implicit ev: _type.ThisType =:= A): A = _type.deepCopy()
This, once more, forbids the invocation with Bogus
add a comment |
If the types are not exactly the same, how is that deepCopy2 compiles?
That is quite simple. It works because there is no polymorphism involved. It's statically known that ConcreteType2
has deepCopy()
method that returns ConcreteType2
. You could even remove type ThisType
from whole hierarchy and it would still work the same way.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type?
You need to tell the compiler that it's the same, as you haven't specified enough. Let's take a look at an example that works and is polymorphic:
def deepCopy[A <: FType { type ThisType = A }](_type: A): A = _type.deepCopy()
// ^ --important bit-- ^
This defines a method that works for any A
that is FType
and also it's type member ThisType
is set to A
, tying them together. That means it would work for your definitions of ConcreteType
and ConcreteType2
. It would NOT compile, however, for classes that aren't defined properly, such as this one:
class Bogus extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = new ConcreteType2
}
deepCopy(new Bogus)
Alternatively, let's start with a slightly modified version of your method:
def deepCopyPD[A <: FType](_type: A): _type.ThisType = _type.deepCopy()
^path-dependent^
It puts no constraints on ThisType
, but in fact compiler would be able to infer proper versions of it for all cases:
val x: ConcreteType2 = deepCopyPD(new ConcreteType2)
val y: ConcreteType2 = deepCopyPD(new Bogus) // yep, this invocation is possible with such signature
However, it is also possible to further add constraints using type equality evidence as implicit parameter:
def deepCopyPD2[A <: FType](_type: A)(implicit ev: _type.ThisType =:= A): A = _type.deepCopy()
This, once more, forbids the invocation with Bogus
If the types are not exactly the same, how is that deepCopy2 compiles?
That is quite simple. It works because there is no polymorphism involved. It's statically known that ConcreteType2
has deepCopy()
method that returns ConcreteType2
. You could even remove type ThisType
from whole hierarchy and it would still work the same way.
But how, then, can I take advantage of F-bounded types if the F-bounded type is not exactly the same as the type using the F-bounded type?
You need to tell the compiler that it's the same, as you haven't specified enough. Let's take a look at an example that works and is polymorphic:
def deepCopy[A <: FType { type ThisType = A }](_type: A): A = _type.deepCopy()
// ^ --important bit-- ^
This defines a method that works for any A
that is FType
and also it's type member ThisType
is set to A
, tying them together. That means it would work for your definitions of ConcreteType
and ConcreteType2
. It would NOT compile, however, for classes that aren't defined properly, such as this one:
class Bogus extends FType {
override type ThisType = ConcreteType2
override def deepCopy(): ConcreteType2 = new ConcreteType2
}
deepCopy(new Bogus)
Alternatively, let's start with a slightly modified version of your method:
def deepCopyPD[A <: FType](_type: A): _type.ThisType = _type.deepCopy()
^path-dependent^
It puts no constraints on ThisType
, but in fact compiler would be able to infer proper versions of it for all cases:
val x: ConcreteType2 = deepCopyPD(new ConcreteType2)
val y: ConcreteType2 = deepCopyPD(new Bogus) // yep, this invocation is possible with such signature
However, it is also possible to further add constraints using type equality evidence as implicit parameter:
def deepCopyPD2[A <: FType](_type: A)(implicit ev: _type.ThisType =:= A): A = _type.deepCopy()
This, once more, forbids the invocation with Bogus
answered Nov 26 '18 at 12:50
Oleg PyzhcovOleg Pyzhcov
4,6201821
4,6201821
add a comment |
add a comment |
In F-bounded types, you'd normally have ThisType
as a type parameter instead of a type member:
trait FType[ThisType <: FType] {
def deepCopy(): ThisType
}
class ConcreteType extends FType[ConcreteType] {
override def deepCopy(): ConcreteType = this
}
// in object FType
def deepCopy[T <: FType[T]](_type: T): T = {
_type.deepCopy()
}
Note the difference: in FType.deepCopy
the compiler knows that the return type of _type.deepCopy()
is T
.
You can do the same with type members:
def deepCopy[T <: FType { type ThisType <: T }](_type: T): T =
_type.deepCopy()
add a comment |
In F-bounded types, you'd normally have ThisType
as a type parameter instead of a type member:
trait FType[ThisType <: FType] {
def deepCopy(): ThisType
}
class ConcreteType extends FType[ConcreteType] {
override def deepCopy(): ConcreteType = this
}
// in object FType
def deepCopy[T <: FType[T]](_type: T): T = {
_type.deepCopy()
}
Note the difference: in FType.deepCopy
the compiler knows that the return type of _type.deepCopy()
is T
.
You can do the same with type members:
def deepCopy[T <: FType { type ThisType <: T }](_type: T): T =
_type.deepCopy()
add a comment |
In F-bounded types, you'd normally have ThisType
as a type parameter instead of a type member:
trait FType[ThisType <: FType] {
def deepCopy(): ThisType
}
class ConcreteType extends FType[ConcreteType] {
override def deepCopy(): ConcreteType = this
}
// in object FType
def deepCopy[T <: FType[T]](_type: T): T = {
_type.deepCopy()
}
Note the difference: in FType.deepCopy
the compiler knows that the return type of _type.deepCopy()
is T
.
You can do the same with type members:
def deepCopy[T <: FType { type ThisType <: T }](_type: T): T =
_type.deepCopy()
In F-bounded types, you'd normally have ThisType
as a type parameter instead of a type member:
trait FType[ThisType <: FType] {
def deepCopy(): ThisType
}
class ConcreteType extends FType[ConcreteType] {
override def deepCopy(): ConcreteType = this
}
// in object FType
def deepCopy[T <: FType[T]](_type: T): T = {
_type.deepCopy()
}
Note the difference: in FType.deepCopy
the compiler knows that the return type of _type.deepCopy()
is T
.
You can do the same with type members:
def deepCopy[T <: FType { type ThisType <: T }](_type: T): T =
_type.deepCopy()
answered Nov 26 '18 at 12:43
Alexey RomanovAlexey Romanov
111k26215357
111k26215357
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53480975%2ff-bounded-types-and-methods-with-type-parameters-at-argument-and-return-sites%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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