Suppose I have types A, B, and C, and an overloaded method:
def foo(a: A): C
def foo(b: B): C
Then suppose I have a (complicated) piece of code that works with objects of type C. What I would like to have is a method that takes either type A or B:
def bar(x: [A or B]) = {
val c = foo(x)
// Code that works with c
}
Of course I could write two versions of bar, overloaded to take types A and B, but in this case, there are multiple functions that behave like bar, and it would be silly to have overloaded versions (in my actual case, there are three versions of foo) for all of them.
C-style macros would be perfect here, so I thought to look into Scala macros. The awkward part is that Scala macros are still typed-checked, so I can't just say
reify(foo(x.splice))
since the compiler wants to know the type of x beforehand. I'm entirely new to using Scala macros (and it's a substantial API), so some pointers in this regard would be appreciated.
Or if there's a way to layout this code without macros, that would be helpful too!
You can solve your problem differently.
Instead of say type A or B think about what you want from those types. In your example it would be enough if you said: "It doesn't matter what type it is, as long as I have a foo method for it". That's what the code below shows:
trait FooMethod[T] {
def apply(t:T):C
}
object FooMethod {
implicit val forA = new FooMethod[A] {
def apply(a:A):C = foo(a)
}
implicit val forB = new FooMethod[B] {
def apply(b:B):C = foo(b)
}
}
def bar[X](x: X)(implicit foo:FooMethod[X]) = {
val c = foo(x)
// Code that works with c
}
Related
Suppose you have a trait like this:
trait Foo[A]{
def foo: A
}
I want to create a function like this:
def getFoo[A <: Foo[_]](a: A) = a.foo
The Scala Compiler deduces Any for the return type of this function.
How can I reference the anonymous parameter _ in the signature (or body) of getFoo?
In other words, how can I un-anonymize the parameter?
I want to be able to use the function like
object ConcreteFoo extends Foo[String] {
override def foo: String = "hello"
}
val x : String = getFoo(ConcreteFoo)
which fails compilation for obvious reasons, because getFoo is implicitly declared as Any.
If this is not possible with Scala (2.12 for that matter), I'd be interested in the rational or the technical reason for this limitation.
I am sure there are articles and existing questions about this, but I appear to be lacking the correct search terms.
Update: The existing answer accurately answers my question as stated, but I suppose I wasn't accurate enough regarding my actual usecase. Sorry for the confusion. I want to be able to write
def getFoo[A <: Foo[_]] = (a: A) => a.foo
val f = getFoo[ConcreteFoo.type]
//In some other, unrelated place
val x = f(ConcreteFoo)
Because I don't have a parameter of type A, the compiler can't deduce the parameters R and A if I do
def getFoo[R, A <: Foo[R]]: (A => R) = (a: A) => a.foo
like suggested. I would like to avoid manually having to supply the type parameter R (String in this case), because it feels redundant.
To answer literally your exact question:
def getFoo[R, A <: Foo[R]](a: A): R = a.foo
But since you don't make any use of the type A, you can actually omit it and the <: Foo[..] bound completely, retaining only the return type:
def getFoo[R](a: Foo[R]): R = a.foo
Update (the question has been changed quite significantly)
You could smuggle in an additional apply invocation that infers the return type from a separate implicit return type witness:
trait Foo[A] { def foo: A }
/** This is the thing that remembers the actual return type of `foo`
* for a given `A <: Foo[R]`.
*/
trait RetWitness[A, R] extends (A => R)
/** This is just syntactic sugar to hide an additional `apply[R]()`
* invocation that infers the actual return type `R`, so you don't
* have to type it in manually.
*/
class RetWitnessConstructor[A] {
def apply[R]()(implicit w: RetWitness[A, R]): A => R = w
}
def getFoo[A <: Foo[_]] = new RetWitnessConstructor[A]
Now it looks almost like what you wanted, but you have to provide the implicit, and you have to call getFoo[ConcreteFoo.type]() with additional pair of round parens:
object ConcreteFoo extends Foo[String] {
override def foo: String = "hey"
}
implicit val cfrw = new RetWitness[ConcreteFoo.type, String] {
def apply(c: ConcreteFoo.type): String = c.foo
}
val f = getFoo[ConcreteFoo.type]()
val x: String = f(ConcreteFoo)
I'm not sure whether it's really worth it, it's not necessarily the most straightforward thing to do. Type-level computations with implicits, hidden behind somewhat subtle syntactic sugar: that might be too much magic hidden behind those two parens (). Unless you expect that the return type of foo will change very often, it might be easier to just add a second generic argument to getFoo, and write out the return type explicitly.
This doesn't compile:
class MyClass[+A] {
def myMethod(a: A): A = a
}
//error: covariant type A occurs in contravariant position in type A of value a
Alright, fair enough. But this does compile:
class MyClass[+A]
implicit class MyImplicitClass[A](mc: MyClass[A]) {
def myMethod(a: A): A = a
}
Which lets us circumvent whatever problems the variance checks are giving us:
class MyClass[+A] {
def myMethod[B >: A](b: B): B = b //B >: A => B
}
implicit class MyImplicitClass[A](mc: MyClass[A]) {
def myExtensionMethod(a: A): A = mc.myMethod(a) //A => A!!
}
val foo = new MyClass[String]
//foo: MyClass[String] = MyClass#4c273e6c
foo.myExtensionMethod("Welp.")
//res0: String = Welp.
foo.myExtensionMethod(new Object())
//error: type mismatch
This feels like cheating. Should it be avoided? Or is there some legitimate reason why the compiler lets it slide?
Update:
Consider this for example:
class CovariantSet[+A] {
private def contains_[B >: A](b: B): Boolean = ???
}
object CovariantSet {
implicit class ImpCovSet[A](cs: CovariantSet[A]) {
def contains(a: A): Boolean = cs.contains_(a)
}
}
It certainly appears we've managed to achieve the impossible: a covariant "set" that still satisfies A => Boolean. But if this is impossible, shouldn't the compiler disallow it?
I don't think it's cheating any more than the version after desugaring is:
val foo: MyClass[String] = ...
new MyImplicitClass(foo).myExtensionMethod("Welp.") // compiles
new MyImplicitClass(foo).myExtensionMethod(new Object()) // doesn't
The reason is that the type parameter on MyImplicitClass constructor gets inferred before myExtensionMethod is considered.
Initially I wanted to say it doesn't let you "circumvent whatever problems the variance checks are giving us", because the extension method needs to be expressed in terms of variance-legal methods, but this is wrong: it can be defined in the companion object and use private state.
The only problem I see is that it might be confusing for people modifying the code (not even reading it, since those won't see non-compiling code). I wouldn't expect it to be a big problem, but without trying in practice it's hard to be sure.
You did not achieve the impossible. You just chose a trade-off that is different from that in the standard library.
What you lost
The signature
def contains[B >: A](b: B): Boolean
forces you to implement your covariant Set in a way that works for Any, because B is completely unconstrained. That means:
No BitSets for Ints only
No Orderings
No custom hashing functions.
This signature forces you to implement essentially a Set[Any].
What you gained
An easily circumventable facade:
val x: CovariantSet[Int] = ???
(x: CovariantSet[Any]).contains("stuff it cannot possibly contain")
compiles just fine. It means that your set x, which has been constructed as a set of integers, and can therefore contain only integers, will be forced to invoke the method contains at runtime to determine whether it contains a String or not, despite the fact that it cannot possibly contain any Strings. So again, the type system doesn't help you in any way to eliminate such nonsensical queries which will always yield a false.
I would prefer to work more with type-classes but having some issues:
Given the following interface
trait Processor[A] {
def process[B](f: A => B): Processor[B]
}
I have an implementation that needs an Ordering[A] for some other reasons. Hence the method process needs an Ordering[B] to construct a Processor[B].The following is what I would like to do, but it does obviously not work:
class Plant[A, OA <: Ordering[A]] extends Processor[A] {
def process[B:Ordering](f: A => B): Processor[B] = null // Plant[B, OB <: Ordering[B]]
}
How can I provide the Ordering[B] for the implementation of process?
I know the reason for this is, that Ordering[A] is passed as an implicit second argument. I don't know but shouldn't there be special support for type-classes in Scala similar to Haskell to recognize what I want (only allow Bs that have an Ordering) in the implementation above without this "workaround"?
No, and this shouldn't work at all. Given your defnition of Processor, this code will compile:
val processor: Processor[Int] = foo() // foo() is some function that returns a Processor
processor.process[Object](x => new Object())
Now if foo is actually implemented as
def foo() = new Plant[Int]()
then its process method won't work with B = Object.
I'm not sure I fully understand what you're trying to achieve, but perhaps you could make Processor generic on the context bound?
trait Processor[A, Bound[_]] {
def process[B: Bound](f: A => B): Processor[B, Any]
}
class Plant[A: Ordering] extends Processor[A, Ordering] {
def process[B: Ordering](f: A => B) = ???
}
Okay, fair warning: this is a follow-up to my ridiculous question from last week. Although I think this question isn't as ridiculous. Anyway, here goes:
Previous ridiculous question:
Assume I have some base trait T with subclasses A, B and C, I can declare a collection Seq[T] for example, that can contain values of type A, B and C. Making the subtyping more explicit, let's use the Seq[_ <: T] type bound syntax.
Now instead assume I have a typeclass TC[_] with members A, B and C (where "member" means the compiler can find some TC[A], etc. in implicit scope). Similar to above, I want to declare a collection of type Seq[_ : TC], using context bound syntax.
This isn't legal Scala, and attempting to emulate may make you feel like a bad person. Remember that context bound syntax (when used correctly!) desugars into an implicit parameter list for the class or method being defined, which doesn't make any sense here.
New premise:
So let's assume that typeclass instances (i.e. implicit values) are out of the question, and instead we need to use implicit conversions in this case. I have some type V (the "v" is supposed to stand for "view," fwiw), and implicit conversions in scope A => V, B => V and C => V. Now I can populate a Seq[V], despite A, B and C being otherwise unrelated.
But what if I want a collection of things that are implicitly convertible both to views V1 and V2? I can't say Seq[V1 with V2] because my implicit conversions don't magically aggregate that way.
Intersection of implicit conversions?
I solved my problem like this:
// a sort of product or intersection, basically identical to Tuple2
final class &[A, B](val a: A, val b: B)
// implicit conversions from the product to its member types
implicit def productToA[A, B](ab: A & B): A = ab.a
implicit def productToB[A, B](ab: A & B): B = ab.b
// implicit conversion from A to (V1 & V2)
implicit def viewsToProduct[A, V1, V2](a: A)(implicit v1: A => V1, v2: A => V2) =
new &(v1(a), v2(a))
Now I can write Seq[V1 & V2] like a boss. For example:
trait Foo { def foo: String }
trait Bar { def bar: String }
implicit def stringFoo(a: String) = new Foo { def foo = a + " sf" }
implicit def stringBar(a: String) = new Bar { def bar = a + " sb" }
implicit def intFoo(a: Int) = new Foo { def foo = a.toString + " if" }
implicit def intBar(a: Int) = new Bar { def bar = a.toString + " ib" }
val s1 = Seq[Foo & Bar]("hoho", 1)
val s2 = s1 flatMap (ab => Seq(ab.foo, ab.bar))
// equal to Seq("hoho sf", "hoho sb", "1 if", "1 ib")
The implicit conversions from String and Int to type Foo & Bar occur when the sequence is populated, and then the implicit conversions from Foo & Bar to Foo and Bar occur when calling foobar.foo and foobar.bar.
The current ridiculous question(s):
Has anybody implemented this pattern anywhere before, or am I the first idiot to do it?
Is there a much simpler way of doing this that I've blindly missed?
If not, then how would I implement more general plumbing, such that I can write Seq[Foo & Bar & Baz]? This seems like a job for HList...
Extra mega combo bonus: in implementing the more general plumbing, can I constrain the types to be unique? For example, I'd like to prohibit Seq[Foo & Foo].
The appendix of fails:
My latest attempt (gist). Not terrible, but there are two things I dislike there:
The Seq[All[A :: B :: C :: HNil]] syntax (I want the HList stuff to be opaque, and prefer Seq[A & B & C])
The explicit type annotation (abc[A].a) required for conversion. It seems like you can either have type inference or implicit conversions, but not both... I couldn't figure out how to avoid it, anyhow.
I can give a partial answer for the point 4. This can be obtained by applying a technique such as :
http://vpatryshev.blogspot.com/2012/03/miles-sabins-type-negation-in-practice.html
I have 3 Scala classes (A,B,C).
I have one implicit conversion from A -> B and one from B -> C.
At some point in my code, I want to call a C method on A. Is this possible?
One fix I came up is to have a conversion from A -> C but that seems somewhat redundant.
Note:
When I call B methods on A it works.
When I call C methods on B it works.
When I call C methods on A it says that it didn't find the method in the body of A
Thanks ...
It seems you made a typo when you wrote the question. Did you mean to say you have implicit conversions from A -> B and B -> C, and that you find an A -> C conversion redundant?
Scala has a rule that it will only apply one implicit conversion when necessary (but never two), so you can't just expect Scala to magically compose A -> B and B -> C to make the conversion you need. You'll need to provide your own A -> C conversion. It's not redundant.
It does seem somewhat redundant, but the A -> C conversion is exactly what you should supply. The reason is that if implicits are rare, transitive chains are also rare, and are probably what you want. But if implicits are common, chances are you'll be able to turn anything into anything (or, if you add a handy-looking implicit, suddenly all sorts of behaviors will change because you've opened up different pathways for implicit conversion).
You can have Scala chain the implicit conversions for you, however, if you specify that it is to be done. The key is to use generics with <% which means "can be converted to". Here's an example:
class Foo(i: Int) { def foo = i }
class Bar(s: String) { def bar = s }
class Okay(b: Boolean) { def okay = b }
implicit def to_bar_through_foo[T <% Foo](t: T) = new Bar((t: Foo).foo.toString)
implicit def to_okay_through_bar[U <% Bar](u: U) = new Okay((u: Bar).bar.length < 4)
scala> (new Foo(5)).okay
res0: Boolean = true