Scala, generic tuple
I have a generic method that can accept any tuple of any size, the only constraint is that the first element of this tuple should be of type MyClass
.
Something like this:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
I've tried this
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
but I get the error unboud wildcard type
scala generics
add a comment |
I have a generic method that can accept any tuple of any size, the only constraint is that the first element of this tuple should be of type MyClass
.
Something like this:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
I've tried this
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
but I get the error unboud wildcard type
scala generics
add a comment |
I have a generic method that can accept any tuple of any size, the only constraint is that the first element of this tuple should be of type MyClass
.
Something like this:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
I've tried this
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
but I get the error unboud wildcard type
scala generics
I have a generic method that can accept any tuple of any size, the only constraint is that the first element of this tuple should be of type MyClass
.
Something like this:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
I've tried this
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
but I get the error unboud wildcard type
scala generics
scala generics
asked Dec 12 '18 at 9:18
Gigitsu
19012
19012
add a comment |
add a comment |
6 Answers
6
active
oldest
votes
It's a little bit unsafe but you can use Structural type in this case:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
2
This is compound type or "structural type" which, unlike "Duck typing", has a clearly-defined meaning is Scala.
– Tim
Dec 12 '18 at 10:25
@Tim, yes thank you I mean structural type.
– mkUltra
Dec 12 '18 at 10:31
1
This was surprisingly simple.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:15
Just to strength constrain you may useProduct { def _1: MyClass }
, but it steel can accept case class withdef _1
– Yuriy
Dec 13 '18 at 1:30
This is very simple to use, thank you. Anyway I had to enable reflective call, am I right?
– Gigitsu
Dec 13 '18 at 13:07
|
show 3 more comments
If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite
type class to put type-level constraints on the first element of a tuple:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
And then:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1@7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1@6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1@108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
If you need to use a trait, you can put the ev
(for "evidence") requirement inside the definition instead of in the constructor:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Now any class instantiating MyTrait
will have to provide evidence that P
is a tuple with MustBeFirst
as its first element.
Probably nitpicking, but I if read shapeless source correctly, IsComposite will also witness that the tuple is of size at least 2. It may be a relevant detail for the asker since tuples of size 1, however awkward, are a thing ^^
– C4stor
Dec 12 '18 at 10:46
@C4stor Good point—I'll update the answer to clarify asap.
– Travis Brown
Dec 12 '18 at 11:19
1
@C4storIsComposite
works forTuple1
, with tail type beingUnit
.
– Oleg Pyzhcov
Dec 12 '18 at 12:19
Oh, interesting ! Shapeless is tricky :D
– C4stor
Dec 12 '18 at 13:18
1
Altought I like this solution and shapeless in general, I don't know how to use this in my case. This is my actual use case: pastebin.com/yCKs0eiQ
– Gigitsu
Dec 13 '18 at 13:02
add a comment |
Scala can't use generic tuple with unknown size because Products don's inherit themeselfs. You can try to use Shapeless or Products from play json lib.
1
Can you clarify what "don't inherit themselves" means here? I don't see what that means or how it would help.
– Travis Brown
Dec 12 '18 at 10:28
Hi :-) The asker didn't specify unknown size but rather any size, which is weaker. For example, shapeless HLists (as you relevantly suggest) are definitely not of unknown size since their size is known at compile time :-) As Travis Brown, I can't quite figure what you mean in this answer, clarifying would be very helpful :-)
– C4stor
Dec 12 '18 at 10:49
add a comment |
You need to inherit your trait from Product
, through which you can have productIterator
, productArity
and, productElement
to handle the returned value. Here is an example
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
And you can invoke like this
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
Hope this helps you.
add a comment |
As others said you can use shapeless:
import shapeless.ops.tuple.IsComposite
import shapeless.syntax.std.tuple._
class MyClass(i : Int){
def hello() = println(i)
}
object Tup extends App {
def getMyClass[P <: Product](p: P)(implicit ev: IsComposite[P]): MyClass = {
if (p.head.isInstanceOf[MyClass]) p.head.asInstanceOf[MyClass] else throw new Exception()
}
val x= (new MyClass(1),5,6)
val y = (new MyClass(2),7)
val c = getMyClass(x)
val c1 = getMyClass(y)
c.hello()
c1.hello()
val c2 = getMyClass((1,5,6,7)) // exception
c2.hello()
}
This doesn't provide any type-safety—the failure happens at runtime, not compile-time. You're not actually doing anything with Shapeless here beyond restricting the tuple to have more than one element, which isn't explicitly a requirement, anyway.
– Travis Brown
Dec 12 '18 at 11:34
@travis fair enough - though I shapeless is also used to get the first element from the tuple regardless of it and I understood that the question as 1. accept tuples of any size.2 get the MyClass from the first element from the tuple (which by the way your suggested solution does not actually do)
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 12:34
Why all the casting, then?
– Travis Brown
Dec 12 '18 at 12:38
@TravisBrown, as I said you're right about that -, could have been done better (e.g. what you did) but it does actually answer the q (how to implement getMyClass(x: T): MyClass = x._1 which works) - your solution is missing a def getMyClass(p: P) : MyClass = p.head to actually answer the question (and be typesafe )
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 13:19
add a comment |
If you are looking for compile time guarantee then this is one of the use cases for
Shapeless,
You need to add Shapeless in your build.sbt
,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
Now, you can use Shapeless to define a typesafe getter which comes with compile time guarantees,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
Now if you want to enrich your tuples with a "first" getter with a specific type then,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
If you don't need the implicit enrichment and are just looking for a way to "lock" the type in a getter and use it for corresponding types,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)
What is the "compile time guarantee" here? The OP has requested that tuples of any length, but only with the 1st element of a specific type, be accepted. (Not my down-vote.)
– jwvh
Dec 12 '18 at 11:52
@jwvh You are right. Fixed.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:08
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%2f53739656%2fscala-generic-tuple%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
It's a little bit unsafe but you can use Structural type in this case:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
2
This is compound type or "structural type" which, unlike "Duck typing", has a clearly-defined meaning is Scala.
– Tim
Dec 12 '18 at 10:25
@Tim, yes thank you I mean structural type.
– mkUltra
Dec 12 '18 at 10:31
1
This was surprisingly simple.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:15
Just to strength constrain you may useProduct { def _1: MyClass }
, but it steel can accept case class withdef _1
– Yuriy
Dec 13 '18 at 1:30
This is very simple to use, thank you. Anyway I had to enable reflective call, am I right?
– Gigitsu
Dec 13 '18 at 13:07
|
show 3 more comments
It's a little bit unsafe but you can use Structural type in this case:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
2
This is compound type or "structural type" which, unlike "Duck typing", has a clearly-defined meaning is Scala.
– Tim
Dec 12 '18 at 10:25
@Tim, yes thank you I mean structural type.
– mkUltra
Dec 12 '18 at 10:31
1
This was surprisingly simple.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:15
Just to strength constrain you may useProduct { def _1: MyClass }
, but it steel can accept case class withdef _1
– Yuriy
Dec 13 '18 at 1:30
This is very simple to use, thank you. Anyway I had to enable reflective call, am I right?
– Gigitsu
Dec 13 '18 at 13:07
|
show 3 more comments
It's a little bit unsafe but you can use Structural type in this case:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
It's a little bit unsafe but you can use Structural type in this case:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
edited Dec 12 '18 at 10:31
answered Dec 12 '18 at 10:09
mkUltra
599620
599620
2
This is compound type or "structural type" which, unlike "Duck typing", has a clearly-defined meaning is Scala.
– Tim
Dec 12 '18 at 10:25
@Tim, yes thank you I mean structural type.
– mkUltra
Dec 12 '18 at 10:31
1
This was surprisingly simple.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:15
Just to strength constrain you may useProduct { def _1: MyClass }
, but it steel can accept case class withdef _1
– Yuriy
Dec 13 '18 at 1:30
This is very simple to use, thank you. Anyway I had to enable reflective call, am I right?
– Gigitsu
Dec 13 '18 at 13:07
|
show 3 more comments
2
This is compound type or "structural type" which, unlike "Duck typing", has a clearly-defined meaning is Scala.
– Tim
Dec 12 '18 at 10:25
@Tim, yes thank you I mean structural type.
– mkUltra
Dec 12 '18 at 10:31
1
This was surprisingly simple.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:15
Just to strength constrain you may useProduct { def _1: MyClass }
, but it steel can accept case class withdef _1
– Yuriy
Dec 13 '18 at 1:30
This is very simple to use, thank you. Anyway I had to enable reflective call, am I right?
– Gigitsu
Dec 13 '18 at 13:07
2
2
This is compound type or "structural type" which, unlike "Duck typing", has a clearly-defined meaning is Scala.
– Tim
Dec 12 '18 at 10:25
This is compound type or "structural type" which, unlike "Duck typing", has a clearly-defined meaning is Scala.
– Tim
Dec 12 '18 at 10:25
@Tim, yes thank you I mean structural type.
– mkUltra
Dec 12 '18 at 10:31
@Tim, yes thank you I mean structural type.
– mkUltra
Dec 12 '18 at 10:31
1
1
This was surprisingly simple.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:15
This was surprisingly simple.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:15
Just to strength constrain you may use
Product { def _1: MyClass }
, but it steel can accept case class with def _1
– Yuriy
Dec 13 '18 at 1:30
Just to strength constrain you may use
Product { def _1: MyClass }
, but it steel can accept case class with def _1
– Yuriy
Dec 13 '18 at 1:30
This is very simple to use, thank you. Anyway I had to enable reflective call, am I right?
– Gigitsu
Dec 13 '18 at 13:07
This is very simple to use, thank you. Anyway I had to enable reflective call, am I right?
– Gigitsu
Dec 13 '18 at 13:07
|
show 3 more comments
If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite
type class to put type-level constraints on the first element of a tuple:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
And then:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1@7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1@6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1@108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
If you need to use a trait, you can put the ev
(for "evidence") requirement inside the definition instead of in the constructor:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Now any class instantiating MyTrait
will have to provide evidence that P
is a tuple with MustBeFirst
as its first element.
Probably nitpicking, but I if read shapeless source correctly, IsComposite will also witness that the tuple is of size at least 2. It may be a relevant detail for the asker since tuples of size 1, however awkward, are a thing ^^
– C4stor
Dec 12 '18 at 10:46
@C4stor Good point—I'll update the answer to clarify asap.
– Travis Brown
Dec 12 '18 at 11:19
1
@C4storIsComposite
works forTuple1
, with tail type beingUnit
.
– Oleg Pyzhcov
Dec 12 '18 at 12:19
Oh, interesting ! Shapeless is tricky :D
– C4stor
Dec 12 '18 at 13:18
1
Altought I like this solution and shapeless in general, I don't know how to use this in my case. This is my actual use case: pastebin.com/yCKs0eiQ
– Gigitsu
Dec 13 '18 at 13:02
add a comment |
If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite
type class to put type-level constraints on the first element of a tuple:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
And then:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1@7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1@6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1@108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
If you need to use a trait, you can put the ev
(for "evidence") requirement inside the definition instead of in the constructor:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Now any class instantiating MyTrait
will have to provide evidence that P
is a tuple with MustBeFirst
as its first element.
Probably nitpicking, but I if read shapeless source correctly, IsComposite will also witness that the tuple is of size at least 2. It may be a relevant detail for the asker since tuples of size 1, however awkward, are a thing ^^
– C4stor
Dec 12 '18 at 10:46
@C4stor Good point—I'll update the answer to clarify asap.
– Travis Brown
Dec 12 '18 at 11:19
1
@C4storIsComposite
works forTuple1
, with tail type beingUnit
.
– Oleg Pyzhcov
Dec 12 '18 at 12:19
Oh, interesting ! Shapeless is tricky :D
– C4stor
Dec 12 '18 at 13:18
1
Altought I like this solution and shapeless in general, I don't know how to use this in my case. This is my actual use case: pastebin.com/yCKs0eiQ
– Gigitsu
Dec 13 '18 at 13:02
add a comment |
If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite
type class to put type-level constraints on the first element of a tuple:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
And then:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1@7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1@6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1@108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
If you need to use a trait, you can put the ev
(for "evidence") requirement inside the definition instead of in the constructor:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Now any class instantiating MyTrait
will have to provide evidence that P
is a tuple with MustBeFirst
as its first element.
If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite
type class to put type-level constraints on the first element of a tuple:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
And then:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1@7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1@6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1@108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
If you need to use a trait, you can put the ev
(for "evidence") requirement inside the definition instead of in the constructor:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Now any class instantiating MyTrait
will have to provide evidence that P
is a tuple with MustBeFirst
as its first element.
edited Dec 12 '18 at 12:38
answered Dec 12 '18 at 10:17
Travis Brown
112k9284533
112k9284533
Probably nitpicking, but I if read shapeless source correctly, IsComposite will also witness that the tuple is of size at least 2. It may be a relevant detail for the asker since tuples of size 1, however awkward, are a thing ^^
– C4stor
Dec 12 '18 at 10:46
@C4stor Good point—I'll update the answer to clarify asap.
– Travis Brown
Dec 12 '18 at 11:19
1
@C4storIsComposite
works forTuple1
, with tail type beingUnit
.
– Oleg Pyzhcov
Dec 12 '18 at 12:19
Oh, interesting ! Shapeless is tricky :D
– C4stor
Dec 12 '18 at 13:18
1
Altought I like this solution and shapeless in general, I don't know how to use this in my case. This is my actual use case: pastebin.com/yCKs0eiQ
– Gigitsu
Dec 13 '18 at 13:02
add a comment |
Probably nitpicking, but I if read shapeless source correctly, IsComposite will also witness that the tuple is of size at least 2. It may be a relevant detail for the asker since tuples of size 1, however awkward, are a thing ^^
– C4stor
Dec 12 '18 at 10:46
@C4stor Good point—I'll update the answer to clarify asap.
– Travis Brown
Dec 12 '18 at 11:19
1
@C4storIsComposite
works forTuple1
, with tail type beingUnit
.
– Oleg Pyzhcov
Dec 12 '18 at 12:19
Oh, interesting ! Shapeless is tricky :D
– C4stor
Dec 12 '18 at 13:18
1
Altought I like this solution and shapeless in general, I don't know how to use this in my case. This is my actual use case: pastebin.com/yCKs0eiQ
– Gigitsu
Dec 13 '18 at 13:02
Probably nitpicking, but I if read shapeless source correctly, IsComposite will also witness that the tuple is of size at least 2. It may be a relevant detail for the asker since tuples of size 1, however awkward, are a thing ^^
– C4stor
Dec 12 '18 at 10:46
Probably nitpicking, but I if read shapeless source correctly, IsComposite will also witness that the tuple is of size at least 2. It may be a relevant detail for the asker since tuples of size 1, however awkward, are a thing ^^
– C4stor
Dec 12 '18 at 10:46
@C4stor Good point—I'll update the answer to clarify asap.
– Travis Brown
Dec 12 '18 at 11:19
@C4stor Good point—I'll update the answer to clarify asap.
– Travis Brown
Dec 12 '18 at 11:19
1
1
@C4stor
IsComposite
works for Tuple1
, with tail type being Unit
.– Oleg Pyzhcov
Dec 12 '18 at 12:19
@C4stor
IsComposite
works for Tuple1
, with tail type being Unit
.– Oleg Pyzhcov
Dec 12 '18 at 12:19
Oh, interesting ! Shapeless is tricky :D
– C4stor
Dec 12 '18 at 13:18
Oh, interesting ! Shapeless is tricky :D
– C4stor
Dec 12 '18 at 13:18
1
1
Altought I like this solution and shapeless in general, I don't know how to use this in my case. This is my actual use case: pastebin.com/yCKs0eiQ
– Gigitsu
Dec 13 '18 at 13:02
Altought I like this solution and shapeless in general, I don't know how to use this in my case. This is my actual use case: pastebin.com/yCKs0eiQ
– Gigitsu
Dec 13 '18 at 13:02
add a comment |
Scala can't use generic tuple with unknown size because Products don's inherit themeselfs. You can try to use Shapeless or Products from play json lib.
1
Can you clarify what "don't inherit themselves" means here? I don't see what that means or how it would help.
– Travis Brown
Dec 12 '18 at 10:28
Hi :-) The asker didn't specify unknown size but rather any size, which is weaker. For example, shapeless HLists (as you relevantly suggest) are definitely not of unknown size since their size is known at compile time :-) As Travis Brown, I can't quite figure what you mean in this answer, clarifying would be very helpful :-)
– C4stor
Dec 12 '18 at 10:49
add a comment |
Scala can't use generic tuple with unknown size because Products don's inherit themeselfs. You can try to use Shapeless or Products from play json lib.
1
Can you clarify what "don't inherit themselves" means here? I don't see what that means or how it would help.
– Travis Brown
Dec 12 '18 at 10:28
Hi :-) The asker didn't specify unknown size but rather any size, which is weaker. For example, shapeless HLists (as you relevantly suggest) are definitely not of unknown size since their size is known at compile time :-) As Travis Brown, I can't quite figure what you mean in this answer, clarifying would be very helpful :-)
– C4stor
Dec 12 '18 at 10:49
add a comment |
Scala can't use generic tuple with unknown size because Products don's inherit themeselfs. You can try to use Shapeless or Products from play json lib.
Scala can't use generic tuple with unknown size because Products don's inherit themeselfs. You can try to use Shapeless or Products from play json lib.
answered Dec 12 '18 at 9:33
Ivan Aristov
923
923
1
Can you clarify what "don't inherit themselves" means here? I don't see what that means or how it would help.
– Travis Brown
Dec 12 '18 at 10:28
Hi :-) The asker didn't specify unknown size but rather any size, which is weaker. For example, shapeless HLists (as you relevantly suggest) are definitely not of unknown size since their size is known at compile time :-) As Travis Brown, I can't quite figure what you mean in this answer, clarifying would be very helpful :-)
– C4stor
Dec 12 '18 at 10:49
add a comment |
1
Can you clarify what "don't inherit themselves" means here? I don't see what that means or how it would help.
– Travis Brown
Dec 12 '18 at 10:28
Hi :-) The asker didn't specify unknown size but rather any size, which is weaker. For example, shapeless HLists (as you relevantly suggest) are definitely not of unknown size since their size is known at compile time :-) As Travis Brown, I can't quite figure what you mean in this answer, clarifying would be very helpful :-)
– C4stor
Dec 12 '18 at 10:49
1
1
Can you clarify what "don't inherit themselves" means here? I don't see what that means or how it would help.
– Travis Brown
Dec 12 '18 at 10:28
Can you clarify what "don't inherit themselves" means here? I don't see what that means or how it would help.
– Travis Brown
Dec 12 '18 at 10:28
Hi :-) The asker didn't specify unknown size but rather any size, which is weaker. For example, shapeless HLists (as you relevantly suggest) are definitely not of unknown size since their size is known at compile time :-) As Travis Brown, I can't quite figure what you mean in this answer, clarifying would be very helpful :-)
– C4stor
Dec 12 '18 at 10:49
Hi :-) The asker didn't specify unknown size but rather any size, which is weaker. For example, shapeless HLists (as you relevantly suggest) are definitely not of unknown size since their size is known at compile time :-) As Travis Brown, I can't quite figure what you mean in this answer, clarifying would be very helpful :-)
– C4stor
Dec 12 '18 at 10:49
add a comment |
You need to inherit your trait from Product
, through which you can have productIterator
, productArity
and, productElement
to handle the returned value. Here is an example
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
And you can invoke like this
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
Hope this helps you.
add a comment |
You need to inherit your trait from Product
, through which you can have productIterator
, productArity
and, productElement
to handle the returned value. Here is an example
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
And you can invoke like this
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
Hope this helps you.
add a comment |
You need to inherit your trait from Product
, through which you can have productIterator
, productArity
and, productElement
to handle the returned value. Here is an example
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
And you can invoke like this
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
Hope this helps you.
You need to inherit your trait from Product
, through which you can have productIterator
, productArity
and, productElement
to handle the returned value. Here is an example
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
And you can invoke like this
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
Hope this helps you.
edited Dec 12 '18 at 10:00
answered Dec 12 '18 at 9:45
Puneeth Reddy V
854715
854715
add a comment |
add a comment |
As others said you can use shapeless:
import shapeless.ops.tuple.IsComposite
import shapeless.syntax.std.tuple._
class MyClass(i : Int){
def hello() = println(i)
}
object Tup extends App {
def getMyClass[P <: Product](p: P)(implicit ev: IsComposite[P]): MyClass = {
if (p.head.isInstanceOf[MyClass]) p.head.asInstanceOf[MyClass] else throw new Exception()
}
val x= (new MyClass(1),5,6)
val y = (new MyClass(2),7)
val c = getMyClass(x)
val c1 = getMyClass(y)
c.hello()
c1.hello()
val c2 = getMyClass((1,5,6,7)) // exception
c2.hello()
}
This doesn't provide any type-safety—the failure happens at runtime, not compile-time. You're not actually doing anything with Shapeless here beyond restricting the tuple to have more than one element, which isn't explicitly a requirement, anyway.
– Travis Brown
Dec 12 '18 at 11:34
@travis fair enough - though I shapeless is also used to get the first element from the tuple regardless of it and I understood that the question as 1. accept tuples of any size.2 get the MyClass from the first element from the tuple (which by the way your suggested solution does not actually do)
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 12:34
Why all the casting, then?
– Travis Brown
Dec 12 '18 at 12:38
@TravisBrown, as I said you're right about that -, could have been done better (e.g. what you did) but it does actually answer the q (how to implement getMyClass(x: T): MyClass = x._1 which works) - your solution is missing a def getMyClass(p: P) : MyClass = p.head to actually answer the question (and be typesafe )
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 13:19
add a comment |
As others said you can use shapeless:
import shapeless.ops.tuple.IsComposite
import shapeless.syntax.std.tuple._
class MyClass(i : Int){
def hello() = println(i)
}
object Tup extends App {
def getMyClass[P <: Product](p: P)(implicit ev: IsComposite[P]): MyClass = {
if (p.head.isInstanceOf[MyClass]) p.head.asInstanceOf[MyClass] else throw new Exception()
}
val x= (new MyClass(1),5,6)
val y = (new MyClass(2),7)
val c = getMyClass(x)
val c1 = getMyClass(y)
c.hello()
c1.hello()
val c2 = getMyClass((1,5,6,7)) // exception
c2.hello()
}
This doesn't provide any type-safety—the failure happens at runtime, not compile-time. You're not actually doing anything with Shapeless here beyond restricting the tuple to have more than one element, which isn't explicitly a requirement, anyway.
– Travis Brown
Dec 12 '18 at 11:34
@travis fair enough - though I shapeless is also used to get the first element from the tuple regardless of it and I understood that the question as 1. accept tuples of any size.2 get the MyClass from the first element from the tuple (which by the way your suggested solution does not actually do)
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 12:34
Why all the casting, then?
– Travis Brown
Dec 12 '18 at 12:38
@TravisBrown, as I said you're right about that -, could have been done better (e.g. what you did) but it does actually answer the q (how to implement getMyClass(x: T): MyClass = x._1 which works) - your solution is missing a def getMyClass(p: P) : MyClass = p.head to actually answer the question (and be typesafe )
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 13:19
add a comment |
As others said you can use shapeless:
import shapeless.ops.tuple.IsComposite
import shapeless.syntax.std.tuple._
class MyClass(i : Int){
def hello() = println(i)
}
object Tup extends App {
def getMyClass[P <: Product](p: P)(implicit ev: IsComposite[P]): MyClass = {
if (p.head.isInstanceOf[MyClass]) p.head.asInstanceOf[MyClass] else throw new Exception()
}
val x= (new MyClass(1),5,6)
val y = (new MyClass(2),7)
val c = getMyClass(x)
val c1 = getMyClass(y)
c.hello()
c1.hello()
val c2 = getMyClass((1,5,6,7)) // exception
c2.hello()
}
As others said you can use shapeless:
import shapeless.ops.tuple.IsComposite
import shapeless.syntax.std.tuple._
class MyClass(i : Int){
def hello() = println(i)
}
object Tup extends App {
def getMyClass[P <: Product](p: P)(implicit ev: IsComposite[P]): MyClass = {
if (p.head.isInstanceOf[MyClass]) p.head.asInstanceOf[MyClass] else throw new Exception()
}
val x= (new MyClass(1),5,6)
val y = (new MyClass(2),7)
val c = getMyClass(x)
val c1 = getMyClass(y)
c.hello()
c1.hello()
val c2 = getMyClass((1,5,6,7)) // exception
c2.hello()
}
answered Dec 12 '18 at 10:53
Arnon Rotem-Gal-Oz
19k13460
19k13460
This doesn't provide any type-safety—the failure happens at runtime, not compile-time. You're not actually doing anything with Shapeless here beyond restricting the tuple to have more than one element, which isn't explicitly a requirement, anyway.
– Travis Brown
Dec 12 '18 at 11:34
@travis fair enough - though I shapeless is also used to get the first element from the tuple regardless of it and I understood that the question as 1. accept tuples of any size.2 get the MyClass from the first element from the tuple (which by the way your suggested solution does not actually do)
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 12:34
Why all the casting, then?
– Travis Brown
Dec 12 '18 at 12:38
@TravisBrown, as I said you're right about that -, could have been done better (e.g. what you did) but it does actually answer the q (how to implement getMyClass(x: T): MyClass = x._1 which works) - your solution is missing a def getMyClass(p: P) : MyClass = p.head to actually answer the question (and be typesafe )
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 13:19
add a comment |
This doesn't provide any type-safety—the failure happens at runtime, not compile-time. You're not actually doing anything with Shapeless here beyond restricting the tuple to have more than one element, which isn't explicitly a requirement, anyway.
– Travis Brown
Dec 12 '18 at 11:34
@travis fair enough - though I shapeless is also used to get the first element from the tuple regardless of it and I understood that the question as 1. accept tuples of any size.2 get the MyClass from the first element from the tuple (which by the way your suggested solution does not actually do)
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 12:34
Why all the casting, then?
– Travis Brown
Dec 12 '18 at 12:38
@TravisBrown, as I said you're right about that -, could have been done better (e.g. what you did) but it does actually answer the q (how to implement getMyClass(x: T): MyClass = x._1 which works) - your solution is missing a def getMyClass(p: P) : MyClass = p.head to actually answer the question (and be typesafe )
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 13:19
This doesn't provide any type-safety—the failure happens at runtime, not compile-time. You're not actually doing anything with Shapeless here beyond restricting the tuple to have more than one element, which isn't explicitly a requirement, anyway.
– Travis Brown
Dec 12 '18 at 11:34
This doesn't provide any type-safety—the failure happens at runtime, not compile-time. You're not actually doing anything with Shapeless here beyond restricting the tuple to have more than one element, which isn't explicitly a requirement, anyway.
– Travis Brown
Dec 12 '18 at 11:34
@travis fair enough - though I shapeless is also used to get the first element from the tuple regardless of it and I understood that the question as 1. accept tuples of any size.2 get the MyClass from the first element from the tuple (which by the way your suggested solution does not actually do)
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 12:34
@travis fair enough - though I shapeless is also used to get the first element from the tuple regardless of it and I understood that the question as 1. accept tuples of any size.2 get the MyClass from the first element from the tuple (which by the way your suggested solution does not actually do)
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 12:34
Why all the casting, then?
– Travis Brown
Dec 12 '18 at 12:38
Why all the casting, then?
– Travis Brown
Dec 12 '18 at 12:38
@TravisBrown, as I said you're right about that -, could have been done better (e.g. what you did) but it does actually answer the q (how to implement getMyClass(x: T): MyClass = x._1 which works) - your solution is missing a def getMyClass(p: P) : MyClass = p.head to actually answer the question (and be typesafe )
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 13:19
@TravisBrown, as I said you're right about that -, could have been done better (e.g. what you did) but it does actually answer the q (how to implement getMyClass(x: T): MyClass = x._1 which works) - your solution is missing a def getMyClass(p: P) : MyClass = p.head to actually answer the question (and be typesafe )
– Arnon Rotem-Gal-Oz
Dec 12 '18 at 13:19
add a comment |
If you are looking for compile time guarantee then this is one of the use cases for
Shapeless,
You need to add Shapeless in your build.sbt
,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
Now, you can use Shapeless to define a typesafe getter which comes with compile time guarantees,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
Now if you want to enrich your tuples with a "first" getter with a specific type then,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
If you don't need the implicit enrichment and are just looking for a way to "lock" the type in a getter and use it for corresponding types,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)
What is the "compile time guarantee" here? The OP has requested that tuples of any length, but only with the 1st element of a specific type, be accepted. (Not my down-vote.)
– jwvh
Dec 12 '18 at 11:52
@jwvh You are right. Fixed.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:08
add a comment |
If you are looking for compile time guarantee then this is one of the use cases for
Shapeless,
You need to add Shapeless in your build.sbt
,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
Now, you can use Shapeless to define a typesafe getter which comes with compile time guarantees,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
Now if you want to enrich your tuples with a "first" getter with a specific type then,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
If you don't need the implicit enrichment and are just looking for a way to "lock" the type in a getter and use it for corresponding types,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)
What is the "compile time guarantee" here? The OP has requested that tuples of any length, but only with the 1st element of a specific type, be accepted. (Not my down-vote.)
– jwvh
Dec 12 '18 at 11:52
@jwvh You are right. Fixed.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:08
add a comment |
If you are looking for compile time guarantee then this is one of the use cases for
Shapeless,
You need to add Shapeless in your build.sbt
,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
Now, you can use Shapeless to define a typesafe getter which comes with compile time guarantees,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
Now if you want to enrich your tuples with a "first" getter with a specific type then,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
If you don't need the implicit enrichment and are just looking for a way to "lock" the type in a getter and use it for corresponding types,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)
If you are looking for compile time guarantee then this is one of the use cases for
Shapeless,
You need to add Shapeless in your build.sbt
,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
Now, you can use Shapeless to define a typesafe getter which comes with compile time guarantees,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
Now if you want to enrich your tuples with a "first" getter with a specific type then,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
If you don't need the implicit enrichment and are just looking for a way to "lock" the type in a getter and use it for corresponding types,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)
edited Dec 12 '18 at 14:08
answered Dec 12 '18 at 11:32
Sarvesh Kumar Singh
8,0911634
8,0911634
What is the "compile time guarantee" here? The OP has requested that tuples of any length, but only with the 1st element of a specific type, be accepted. (Not my down-vote.)
– jwvh
Dec 12 '18 at 11:52
@jwvh You are right. Fixed.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:08
add a comment |
What is the "compile time guarantee" here? The OP has requested that tuples of any length, but only with the 1st element of a specific type, be accepted. (Not my down-vote.)
– jwvh
Dec 12 '18 at 11:52
@jwvh You are right. Fixed.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:08
What is the "compile time guarantee" here? The OP has requested that tuples of any length, but only with the 1st element of a specific type, be accepted. (Not my down-vote.)
– jwvh
Dec 12 '18 at 11:52
What is the "compile time guarantee" here? The OP has requested that tuples of any length, but only with the 1st element of a specific type, be accepted. (Not my down-vote.)
– jwvh
Dec 12 '18 at 11:52
@jwvh You are right. Fixed.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:08
@jwvh You are right. Fixed.
– Sarvesh Kumar Singh
Dec 12 '18 at 14:08
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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%2f53739656%2fscala-generic-tuple%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